Skip to content

Commit

Permalink
Don't re-run the selector after update
Browse files Browse the repository at this point in the history
Fixes #1697

We can avoid running the selector twice by setting the latestStoreState at the same time as setting the latestSelectedState. If the store state hasn't changed, then the selector won't as well (since it's pure).
  • Loading branch information
timdorr committed Mar 25, 2021
1 parent 010c3ee commit 3146b35
Show file tree
Hide file tree
Showing 2 changed files with 8 additions and 2 deletions.
4 changes: 3 additions & 1 deletion src/hooks/useSelector.js
Expand Up @@ -64,13 +64,15 @@ function useSelectorWithStoreAndSubscription(
useIsomorphicLayoutEffect(() => {
function checkForUpdates() {
try {
const newSelectedState = latestSelector.current(store.getState())
const storeState = store.getState()
const newSelectedState = latestSelector.current(storeState)

if (equalityFn(newSelectedState, latestSelectedState.current)) {
return
}

latestSelectedState.current = newSelectedState
latestStoreState.current = storeState
} catch (err) {
// we ignore all errors here, since when the component
// is re-rendered, the selectors are called again, and
Expand Down
6 changes: 5 additions & 1 deletion test/hooks/useSelector.spec.js
Expand Up @@ -38,17 +38,21 @@ describe('React', () => {
})

it('selects the state and renders the component when the store updates', () => {
const { result } = renderHook(() => useSelector((s) => s.count), {
const selector = jest.fn((s) => s.count)

const { result } = renderHook(() => useSelector(selector), {
wrapper: (props) => <ProviderMock {...props} store={store} />,
})

expect(result.current).toEqual(0)
expect(selector).toHaveBeenCalledTimes(2)

act(() => {
store.dispatch({ type: '' })
})

expect(result.current).toEqual(1)
expect(selector).toHaveBeenCalledTimes(3)
})
})

Expand Down

0 comments on commit 3146b35

Please sign in to comment.