-
Notifications
You must be signed in to change notification settings - Fork 96
/
Copy pathindex.ts
43 lines (37 loc) · 1.33 KB
/
index.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
import {type SetStateAction, useCallback, useRef} from 'react';
import {useFirstMountState} from '../useFirstMountState/index.js';
import {useRerender} from '../useRerender/index.js';
import {resolveHookState} from '../util/resolve-hook-state.js';
export type ControlledRerenderDispatch<A> = (value: A, rerender?: boolean) => void;
export function useControlledRerenderState<S>(
initialState: S | (() => S)
): [S, ControlledRerenderDispatch<SetStateAction<S>>];
export function useControlledRerenderState<S = undefined>(): [
S | undefined,
ControlledRerenderDispatch<SetStateAction<S | undefined>>,
];
/**
* Like `React.useState`, but its state setter accepts extra argument, that allows to cancel
* rerender.
*/
export function useControlledRerenderState<S>(
initialState?: S | (() => S),
): [S | undefined, ControlledRerenderDispatch<SetStateAction<S | undefined>>] {
const state = useRef<S | undefined>(
useFirstMountState() ? resolveHookState(initialState) : undefined,
);
const rr = useRerender();
return [
state.current,
useCallback((value, rerender) => {
const newState = resolveHookState(value, state.current);
if (newState !== state.current) {
state.current = newState;
if (rerender === undefined || rerender) {
rr();
}
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []),
];
}