1

所以我试图解决我在使用时面临的保湿问题wrapper.getServerSideProps。当我使用当前设置重新路由时,存储被清除,然后添加新数据,这导致一个白页,因为许多重要数据不再存在(即翻译和 cms 数据)。

redux-dev-tools 的屏幕截图 Hydrate 操作差异:

在此处输入图像描述

从主页路由到产品页面后截取屏幕截图,因此存在现有商店。一切都重置为初始应用程序状态。

我想要做什么

在 store.js 中,我创建了 store 并预见了一个 reducer 来处理 Hydrate 调用。这种方法的缺点是有效负载将始终是一个新的存储对象,因为它是在服务器上调用的。我正在考虑检查 2 个 json 之间的差异,然后只应用差异而不是整个初始存储。

  1. 获取客户端和服务器状态之间的差异。
  2. 制作下一个状态,用修补过的服务器状态覆盖客户端状态,因此这包括来自 hydra 的更新状态和现有客户端状态。
  3. 当前结果是一个白页。

你可以在 store.js 中看到下面的 reducer 代码

//store.js

import combinedReducer from './reducer';

const bindMiddleware = (middleware) => {
    if (process.env.NODE_ENV !== 'production') {
        return composeWithDevTools(applyMiddleware(...middleware));
    }
    return applyMiddleware(...middleware);
};

const reducer = (state, action) => {
  if (action.type === HYDRATE) {
    const clientState = { ...state };
    const serverState = { ...action.payload };

    if (state) {
      // preserve state value on client side navigation

      // Get the difference between the client and server state.
      const diff = jsondiffpatch.diff(clientState, serverState);
      if (diff !== undefined) {
        // If there is a diff patch the serverState, with the existing diff
        jsondiffpatch.patch(serverState, diff);
      }
    }

    // Make next state, overwrite clientstate with patched serverstate
    const nextState = {
      ...clientState,
      ...serverState,
    };

    // Result, blank page.
    return nextState;
  }
  return combinedReducer(state, action);
};

export const makeStore = () => {
    const cookies = new Cookies();
    const client = new ApiClient(null, cookies);

    const middleware = [
        createMiddleware(client), 
        thunkMiddleware.withExtraArgument(cookies),
    ];

    return createStore(reducer, bindMiddleware(middleware));
};

const wrapper = createWrapper(makeStore);

export default wrapper;
//_app.jsx

const App = (props) => {
    const { Component, pageProps, router } = props;

    return (
        <AppComponent cookies={cookies} locale={router.locale} location={router}>
            <Component {...pageProps} />
        </AppComponent>
    );
};

App.getInitialProps = async ({ Component, ctx }) => {
    return {
        pageProps: {
            ...(Component.getInitialProps ? await Component.getInitialProps(ctx) : {}),
        },
    };
};

App.propTypes = {
    Component: PropTypes.objectOf(PropTypes.any).isRequired,
    pageProps: PropTypes.func,
    router: PropTypes.objectOf(PropTypes.any).isRequired,
};

App.defaultProps = {
    pageProps: () => null,
};

export default wrapper.withRedux(withRouter(App));
// Product page
export const getServerSideProps = wrapper.getServerSideProps(
async ({ query, store: { dispatch } }) => {
    const productCode = query.id?.split('-', 1).toString();
    await dispatch(getProductByCode(productCode, true));
});

const PDP = () => {
    const { product } = useSelector((state) => state.product);
    return (
        <PageLayout>
            <main>
                <h1>{product?.name}</h1>
                <div
                    className="description"
                    dangerouslySetInnerHTML={{ __html: product?.description }}
                />
            </main>
        </PageLayout>
    );
};

export default PDP;
4

1 回答 1

3

好的,所以我通过不过度思考这个概念来解决我的问题。回到绘图板并制定了一个简单的解决方案。

得出的结论是,在客户端导航期间只有少数状态对象需要保留。

我只需要对我的 i18n 进行更改,使其动态化,因为我们以页面为基础获取翻译。

对于将来可能遇到类似问题的任何人来说,这是最终的减速器。

const reducer = (state, action) => {
  if (action.type === HYDRATE) {
    const clientState = { ...state };
    const serverState = { ...action.payload };
    const nextState = { ...clientState, ...serverState };

    const locale = nextState.i18n.defaultLocale || config.i18n.defaultLocale;

    const nextI18n = {
      ...state.i18n,
      locale,
      messages: {
        [locale]: {
          ...state.i18n.messages[locale],
          ...nextState.i18n.messages[locale],
        },
      },
      loadedGroups: {
        ...state.i18n.loadedGroups,
        ...nextState.i18n.loadedGroups,
      },
    };

    if (state) {
      nextState.i18n = nextI18n;
      nextState.configuration.webConfig = state.configuration.webConfig;
      nextState.category.navigation = state.category.navigation;
    }

    return nextState;
  }
  return combinedReducer(state, action);
};
于 2021-04-12T10:10:33.327 回答