Add optional dependencies for selector

This commit is contained in:
JeremyHolcomb 2019-05-10 10:51:53 -07:00
parent 9f2dfedf70
commit 1b6dae9fe5
2 changed files with 35 additions and 5 deletions

View File

@ -36,14 +36,23 @@ export default function create<
}
function useStore(): State
function useStore<U>(selector: StateSelector<State, U>): U
function useStore<U>(selector?: StateSelector<State, U>) {
function useStore<U>(
selector: StateSelector<State, U>,
deps?: readonly any[]
): U
function useStore<U>(
selector?: StateSelector<State, U>,
deps?: readonly any[]
) {
// Gets entire state if no selector was passed in
const selectState = typeof selector === 'function' ? selector : getState
const selectState = React.useCallback(
typeof selector === 'function' ? selector : getState,
deps as readonly any[]
)
// Nothing stored in useState, just using to enable forcing an update
const [, forceUpdate] = React.useState({})
// Always get latest slice because selector can change
const stateSlice = selectState(state)
// Always get latest slice unless dependencies are passed in
const stateSlice = React.useMemo(() => selectState(state), deps)
// Prevent subscribing/unsubscribing to the store when values change by storing them in a ref object
const refs = React.useRef({ stateSlice, selectState }).current

View File

@ -160,3 +160,24 @@ it('can update the selector even when the store does not change', async () => {
rerender(<Component selector={s => s.two} />)
await waitForElement(() => getByText('two'))
})
it('can pass optional dependencies to restrict selector calls', async () => {
const [useStore] = create(() => ({}))
let selectorCallCount = 0
function Component({ deps }) {
useStore(() => {
selectorCallCount++
}, deps)
return <div>{selectorCallCount}</div>
}
const { rerender } = render(<Component deps={[true]} />)
expect(selectorCallCount).toBe(1)
rerender(<Component deps={[true]} />)
expect(selectorCallCount).toBe(1)
rerender(<Component deps={[false]} />)
expect(selectorCallCount).toBe(2)
})