使用Nextjs还原-错误:找不到react-redux上下文值;请确保组件 Package 在< Provider>

kb5ga3dv  于 2023-03-02  发布在  React
关注(0)|答案(1)|浏览(147)

在呈现应用程序之前,我通过将data存储到redux存储中来从服务器获取数据。
面对这个错误:
错误:找不到react-redux上下文值;请确保组件 Package 在
_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。

mkshixfv

mkshixfv1#

不能在Provider之外使用useDispatch
您可以在Component中使用useDispatch,但不能在MyApp中使用,因为Component在连接了storeProvider中,但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对象期间添加数据
1.直接使用store对象(不使用useDispatch
1.创建Loader组件,该组件可以使用useDispatch

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

您一定有代码在某处创建存储,例如:

const myStore = createStore( myReducer, myInitialState );

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

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对象有一个dispatch和一个getState方法,你可以使用它们,例如:

function MyApp() {

    console.log( store.getState() );

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

我认为这是可以的,但更像是一种“变通方法”而不是“解决方案”,因为直接使用store方法似乎比使用Provider更“低级”一点,可能是为了更高级的用例。

3.创建一个“Loader”组件

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

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>
    );
}

在我看来,这似乎很不寻常,因为is(mis-)将组件用作一种“生命周期钩子”,并且DataLoader与它在代码中的放置位置之间没有逻辑关系(它实际上可以在任何位置,只要组件在正确的时间呈现)。

相关问题