From 69006eb9564e24a190bea44ffb558fa6bd232904 Mon Sep 17 00:00:00 2001 From: Ryan Kennedy Date: Wed, 12 Jun 2019 10:27:30 -0400 Subject: [PATCH] feat: Hook creators accept context directly --- docs/api/hooks.md | 8 +++----- src/hooks/useDispatch.js | 10 +++++----- src/hooks/useReduxContext.js | 31 +++++++++++-------------------- src/hooks/useSelector.js | 9 +++++---- src/hooks/useStore.js | 9 +++++---- src/index.js | 2 -- test/hooks/useDispatch.spec.js | 7 ++----- test/hooks/useSelector.spec.js | 7 ++----- 8 files changed, 33 insertions(+), 50 deletions(-) diff --git a/docs/api/hooks.md b/docs/api/hooks.md index e27b1caaf..0fa5ab95e 100644 --- a/docs/api/hooks.md +++ b/docs/api/hooks.md @@ -306,19 +306,17 @@ To access an alternate context via the hooks API, use the hook creator functions import React from 'react' import { Provider, - createReduxContextHook, createStoreHook, createDispatchHook, createSelectorHook } from 'react-redux' const MyContext = React.createContext(null) -const useMyReduxContext = createReduxContextHook(MyContext) // Export your custom hooks if you wish to use them in other files. -export const useStore = createStoreHook(useMyReduxContext) -export const useDispatch = createDispatchHook(useMyReduxContext) -export const useSelector = createSelectorHook(useMyReduxContext) +export const useStore = createStoreHook(MyContext) +export const useDispatch = createDispatchHook(MyContext) +export const useSelector = createSelectorHook(MyContext) const myStore = createStore(rootReducer) diff --git a/src/hooks/useDispatch.js b/src/hooks/useDispatch.js index 803ba819a..0c3e33466 100644 --- a/src/hooks/useDispatch.js +++ b/src/hooks/useDispatch.js @@ -1,15 +1,15 @@ +import { ReactReduxContext } from '../components/Context' import { useStore as useDefaultStore, createStoreHook } from './useStore' /** * Hook factory, which creates a `useDispatch` hook bound to a given context. * - * @param {Function} [useReduxContext] Hook which returns the Redux context. + * @param {Function} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useDispatch` hook bound to the specified context. */ -export function createDispatchHook(useReduxContext = null) { - const useStore = useReduxContext - ? createStoreHook(useReduxContext) - : useDefaultStore +export function createDispatchHook(context = ReactReduxContext) { + const useStore = + context === ReactReduxContext ? useDefaultStore : createStoreHook(context) return function useDispatch() { const store = useStore() return store.dispatch diff --git a/src/hooks/useReduxContext.js b/src/hooks/useReduxContext.js index a0e518cb9..2a526ac2e 100644 --- a/src/hooks/useReduxContext.js +++ b/src/hooks/useReduxContext.js @@ -2,29 +2,11 @@ import { useContext } from 'react' import invariant from 'invariant' import { ReactReduxContext } from '../components/Context' -/** - * Hook factory, which creates a `useReduxContext` hook bound to a given context. - * - * @param {Function} [context=ReactReduxContext] React context passed to the `context` prop of your ``. - * @returns {Function} A `useReactContext` hook bound to the specified context. - */ -export function createReduxContextHook(context = ReactReduxContext) { - return function useReduxContext() { - const contextValue = useContext(context) - - invariant( - contextValue, - 'could not find react-redux context value; please ensure the component is wrapped in a ' - ) - - return contextValue - } -} - /** * A hook to access the value of the `ReactReduxContext`. This is a low-level * hook that you should usually not need to call directly. * + * @param {Function} [context=ReactReduxContext] Context passed to your ``, if you're not using the default. * @returns {any} the value of the `ReactReduxContext` * * @example @@ -37,4 +19,13 @@ export function createReduxContextHook(context = ReactReduxContext) { * return
{store.getState()}
* } */ -export const useReduxContext = createReduxContextHook() +export function useReduxContext(context = ReactReduxContext) { + const contextValue = useContext(context) + + invariant( + contextValue, + 'could not find react-redux context value; please ensure the component is wrapped in a ' + ) + + return contextValue +} diff --git a/src/hooks/useSelector.js b/src/hooks/useSelector.js index 2a7a541fe..9d272ee61 100644 --- a/src/hooks/useSelector.js +++ b/src/hooks/useSelector.js @@ -1,7 +1,8 @@ import { useReducer, useRef, useEffect, useMemo, useLayoutEffect } from 'react' import invariant from 'invariant' -import { useReduxContext as useDefaultReduxContext } from './useReduxContext' +import { useReduxContext } from './useReduxContext' import Subscription from '../utils/Subscription' +import { ReactReduxContext } from '../components/Context' // React currently throws a warning when using useLayoutEffect on the server. // To get around it, we can conditionally useEffect on the server (no-op) and @@ -95,14 +96,14 @@ function useSelectorWithStoreAndSubscription( /** * Hook factory, which creates a `useSelector` hook bound to a given context. * - * @param {Function} [useReduxContext] Hook which returns the Redux context. + * @param {Function} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useSelector` hook bound to the specified context. */ -export function createSelectorHook(useReduxContext = useDefaultReduxContext) { +export function createSelectorHook(context = ReactReduxContext) { return function useSelector(selector, equalityFn = refEquality) { invariant(selector, `You must pass a selector to useSelectors`) - const { store, subscription: contextSub } = useReduxContext() + const { store, subscription: contextSub } = useReduxContext(context) return useSelectorWithStoreAndSubscription( selector, diff --git a/src/hooks/useStore.js b/src/hooks/useStore.js index 336830606..376578fdb 100644 --- a/src/hooks/useStore.js +++ b/src/hooks/useStore.js @@ -1,14 +1,15 @@ -import { useReduxContext as useDefaultReduxContext } from './useReduxContext' +import { ReactReduxContext } from '../components/Context' +import { useReduxContext } from './useReduxContext' /** * Hook factory, which creates a `useStore` hook bound to a given context. * - * @param {Function} [useReduxContext] Hook which returns the Redux context. + * @param {Function} [context=ReactReduxContext] Context passed to your ``. * @returns {Function} A `useStore` hook bound to the specified context. */ -export function createStoreHook(useReduxContext = useDefaultReduxContext) { +export function createStoreHook(context = ReactReduxContext) { return function useStore() { - const { store } = useReduxContext() + const { store } = useReduxContext(context) return store } } diff --git a/src/index.js b/src/index.js index f94836071..d02c35a07 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,6 @@ import connect from './connect/connect' import { useDispatch, createDispatchHook } from './hooks/useDispatch' import { useSelector, createSelectorHook } from './hooks/useSelector' import { useStore, createStoreHook } from './hooks/useStore' -import { createReduxContextHook } from './hooks/useReduxContext' import { setBatch } from './utils/batch' import { unstable_batchedUpdates as batch } from './utils/reactBatchedUpdates' @@ -26,6 +25,5 @@ export { createSelectorHook, useStore, createStoreHook, - createReduxContextHook, shallowEqual } diff --git a/test/hooks/useDispatch.spec.js b/test/hooks/useDispatch.spec.js index 908b5c76d..72653575c 100644 --- a/test/hooks/useDispatch.spec.js +++ b/test/hooks/useDispatch.spec.js @@ -4,8 +4,7 @@ import { renderHook } from 'react-hooks-testing-library' import { Provider as ProviderMock, useDispatch, - createDispatchHook, - createReduxContextHook + createDispatchHook } from '../../src/index.js' const store = createStore(c => c + 1) @@ -25,9 +24,7 @@ describe('React', () => { describe('createDispatchHook', () => { it("returns the correct store's dispatch function", () => { const nestedContext = React.createContext(null) - const useCustomDispatch = createDispatchHook( - createReduxContextHook(nestedContext) - ) + const useCustomDispatch = createDispatchHook(nestedContext) const { result } = renderHook(() => useDispatch(), { // eslint-disable-next-line react/prop-types wrapper: ({ children, ...props }) => ( diff --git a/test/hooks/useSelector.spec.js b/test/hooks/useSelector.spec.js index db363ae52..47d7dc599 100644 --- a/test/hooks/useSelector.spec.js +++ b/test/hooks/useSelector.spec.js @@ -9,8 +9,7 @@ import { useSelector, shallowEqual, connect, - createSelectorHook, - createReduxContextHook + createSelectorHook } from '../../src/index.js' import { useReduxContext } from '../../src/hooks/useReduxContext' @@ -403,9 +402,7 @@ describe('React', () => { it('subscribes to the correct store', () => { const nestedContext = React.createContext(null) - const useCustomSelector = createSelectorHook( - createReduxContextHook(nestedContext) - ) + const useCustomSelector = createSelectorHook(nestedContext) let defaultCount = null let customCount = null