Skip to content

Commit 9ecceb2

Browse files
committed
Add a failing tests (and update one test)
Currently, useSelector(selector) will call the passed selector twice on mount when it only needs to be called once on mount. This is unnecessary, and in the case of expensive selectors, can be a performance concern.
1 parent d4e4eba commit 9ecceb2

File tree

1 file changed

+38
-2
lines changed

1 file changed

+38
-2
lines changed

test/hooks/useSelector.spec.tsx

Lines changed: 38 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -72,14 +72,14 @@ describe('React', () => {
7272
})
7373

7474
expect(result.current).toEqual(0)
75-
expect(selector).toHaveBeenCalledTimes(2)
75+
expect(selector).toHaveBeenCalledTimes(1)
7676

7777
act(() => {
7878
normalStore.dispatch({ type: '' })
7979
})
8080

8181
expect(result.current).toEqual(1)
82-
expect(selector).toHaveBeenCalledTimes(3)
82+
expect(selector).toHaveBeenCalledTimes(2)
8383
})
8484
})
8585

@@ -283,6 +283,42 @@ describe('React', () => {
283283

284284
expect(renderedItems.length).toBe(1)
285285
})
286+
287+
it('calls selector exactly once on mount and on update', () => {
288+
interface StateType {
289+
count: number
290+
}
291+
const store = createStore(({ count }: StateType = { count: 0 }) => ({
292+
count: count + 1,
293+
}))
294+
295+
let numCalls = 0
296+
const selector = (s: StateType) => {
297+
numCalls += 1
298+
return s.count
299+
}
300+
const renderedItems = []
301+
302+
const Comp = () => {
303+
const value = useSelector(selector)
304+
renderedItems.push(value)
305+
return <div />
306+
}
307+
308+
rtl.render(
309+
<ProviderMock store={store}>
310+
<Comp />
311+
</ProviderMock>
312+
)
313+
314+
expect(numCalls).toBe(1)
315+
expect(renderedItems.length).toEqual(1)
316+
317+
store.dispatch({ type: '' })
318+
319+
expect(numCalls).toBe(2)
320+
expect(renderedItems.length).toEqual(2)
321+
})
286322
})
287323

288324
it('uses the latest selector', () => {

0 commit comments

Comments
 (0)