From d14cdcb3a1aeb79f7ecc51d0c6f1cabe98dcaae3 Mon Sep 17 00:00:00 2001 From: "ben.durrant" Date: Mon, 20 Mar 2023 23:28:03 +0000 Subject: [PATCH 01/28] check for Provider even when using custom context --- src/hooks/useReduxContext.ts | 33 +++++++++++++++++++---------- src/hooks/useSelector.ts | 9 +++++--- src/hooks/useStore.ts | 9 +++++--- test/hooks/useReduxContext.spec.tsx | 22 ++++++++++++++++++- 4 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/hooks/useReduxContext.ts b/src/hooks/useReduxContext.ts index 61b009e9f..1e0f3887b 100644 --- a/src/hooks/useReduxContext.ts +++ b/src/hooks/useReduxContext.ts @@ -2,6 +2,27 @@ import { useContext } from 'react' import { ReactReduxContext } from '../components/Context' import type { ReactReduxContextValue } from '../components/Context' +/** + * Hook factory, which creates a `useReduxContext` hook bound to a given context. This is a low-level + * hook that you should usually not need to call directly. + * + * @param {React.Context} [context=ReactReduxContext] Context passed to your ``. + * @returns {Function} A `useReduxContext` hook bound to the specified context. + */ +export function createReduxContextHook(context = ReactReduxContext) { + return function useReduxContext(): ReactReduxContextValue | null { + const contextValue = useContext(context) + + if (process.env.NODE_ENV !== 'production' && !contextValue) { + throw new Error( + '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. @@ -18,14 +39,4 @@ import type { ReactReduxContextValue } from '../components/Context' * return
{store.getState()}
* } */ -export function useReduxContext(): ReactReduxContextValue | null { - const contextValue = useContext(ReactReduxContext) - - if (process.env.NODE_ENV !== 'production' && !contextValue) { - throw new Error( - 'could not find react-redux context value; please ensure the component is wrapped in a ' - ) - } - - return contextValue -} +export const useReduxContext = /*#__PURE__*/ createReduxContextHook() diff --git a/src/hooks/useSelector.ts b/src/hooks/useSelector.ts index 626b0b483..7388044d2 100644 --- a/src/hooks/useSelector.ts +++ b/src/hooks/useSelector.ts @@ -1,6 +1,9 @@ -import { useContext, useDebugValue } from 'react' +import { useDebugValue } from 'react' -import { useReduxContext as useDefaultReduxContext } from './useReduxContext' +import { + createReduxContextHook, + useReduxContext as useDefaultReduxContext, +} from './useReduxContext' import { ReactReduxContext } from '../components/Context' import type { EqualityFn, NoInfer } from '../types' import type { uSESWS } from '../utils/useSyncExternalStore' @@ -28,7 +31,7 @@ export function createSelectorHook( const useReduxContext = context === ReactReduxContext ? useDefaultReduxContext - : () => useContext(context) + : createReduxContextHook(context) return function useSelector( selector: (state: TState) => Selected, diff --git a/src/hooks/useStore.ts b/src/hooks/useStore.ts index c1dca43cb..5174b9787 100644 --- a/src/hooks/useStore.ts +++ b/src/hooks/useStore.ts @@ -1,10 +1,13 @@ -import { useContext, Context } from 'react' +import { Context } from 'react' import { Action as BasicAction, AnyAction, Store } from 'redux' import { ReactReduxContext, ReactReduxContextValue, } from '../components/Context' -import { useReduxContext as useDefaultReduxContext } from './useReduxContext' +import { + createReduxContextHook, + useReduxContext as useDefaultReduxContext, +} from './useReduxContext' /** * Hook factory, which creates a `useStore` hook bound to a given context. @@ -21,7 +24,7 @@ export function createStoreHook< // @ts-ignore context === ReactReduxContext ? useDefaultReduxContext - : () => useContext(context) + : createReduxContextHook(context) return function useStore< State = S, Action extends BasicAction = A diff --git a/test/hooks/useReduxContext.spec.tsx b/test/hooks/useReduxContext.spec.tsx index 18b31fb0d..0a2278aea 100644 --- a/test/hooks/useReduxContext.spec.tsx +++ b/test/hooks/useReduxContext.spec.tsx @@ -1,5 +1,10 @@ import { renderHook } from '@testing-library/react-hooks' -import { useReduxContext } from '../../src/hooks/useReduxContext' +import { createContext } from 'react' +import { ReactReduxContextValue } from '../../src/components/Context' +import { + createReduxContextHook, + useReduxContext, +} from '../../src/hooks/useReduxContext' describe('React', () => { describe('hooks', () => { @@ -13,6 +18,21 @@ describe('React', () => { /could not find react-redux context value/ ) + spy.mockRestore() + }) + }) + describe('createReduxContextHook', () => { + it('throws if component is not wrapped in provider', () => { + const customContext = createContext(null as any) + const useCustomReduxContext = createReduxContextHook(customContext) + const spy = jest.spyOn(console, 'error').mockImplementation(() => {}) + + const { result } = renderHook(() => useCustomReduxContext()) + + expect(result.error.message).toMatch( + /could not find react-redux context value/ + ) + spy.mockRestore() }) }) From 52a16e3b670493d8cd6098065befc000968351a7 Mon Sep 17 00:00:00 2001 From: "ben.durrant" Date: Mon, 20 Mar 2023 23:46:11 +0000 Subject: [PATCH 02/28] another ts-ignore wee --- src/hooks/useStore.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/hooks/useStore.ts b/src/hooks/useStore.ts index 5174b9787..cf5d8868b 100644 --- a/src/hooks/useStore.ts +++ b/src/hooks/useStore.ts @@ -24,7 +24,8 @@ export function createStoreHook< // @ts-ignore context === ReactReduxContext ? useDefaultReduxContext - : createReduxContextHook(context) + : // @ts-ignore + createReduxContextHook(context) return function useStore< State = S, Action extends BasicAction = A From 07e89acf60a505169a9b3d4ab4cec140af801f17 Mon Sep 17 00:00:00 2001 From: Mark Erikson Date: Tue, 30 May 2023 20:43:57 -0400 Subject: [PATCH 03/28] Update lockfile --- yarn.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn.lock b/yarn.lock index 6dfbe0995..ac58946bc 100644 --- a/yarn.lock +++ b/yarn.lock @@ -8931,7 +8931,7 @@ __metadata: typescript: ^4.3.4 use-sync-external-store: ^1.0.0 peerDependencies: - "@reduxjs/toolkit": ^5.0.0-beta.0 + "@reduxjs/toolkit": ^1 || ^2.0.0-beta.0 "@types/react": ^16.8 || ^17.0 || ^18.0 "@types/react-dom": ^16.8 || ^17.0 || ^18.0 react: ^16.8 || ^17.0 || ^18.0 From ee7ac845555046efc2a4d97da75f7115c7ba014d Mon Sep 17 00:00:00 2001 From: Snehil Kumar <88778723+snehil002@users.noreply.github.com> Date: Sat, 3 Jun 2023 20:47:49 +0530 Subject: [PATCH 04/28] Update quick-start.md typos (#2021) Co-authored-by: Tim Dorr --- docs/tutorials/quick-start.md | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/docs/tutorials/quick-start.md b/docs/tutorials/quick-start.md index fc22ef1cd..4e419f170 100644 --- a/docs/tutorials/quick-start.md +++ b/docs/tutorials/quick-start.md @@ -105,7 +105,8 @@ export const counterSlice = createSlice({ // Redux Toolkit allows us to write "mutating" logic in reducers. It // doesn't actually mutate the state because it uses the Immer library, // which detects changes to a "draft state" and produces a brand new - // immutable state based off those changes + // immutable state based off those changes. + // Also, no return statement is required from these functions. state.value += 1 }, decrement: (state) => { @@ -125,7 +126,7 @@ export default counterSlice.reducer ### Add Slice Reducers to the Store -Next, we need to import the reducer function from the counter slice and add it to our store. By defining a field inside the `reducers` parameter, we tell the store to use this slice reducer function to handle all updates to that state. +Next, we need to import the reducer function from the counter slice and add it to our store. By defining a field inside the `reducer` parameter, we tell the store to use this slice reducer function to handle all updates to that state. ```js title="app/store.js" import { configureStore } from '@reduxjs/toolkit' @@ -206,9 +207,7 @@ That was a brief overview of how to set up and use Redux Toolkit with React. Rec ### Full Counter App Example -The counter example app shown here is also the - -Here's the complete counter application as a running CodeSandbox: +Here's the complete Counter application as a running CodeSandbox: