1
- import { useReducer , useRef , useEffect , useMemo , useLayoutEffect } from 'react'
1
+ import { useState , useRef , useEffect , useMemo , useLayoutEffect } from 'react'
2
2
import invariant from 'invariant'
3
3
import { useReduxContext } from './useReduxContext'
4
4
import shallowEqual from '../utils/shallowEqual'
@@ -42,7 +42,7 @@ export function useSelector(selector) {
42
42
invariant ( selector , `You must pass a selector to useSelectors` )
43
43
44
44
const { store, subscription : contextSub } = useReduxContext ( )
45
- const [ , forceRender ] = useReducer ( s => s + 1 , 0 )
45
+ const [ state , setState ] = useState ( { id : 0 , state : null } )
46
46
47
47
const subscription = useMemo ( ( ) => new Subscription ( store , contextSub ) , [
48
48
store ,
@@ -51,31 +51,13 @@ export function useSelector(selector) {
51
51
52
52
const latestSubscriptionCallbackError = useRef ( )
53
53
const latestSelector = useRef ( selector )
54
-
55
- let selectedState = undefined
56
-
57
- try {
58
- selectedState = selector ( store . getState ( ) )
59
- } catch ( err ) {
60
- let errorMessage = `An error occured while selecting the store state: ${
61
- err . message
62
- } .`
63
-
64
- if ( latestSubscriptionCallbackError . current ) {
65
- errorMessage += `\nThe error may be correlated with this previous error:\n${
66
- latestSubscriptionCallbackError . current . stack
67
- } \n\nOriginal stack trace:`
68
- }
69
-
70
- throw new Error ( errorMessage )
71
- }
72
-
73
- const latestSelectedState = useRef ( selectedState )
54
+ const latestSelectedState = useRef ( )
55
+ const latestId = useRef ( 0 )
74
56
75
57
useIsomorphicLayoutEffect ( ( ) => {
76
58
latestSelector . current = selector
77
- latestSelectedState . current = selectedState
78
59
latestSubscriptionCallbackError . current = undefined
60
+ latestId . current = state . id
79
61
} )
80
62
81
63
useIsomorphicLayoutEffect ( ( ) => {
@@ -96,7 +78,10 @@ export function useSelector(selector) {
96
78
latestSubscriptionCallbackError . current = err
97
79
}
98
80
99
- forceRender ( { } )
81
+ setState ( prev => ( {
82
+ id : prev . id + 1 ,
83
+ state : latestSelectedState . current
84
+ } ) )
100
85
}
101
86
102
87
subscription . onStateChange = checkForUpdates
@@ -107,5 +92,31 @@ export function useSelector(selector) {
107
92
return ( ) => subscription . tryUnsubscribe ( )
108
93
} , [ store , subscription ] )
109
94
110
- return selectedState
95
+ try {
96
+ latestSelectedState . current = useMemo ( ( ) => selector ( store . getState ( ) ) , [
97
+ selector
98
+ ] )
99
+
100
+ if ( state . id != latestId . current ) {
101
+ if ( latestSubscriptionCallbackError . current ) {
102
+ latestSelectedState . current = selector ( store . getState ( ) )
103
+ return latestSelectedState . current
104
+ }
105
+ return state . state
106
+ }
107
+ } catch ( err ) {
108
+ let errorMessage = `An error occured while selecting the store state: ${
109
+ err . message
110
+ } .`
111
+
112
+ if ( latestSubscriptionCallbackError . current ) {
113
+ errorMessage += `\nThe error may be correlated with this previous error:\n${
114
+ latestSubscriptionCallbackError . current . stack
115
+ } \n\nOriginal stack trace:`
116
+ }
117
+
118
+ throw new Error ( errorMessage )
119
+ }
120
+
121
+ return latestSelectedState . current
111
122
}
0 commit comments