1
- import { useReducer , useRef , useMemo , useContext , useDebugValue } from 'react'
1
+ import { useRef , useMemo , useContext , useDebugValue } from 'react'
2
+
3
+ import { useSyncExternalStoreExtra } from 'use-sync-external-store/extra'
4
+
2
5
import { useReduxContext as useDefaultReduxContext } from './useReduxContext'
3
6
import { createSubscription , Subscription } from '../utils/Subscription'
4
7
import { useIsomorphicLayoutEffect } from '../utils/useIsomorphicLayoutEffect'
@@ -16,94 +19,25 @@ function useSelectorWithStoreAndSubscription<TStoreState, TSelectedState>(
16
19
store : Store < TStoreState , AnyAction > ,
17
20
contextSub : Subscription
18
21
) : TSelectedState {
19
- const [ , forceRender ] = useReducer ( ( s ) => s + 1 , 0 )
20
-
21
- const subscription = useMemo (
22
- ( ) => createSubscription ( store , contextSub ) ,
23
- [ store , contextSub ]
24
- )
25
-
26
- const latestSubscriptionCallbackError = useRef < Error > ( )
27
- const latestSelector = useRef < TSelector < TStoreState , TSelectedState > > ( )
28
- const latestStoreState = useRef < TStoreState > ( )
29
- const latestSelectedState = useRef < TSelectedState > ( )
30
-
31
- const storeState = store . getState ( )
32
- let selectedState : TSelectedState | undefined
33
-
34
- try {
35
- if (
36
- selector !== latestSelector . current ||
37
- storeState !== latestStoreState . current ||
38
- latestSubscriptionCallbackError . current
39
- ) {
40
- const newSelectedState = selector ( storeState )
41
- // ensure latest selected state is reused so that a custom equality function can result in identical references
42
- if (
43
- latestSelectedState . current === undefined ||
44
- ! equalityFn ( newSelectedState , latestSelectedState . current )
45
- ) {
46
- selectedState = newSelectedState
47
- } else {
48
- selectedState = latestSelectedState . current
49
- }
50
- } else {
51
- selectedState = latestSelectedState . current
52
- }
53
- } catch ( err ) {
54
- if ( latestSubscriptionCallbackError . current ) {
55
- ; (
56
- err as Error
57
- ) . message += `\nThe error may be correlated with this previous error:\n${ latestSubscriptionCallbackError . current . stack } \n\n`
58
- }
59
-
60
- throw err
61
- }
62
-
63
- useIsomorphicLayoutEffect ( ( ) => {
64
- latestSelector . current = selector
65
- latestStoreState . current = storeState
66
- latestSelectedState . current = selectedState
67
- latestSubscriptionCallbackError . current = undefined
68
- } )
69
-
70
- useIsomorphicLayoutEffect ( ( ) => {
71
- function checkForUpdates ( ) {
72
- try {
73
- const newStoreState = store . getState ( )
74
- // Avoid calling selector multiple times if the store's state has not changed
75
- if ( newStoreState === latestStoreState . current ) {
76
- return
77
- }
78
-
79
- const newSelectedState = latestSelector . current ! ( newStoreState )
80
-
81
- if ( equalityFn ( newSelectedState , latestSelectedState . current ) ) {
82
- return
83
- }
84
-
85
- latestSelectedState . current = newSelectedState
86
- latestStoreState . current = newStoreState
87
- } catch ( err ) {
88
- // we ignore all errors here, since when the component
89
- // is re-rendered, the selectors are called again, and
90
- // will throw again, if neither props nor store state
91
- // changed
92
- latestSubscriptionCallbackError . current = err as Error
93
- }
94
-
95
- forceRender ( )
22
+ const subscribe = useMemo ( ( ) => {
23
+ const subscription = createSubscription ( store , contextSub )
24
+ const subscribe = ( reactListener : ( ) => void ) => {
25
+ // React provides its own subscription handler - trigger that on dispatch
26
+ subscription . onStateChange = reactListener
27
+ subscription . trySubscribe ( )
28
+
29
+ return ( ) => subscription . tryUnsubscribe ( )
96
30
}
97
31
98
- subscription . onStateChange = checkForUpdates
99
- subscription . trySubscribe ( )
100
-
101
- checkForUpdates ( )
32
+ return subscribe
33
+ } , [ store , contextSub ] )
102
34
103
- return ( ) => subscription . tryUnsubscribe ( )
104
- } , [ store , subscription ] )
105
-
106
- return selectedState !
35
+ return useSyncExternalStoreExtra (
36
+ subscribe ,
37
+ store . getState ,
38
+ selector ,
39
+ equalityFn
40
+ )
107
41
}
108
42
109
43
/**
0 commit comments