Skip to content

Commit 832a397

Browse files
authored
refactor: fallback of useMergedState (#381)
1 parent 6e87871 commit 832a397

File tree

1 file changed

+23
-64
lines changed

1 file changed

+23
-64
lines changed

src/hooks/useMergedState.ts

Lines changed: 23 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,13 @@
11
import * as React from 'react';
22
import useEvent from './useEvent';
3-
import useLayoutEffect, { useLayoutUpdateEffect } from './useLayoutEffect';
3+
import { useLayoutUpdateEffect } from './useLayoutEffect';
44
import useState from './useState';
55

66
type Updater<T> = (
77
updater: T | ((origin: T) => T),
88
ignoreDestroy?: boolean,
99
) => void;
1010

11-
enum Source {
12-
INNER,
13-
PROP,
14-
}
15-
16-
type ValueRecord<T> = [T, Source, T];
17-
1811
/** We only think `undefined` is empty */
1912
function hasValue(value: any) {
2013
return value !== undefined;
@@ -36,74 +29,40 @@ export default function useMergedState<T, R = T>(
3629
const { defaultValue, value, onChange, postState } = option || {};
3730

3831
// ======================= Init =======================
39-
const [mergedValue, setMergedValue] = useState<ValueRecord<T>>(() => {
40-
let finalValue: T = undefined;
41-
let source: Source;
42-
32+
const [innerValue, setInnerValue] = useState<T>(() => {
4333
if (hasValue(value)) {
44-
finalValue = value;
45-
source = Source.PROP;
34+
return value;
4635
} else if (hasValue(defaultValue)) {
47-
finalValue =
48-
typeof defaultValue === 'function'
49-
? (defaultValue as any)()
50-
: defaultValue;
51-
source = Source.PROP;
36+
return typeof defaultValue === 'function'
37+
? (defaultValue as any)()
38+
: defaultValue;
5239
} else {
53-
finalValue =
54-
typeof defaultStateValue === 'function'
55-
? (defaultStateValue as any)()
56-
: defaultStateValue;
57-
source = Source.INNER;
40+
return typeof defaultStateValue === 'function'
41+
? (defaultStateValue as any)()
42+
: defaultStateValue;
5843
}
59-
60-
return [finalValue, source, finalValue];
6144
});
6245

63-
const chosenValue = hasValue(value) ? value : mergedValue[0];
64-
const postMergedValue = postState ? postState(chosenValue) : chosenValue;
46+
const mergedValue = value !== undefined ? value : innerValue;
47+
const postMergedValue = postState ? postState(mergedValue) : mergedValue;
48+
49+
// ====================== Change ======================
50+
const onChangeFn = useEvent(onChange);
51+
52+
const [prevValue, setPrevValue] = React.useState<[T]>([mergedValue]);
6553

66-
// ======================= Sync =======================
6754
useLayoutUpdateEffect(() => {
68-
setMergedValue(([prevValue]) => [value, Source.PROP, prevValue]);
69-
}, [value]);
55+
const prev = prevValue[0];
56+
if (innerValue !== prev) {
57+
onChangeFn(innerValue, prev);
58+
}
59+
}, [prevValue]);
7060

7161
// ====================== Update ======================
72-
const changeEventPrevRef = React.useRef<T>();
73-
7462
const triggerChange: Updater<T> = useEvent((updater, ignoreDestroy) => {
75-
setMergedValue(prev => {
76-
const [prevValue, prevSource, prevPrevValue] = prev;
77-
78-
const nextValue: T =
79-
typeof updater === 'function' ? (updater as any)(prevValue) : updater;
80-
81-
// Do nothing if value not change
82-
if (nextValue === prevValue) {
83-
return prev;
84-
}
85-
86-
// Use prev prev value if is in a batch update to avoid missing data
87-
const overridePrevValue =
88-
prevSource === Source.INNER &&
89-
changeEventPrevRef.current !== prevPrevValue
90-
? prevPrevValue
91-
: prevValue;
92-
93-
return [nextValue, Source.INNER, overridePrevValue];
94-
}, ignoreDestroy);
63+
setInnerValue(updater, ignoreDestroy);
64+
setPrevValue([mergedValue]);
9565
});
9666

97-
// ====================== Change ======================
98-
const onChangeFn = useEvent(onChange);
99-
100-
useLayoutEffect(() => {
101-
const [current, source, prev] = mergedValue;
102-
if (current !== prev && source === Source.INNER) {
103-
onChangeFn(current, prev);
104-
changeEventPrevRef.current = prev;
105-
}
106-
}, [mergedValue]);
107-
10867
return [postMergedValue as unknown as R, triggerChange];
10968
}

0 commit comments

Comments
 (0)