Skip to content

Commit 11db31a

Browse files
committed
Fix useSelector race condition when dispatch happens in componentDidUpdate
1 parent 81c93f1 commit 11db31a

File tree

2 files changed

+46
-5
lines changed

2 files changed

+46
-5
lines changed

src/hooks/useSelector.js

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,11 +42,9 @@ function useSelectorWithStoreAndSubscription(
4242
throw err
4343
}
4444

45-
useIsomorphicLayoutEffect(() => {
46-
latestSelector.current = selector
47-
latestSelectedState.current = selectedState
48-
latestSubscriptionCallbackError.current = undefined
49-
})
45+
latestSelector.current = selector
46+
latestSelectedState.current = selectedState
47+
latestSubscriptionCallbackError.current = undefined
5048

5149
useIsomorphicLayoutEffect(() => {
5250
function checkForUpdates() {

test/hooks/useSelector.spec.js

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -154,6 +154,49 @@ describe('React', () => {
154154

155155
expect(renderedItems).toEqual([0, 1])
156156
})
157+
158+
it('works properly with dispatch from componentDidUpdate', () => {
159+
store = createStore(c => c + 1, -1)
160+
161+
const Comp = () => {
162+
const selector = useCallback(c => c, [])
163+
const value = useSelector(selector)
164+
renderedItems.push(value)
165+
return <CompClass val={value} />
166+
}
167+
168+
class CompClass extends React.PureComponent {
169+
constructor(props) {
170+
super(props)
171+
this.dispatched = false
172+
}
173+
componentDidUpdate() {
174+
if (this.dispatched) {
175+
return
176+
}
177+
store.dispatch({ type: '' })
178+
this.dispatched = true
179+
}
180+
render() {
181+
return <div />
182+
}
183+
}
184+
185+
rtl.render(
186+
<ProviderMock store={store}>
187+
<Comp />
188+
</ProviderMock>
189+
)
190+
191+
// The first render doesn't trigger componentDidUpdate
192+
expect(renderedItems).toEqual([0])
193+
194+
// This dispatch forces Comp and CompClass to re-render,
195+
// triggering componentDidUpdate and dispatching another action
196+
store.dispatch({ type: '' })
197+
198+
expect(renderedItems).toEqual([0, 1, 2])
199+
})
157200
})
158201

159202
describe('performance optimizations and bail-outs', () => {

0 commit comments

Comments
 (0)