【问题标题】:Redux with Nextjs - Error: could not find react-redux context value; please ensure the component is wrapped in a <Provider>带有 Nextjs 的 Redux - 错误:找不到 react-redux 上下文值;请确保组件包装在 <Provider> 中
【发布时间】:2023-02-24 06:09:24
【问题描述】:

我正在获取应用程序呈现之前从服务器获取数据,通过将 data 存储到 redux 存储中。

并面临这个错误:

错误:找不到 react-redux 上下文值;请确保组件包裹在

_app.tsx

function MyApp({ Component, pageProps, data }: AppProps & { data: any }) {
  console.log(data); // data is here

  const dispatch = useDispatch();

  useEffect(() => {
    // Dispatch an action to store the fetched data in Redux store
    dispatch(saveData(data));
  }, [dispatch]);

  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  );
}

MyApp.getInitialProps = async ({ Component, ctx }) => {
  const data = await fetch(`http://base-url/my-route`).then((res) => res.json());

  let pageProps = {};

  if (Component.getInitialProps) {
    pageProps = await Component.getInitialProps(ctx);
  }

  return { pageProps, data };
};

export default MyApp;

store 是从 store.ts 导出的,我可以在应用程序的其他部分很好地使用这些 useDispatch 和 useSelector。

【问题讨论】:

  • 我认为在 _app.tsx 中使用 useDispatchdispatch 是行不通的,因为 _app.tsxstore 中的 providing 并且无权访问商店。 Meaninig,只有&lt;Provider /&gt; 内部的组件可以访问存储并可以调度操作。 _app.tsx 不是这种情况。所以,我认为这就是问题所在。

标签: javascript reactjs redux


【解决方案1】:

您不能在Provider 之外使用useDispatch

你可以在你的Component中使用useDispatch,但不能在MyApp中使用, 因为 ComponentProvider 内并且连接了 store,但是 MyApp 不是:

function MyApp() {

  // -- here is outside the Provider (no useDispatch possible) --

    return (
        <Provider store={ store }>
            {/* -- here is inside the provider -- */}
            <Component {...pageProps} />
        </Provider>
    );
}

有3种解决方案:

  1. 在创建初始store 对象期间添加数据
  2. 直接使用store对象(没有useDispatch
  3. 创建一个Loader组件,可以使用useDispatch

    1.在创建初始store对象时添加数据

    您肯定有在某处创建商店的代码,例如:

    const myStore = createStore( myReducer, myInitialState );
    

    您可以使用来自的数据创建初始状态myInitialState getInitialProps 已经包含:

    const myStore = useMemo(() => {
        const staticInitialState = {
            // your static state
        };
        
        const myInitialState = {
            ...staticInitialState,
            ...dataFromGetInitialProps
        }; 
        
        return createStore( reducer, myInitialState );
    }, []);
    

    我认为这将是最干净的解决方案,因为它完全符合 React 和 Redux 的概念。

    (显然 createStore 已被弃用,有一个新的,更复杂的 configureStorecreateSlice 的语法,我不熟悉。)

    2.直接使用store对象

    你不能在MyApp里面使用useDispatch,但是你在那里提供 store 对象。 store 对象 has a dispatch and a getState method,您可以使用它,例如:

    function MyApp() {
    
        console.log( store.getState() );
    
        useEffect(() => {
            store.dispatch( saveData( data ) );
        }, []);
        
        return (
            <Provider store={ store }>
                <Component {...pageProps} />
            </Provider>
        );
    }
    

    我认为这没问题,但更像是一种“解决方法”而不是“解决方案”,因为直接使用 store 方法 好像有点多低级比使用 Provider 更高级 用例。

    3. 创建一个“Loader”组件

    您可以在Provider 中创建一个组件,并将您的dispatch 逻辑放在那里。 或者你可以创建一个 Wrapper HOC Component 左右,如果更合适的话。

    function DataLoader({ data }){
    
        const dispatch = useDispatch();
    
        useEffect( () => {
            dispatch( saveData( data ) );
        }, [] );
    
        return null;
    }
    
    function MyApp({ Component, pageProps, data }){
        return (
            <Provider store={ store }>
                <DataLoader data={ data } />
                <Component { ...pageProps } />
            </Provider>
        );
    }
    

    这对我来说似乎很老套,因为它(错误地)将组件用作一种“生命周期挂钩”, DataLoader 和它被放入的位置之间没有逻辑关系 代码(它实际上可以在任何地方,只要组件在正确的时间呈现)。

【讨论】:

    猜你喜欢
    • 2020-09-08
    • 2020-06-05
    • 2021-03-12
    • 1970-01-01
    • 1970-01-01
    • 2021-05-15
    • 1970-01-01
    • 2022-06-24
    • 2020-05-31
    相关资源
    最近更新 更多