UNPKG

@supunlakmal/hooks

Version:

A collection of reusable React hooks

65 lines 2.11 kB
import { useCallback, useRef, useState, useEffect, } from 'react'; /** * Returns a boolean that is `true` only on first render. */ const useFirstMountState = () => { const isFirstMount = useRef(true); useEffect(() => { isFirstMount.current = false; }, []); return isFirstMount.current; }; const stateChanger = (state) => (state + 1) % Number.MAX_SAFE_INTEGER; /** * Return callback function that re-renders component. */ const useRerender = () => { // eslint-disable-next-line react/hook-use-state const [, setState] = useState(0); return useCallback(() => setState(stateChanger), []); }; const initState = (initialState) => { if (typeof initialState === 'function') { initialState = initialState(); } return initialState; }; const updateState = (nextState, previousState) => { if (typeof nextState === 'function') { return nextState(previousState); } return nextState; }; const resolveHookState = (...args) => { if (args.length === 1) { return initState(args[0]); } return updateState(args[0], args[1]); }; /** * Like `React.useState`, but its state setter accepts extra argument, that allows to cancel * rerender. */ export const useControlledRerenderState = (initialState) => { const isFirstMount = useFirstMountState(); const state = useRef(useFirstMountState() ? (initialState instanceof Function ? initialState() : initialState) : undefined); const rr = useRerender(); return [ state.current, useCallback((value, rerender) => { const newState = resolveHookState(value, state.current); if (isFirstMount) { state.current = (initialState instanceof Function ? initialState() : initialState); } if (newState !== state.current) { state.current = newState; if (rerender === undefined || rerender) { rr(); } } }, [rr, initialState, isFirstMount]), ]; }; //# sourceMappingURL=useControlledRerenderState.js.map