diff --git a/src/hooks/useSelector.js b/src/hooks/useSelector.js index 83e48569d..62171b3ee 100644 --- a/src/hooks/useSelector.js +++ b/src/hooks/useSelector.js @@ -20,9 +20,9 @@ const refEquality = (a, b) => a === b * A hook to access the redux store's state. This hook takes a selector function * as an argument. The selector is called with the store state. * - * This hook takes a dependencies array as an optional second argument, - * which when passed ensures referential stability of the selector (this is primarily - * useful if you provide a selector that memoizes values). + * This hook takes an optional equality comparison function as the second parameter + * that allows you to customize the way the selected state is compared to determine + * whether the component needs to be re-rendered. * * @param {Function} selector the selector function * @param {Function} equalityFn the function that will be used to determine equality @@ -33,7 +33,6 @@ const refEquality = (a, b) => a === b * * import React from 'react' * import { useSelector } from 'react-redux' - * import { RootState } from './store' * * export const CounterComponent = () => { * const counter = useSelector(state => state.counter) diff --git a/test/hooks/useSelector.spec.js b/test/hooks/useSelector.spec.js index a4756d244..fdaffdba4 100644 --- a/test/hooks/useSelector.spec.js +++ b/test/hooks/useSelector.spec.js @@ -7,7 +7,8 @@ import * as rtl from 'react-testing-library' import { Provider as ProviderMock, useSelector, - shallowEqual + shallowEqual, + connect } from '../../src/index.js' import { useReduxContext } from '../../src/hooks/useReduxContext' @@ -302,6 +303,78 @@ describe('React', () => { spy.mockRestore() }) + + it('re-throws errors from the selector that only occur during rendering', () => { + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + + const Parent = () => { + const count = useSelector(s => s.count) + return + } + + const Child = ({ parentCount }) => { + const result = useSelector(({ count }) => { + if (parentCount > 0) { + throw new Error() + } + + return count + parentCount + }) + + return
{result}
+ } + + rtl.render( + + + + ) + + expect(() => store.dispatch({ type: '' })).toThrowError() + + spy.mockRestore() + }) + + it('allows dealing with stale props by putting a specific connected component above the hooks component', () => { + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + + const Parent = () => { + const count = useSelector(s => s.count) + return + } + + const ConnectedWrapper = connect(({ count }) => ({ count }))( + ({ parentCount }) => { + return + } + ) + + let sawInconsistentState = false + + const Child = ({ parentCount }) => { + const result = useSelector(({ count }) => { + if (count !== parentCount) { + sawInconsistentState = true + } + + return count + parentCount + }) + + return
{result}
+ } + + rtl.render( + + + + ) + + store.dispatch({ type: '' }) + + expect(sawInconsistentState).toBe(false) + + spy.mockRestore() + }) }) describe('error handling for invalid arguments', () => {