繁体   English   中英

如何正确使用带有“Next.js”、“Redux-ToolKit”和 Typescript 的“next-redux-wrapper”?

[英]How to use "next-redux-wrapper" with "Next.js", "Redux-ToolKit" and Typescript properly?

我在 Next.js 应用程序中使用 RTK(redux-toolkit)。 我正在尝试在“getInitialProps”中调度一个 AsyncThunk Action。 搜索时,我发现了一个名为“next-redux-wrapper”的 package,它暴露了“getInitialProps”中的“商店”,但我正在努力弄清楚如何让它与我的项目一起使用。

这是该项目的准系统示例,我目前正在使用带有 2 个减速器的 Typescript。 一个 reducer 使用 AsyncThunk 从 API 获取数据。 我已经安装了“next-redux-wrapper”,但我不知道如何实现它,以便所有页面都可以访问“getInitialProps”中的“store”。 该 package 的文档有一个示例,但令人困惑。

这是我的 store.ts 的样子......

import { Action, configureStore, ThunkAction } from '@reduxjs/toolkit';
import { createWrapper, HYDRATE } from 'next-redux-wrapper';
import { counterReducer } from '../features/counter';
import { kanyeReducer } from '../features/kanye';

export const store = configureStore({
  reducer: {
    counter: counterReducer,
    kanyeQuote: kanyeReducer,
  },
});

export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;

如您所见,我导入next-redux-wrapper ,仅此而已。

这就是我的“_app.tsx”的样子......

import { Provider } from 'react-redux';
import type { AppProps } from 'next/app';
import { store } from '../app/store';

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <Provider store={store}>
      <Component {...pageProps} />
    </Provider>
  );
}

export default MyApp;

我需要能够在此页面的“getInitialProps”中发送“getKanyeQuote”操作...

import React from 'react';
import { useAppDispatch, useAppSelector } from '../app/hooks';
import { getKanyeQuote } from '../features/kanye';

const kanye: React.FC = () => {
  const dispatch = useAppDispatch();
  const { data, pending, error } = useAppSelector((state) => state.kanyeQuote);

  return (
    <div>
      <h2>Generate random Kanye West quote</h2>
      {pending && <p>Loading...</p>}
      {data && <p>{data.quote}</p>}
      {error && <p>Oops, something went wrong</p>}
      <button onClick={() => dispatch(getKanyeQuote())} disabled={pending}>
        Generate Kanye Quote
      </button>
    </div>
  );
};

export default kanye;

这是完整示例的链接。 https://stackblitz.com/edit/github-bizsur-zkcmca?file=src%2Ffeatures%2Fcounter%2Freducer.ts

非常感谢任何帮助。

遵循next-redux-wrapper repo 上的使用指南 在您的存储文件中将是

import { Action, configureStore, ThunkAction } from '@reduxjs/toolkit';
import { createWrapper, HYDRATE } from 'next-redux-wrapper';
import { counterReducer } from '../features/counter';
import { kanyeReducer } from '../features/kanye';

const store = configureStore({
  reducer: {
    counter: counterReducer,
    kanyeQuote: kanyeReducer,
  },
});

export type AppDispatch = typeof store.dispatch;
export type RootState = ReturnType<typeof store.getState>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;

const makeStore = () => store;

export const wrapper = createWrapper(makeStore);

和 _app.js 文件更改如下

import type { AppProps } from 'next/app';
import { wrapper } from '../app/store';

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default wrapper.withRedux(MyApp);

然后直接到/kanye页面它应该可以工作

工作演示

https://stackblitz.com/edit/github-bizsur-azd1ro?file=src%2Fpages%2Fkanye.tsx

首先,配置包装器:

import {
  Action,
  combineReducers,
  configureStore,
  ThunkAction,
} from '@reduxjs/toolkit';
import { createWrapper, HYDRATE } from 'next-redux-wrapper';
import { counterReducer } from '../features/counter';
import { kanyeReducer } from '../features/kanye';

const combinedReducer = combineReducers({
  counter: counterReducer,
  kanyeQuote: kanyeReducer,
});

const reducer = (state, action) => {
  if (action.type === HYDRATE) {
    const nextState = {
      ...state, // use previous state
      ...action.payload, // apply delta from hydration
    };
    return nextState;
  } else {
    return combinedReducer(state, action);
  }
};

export const makeStore = () =>
  configureStore({
    reducer,
  });

type Store = ReturnType<typeof makeStore>;

export type AppDispatch = Store['dispatch'];
export type RootState = ReturnType<Store['getState']>;
export type AppThunk<ReturnType = void> = ThunkAction<
  ReturnType,
  RootState,
  unknown,
  Action<string>
>;

export const wrapper = createWrapper(makeStore, { debug: true });

这里新的 reducer function 合并了新创建的服务器存储和客户端存储:

  • wrapper 使用makeStore function 创建一个新的服务器端 redux 存储
  • wrapper 调度HYDRATE动作。 它的有效载荷是新创建的服务器存储
  • reducer 将服务器存储与客户端存储合并。

我们只是用服务器 state 替换客户端 state,但如果商店变得复杂,可能需要进一步协调。

包装你的 _app.tsx

无需提供Provider和 store,因为wrapper会相应地进行:

import type { AppProps } from 'next/app';
import { wrapper } from '../app/store';

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default wrapper.withRedux(MyApp);

然后您可以在您的页面中发送 thunk 操作:

import { NextPage } from 'next/types';
import React from 'react';
import { useAppDispatch, useAppSelector } from '../app/hooks';
import { getKanyeQuote } from '../features/kanye';
import { wrapper } from '../app/store';

const kanye: NextPage = () => {
  const dispatch = useAppDispatch();
  const { data, pending, error } = useAppSelector((state) => state.kanyeQuote);

  return (
    <div>
      <h2>Generate random Kanye West quote</h2>
      {pending && <p>Loading...</p>}
      {data && <p>{data.quote}</p>}
      {error && <p>Oops, something went wrong</p>}
      <button onClick={() => dispatch(getKanyeQuote())} disabled={pending}>
        Generate Kanye Quote
      </button>
    </div>
  );
};

kanye.getInitialProps = wrapper.getInitialAppProps(
  ({ dispatch }) =>
    async () => {
      await dispatch(getKanyeQuote());
    }
);

export default kanye;

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM