[英]How to use "next-redux-wrapper" with "Next.js", "Redux-ToolKit" and Typescript properly?
I'm using RTK (redux-toolkit) inside a Next.js App.我在 Next.js 应用程序中使用 RTK(redux-toolkit)。 And I'm trying to dispatch an AsyncThunk Action inside "getInitialProps".我正在尝试在“getInitialProps”中调度一个 AsyncThunk Action。 When searching I found a package called "next-redux-wrapper" that exposes the "store" inside "getInitialProps", but I'm struggling to figure out how to make it work with my project.搜索时,我发现了一个名为“next-redux-wrapper”的 package,它暴露了“getInitialProps”中的“商店”,但我正在努力弄清楚如何让它与我的项目一起使用。
Here's a barebone sample of the project where I'm using Typescript with 2 reducers at the moment.这是该项目的准系统示例,我目前正在使用带有 2 个减速器的 Typescript。 One reducer is using AsyncThunk to get data from an API.一个 reducer 使用 AsyncThunk 从 API 获取数据。 I already installed "next-redux-wrapper" but I don't know how to implement it around the so that all pages get access to the "store" inside "getInitialProps".我已经安装了“next-redux-wrapper”,但我不知道如何实现它,以便所有页面都可以访问“getInitialProps”中的“store”。 The Docs of that package has an example but rather a confusing one.该 package 的文档有一个示例,但令人困惑。
Here's how my store.ts looks like...这是我的 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>
>;
As you can see I imported next-redux-wrapper
, but that's abuout it.如您所见,我导入next-redux-wrapper
,仅此而已。
And here's how my "_app.tsx" looks like...这就是我的“_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;
I need to be able to dispatch the "getKanyeQuote" action in "getInitialProps" on this page...我需要能够在此页面的“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;
And here's a link to a full sample.这是完整示例的链接。 https://stackblitz.com/edit/github-bizsur-zkcmca?file=src%2Ffeatures%2Fcounter%2Freducer.ts https://stackblitz.com/edit/github-bizsur-zkcmca?file=src%2Ffeatures%2Fcounter%2Freducer.ts
Any help is highly appreciated.非常感谢任何帮助。
Following the Usage guide on next-redux-wrapper
repo.遵循next-redux-wrapper
repo 上的使用指南。 Within you store file will be在您的存储文件中将是
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);
and _app.js file change following和 _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);
Then direct to /kanye
page It should works然后直接到/kanye
页面它应该可以工作
https://stackblitz.com/edit/github-bizsur-azd1ro?file=src%2Fpages%2Fkanye.tsx https://stackblitz.com/edit/github-bizsur-azd1ro?file=src%2Fpages%2Fkanye.tsx
First, configure wrapper:首先,配置包装器:
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 });
Here the new reducer function merges newly created server store and client store:这里新的 reducer function 合并了新创建的服务器存储和客户端存储:
makeStore
function wrapper 使用makeStore
function 创建一个新的服务器端 redux 存储HYDRATE
action. wrapper 调度HYDRATE
动作。 Its payload is newly created server store它的有效载荷是新创建的服务器存储We're just replacing client state with server state but further reconcilation might be required if the store grows complicated.我们只是用服务器 state 替换客户端 state,但如果商店变得复杂,可能需要进一步协调。
wrap your _app.tsx包装你的 _app.tsx
No need to provide Provider
and store because wrapper
will do it accordingly:无需提供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);
And then you can dispatch thunk action in your page:然后您可以在您的页面中发送 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.