File tree Expand file tree Collapse file tree 3 files changed +54
-0
lines changed Expand file tree Collapse file tree 3 files changed +54
-0
lines changed Original file line number Diff line number Diff line change 63
63
"husky" : " ^8.0.3" ,
64
64
"lint-staged" : " ^15.1.0" ,
65
65
"np" : " ^10.0.2" ,
66
+ "prettier" : " ^3.3.2" ,
66
67
"rc-test" : " ^7.0.14" ,
67
68
"react" : " ^18.0.0" ,
68
69
"react-dom" : " ^18.0.0" ,
Original file line number Diff line number Diff line change
1
+ import * as React from 'react' ;
2
+ import useEvent from './useEvent' ;
3
+
4
+ type Updater < T > = T | ( ( prevValue : T ) => T ) ;
5
+
6
+ export type SetState < T > = ( nextValue : Updater < T > ) => void ;
7
+
8
+ /**
9
+ * Same as React.useState but will always get latest state.
10
+ * This is useful when React merge multiple state updates into one.
11
+ * e.g. onTransitionEnd trigger multiple event at once will be merged state update in React.
12
+ */
13
+ export default function useSyncState < T > (
14
+ defaultValue ?: T ,
15
+ ) : [ get : ( ) => T , set : SetState < T > ] {
16
+ const [ , forceUpdate ] = React . useReducer ( x => x + 1 , 0 ) ;
17
+
18
+ const currentValueRef = React . useRef ( defaultValue ) ;
19
+
20
+ const getValue = useEvent ( ( ) => {
21
+ return currentValueRef . current ;
22
+ } ) ;
23
+
24
+ const setValue = useEvent ( ( updater : Updater < T > ) => {
25
+ currentValueRef . current =
26
+ typeof updater === 'function'
27
+ ? ( updater as ( prevValue : T ) => T ) ( currentValueRef . current )
28
+ : updater ;
29
+
30
+ forceUpdate ( ) ;
31
+ } ) ;
32
+
33
+ return [ getValue , setValue ] ;
34
+ }
Original file line number Diff line number Diff line change @@ -7,6 +7,7 @@ import useMemo from '../src/hooks/useMemo';
7
7
import useMergedState from '../src/hooks/useMergedState' ;
8
8
import useMobile from '../src/hooks/useMobile' ;
9
9
import useState from '../src/hooks/useState' ;
10
+ import useSyncState from '../src/hooks/useSyncState' ;
10
11
11
12
global . disableUseId = false ;
12
13
@@ -521,4 +522,22 @@ describe('hooks', () => {
521
522
) ;
522
523
} ) ;
523
524
} ) ;
525
+
526
+ describe ( 'useSyncState' , ( ) => {
527
+ it ( 'batch use latest' , ( ) => {
528
+ const Demo = ( ) => {
529
+ const [ getCounter , setCounter ] = useSyncState ( 0 ) ;
530
+
531
+ React . useEffect ( ( ) => {
532
+ setCounter ( getCounter ( ) + 1 ) ;
533
+ setCounter ( getCounter ( ) + 1 ) ;
534
+ } , [ getCounter , setCounter ] ) ;
535
+
536
+ return getCounter ( ) ;
537
+ } ;
538
+
539
+ const { container } = render ( < Demo /> ) ;
540
+ expect ( container . textContent ) . toEqual ( '2' ) ;
541
+ } ) ;
542
+ } ) ;
524
543
} ) ;
You can’t perform that action at this time.
0 commit comments