Skip to content

Commit 4e0b6e0

Browse files
committed
[WIP] useDerivedState
1 parent eef52d0 commit 4e0b6e0

1 file changed

Lines changed: 40 additions & 0 deletions

File tree

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import { DependencyList, useRef, useReducer, useCallback, Dispatch, SetStateAction, useEffect } from "react";
2+
3+
export const useDerivedState = <T>(initialState: T|(()=>T), compute: ()=>void|Promise<void>|(()=>void), deps?: DependencyList): [T, Dispatch<SetStateAction<T>>] => {
4+
const [, update] = useReducer(t => !t, false);
5+
const ref = useRef<{ init: boolean, localState?: T, deps?: DependencyList }>({
6+
init: false
7+
});
8+
9+
let localState: T;
10+
if (!ref.current.init || (ref.current.deps || []).length !== (deps || []).length || !(ref.current.deps || []).every((dep, i) => (deps || [])[i] === dep)) {
11+
localState = typeof initialState === "function" ? (initialState as ()=>T)() : initialState;
12+
ref.current = {
13+
init: true,
14+
localState: localState,
15+
deps
16+
}
17+
update();
18+
} else {
19+
localState = ref.current.localState!;
20+
}
21+
22+
const updateLocalState = useCallback((state: T | ((state: T) => T)) => {
23+
if (!ref.current.init) {
24+
throw Error();
25+
}
26+
const localState = typeof state === "function"
27+
? (state as ((state: T) => T))(ref.current.localState!)
28+
: state;
29+
ref.current.localState = localState;
30+
update();
31+
}, []) as Dispatch<SetStateAction<T>>;
32+
33+
useEffect(() => {
34+
const cleanUp = compute();
35+
return () => cleanUp && (cleanUp as ()=>void)();
36+
}, [compute]);
37+
38+
return [localState, updateLocalState];
39+
40+
}

0 commit comments

Comments
 (0)