Next.js v12使用next-redux-wrapper时Link跳转后state被重置问题
问题根因
你遇到的重复请求和状态重置问题核心来自两个错误:
- Next.js 服务端与客户端 Redux store 完全隔离:
getServerSideProps每次运行(包括首次访问、客户端导航跳转)都会在服务端创建全新的 Redux store,你在其中写的if(state.address.id === null)判断永远返回 true,所以每次跳转都会触发服务端拉取数据。 getServerSideProps逻辑错误:你只在else分支返回了props,进入拉取数据的if分支后没有任何返回值,会导致 Next.js 拿到异常的返回结果,状态同步出错。
而你的 transaction 切片能正常持久化,是因为它的数据拉取逻辑在客户端执行,服务端 store 中永远没有 transaction 数据,HYDRATE 时不会覆盖客户端已有的状态。
修复方案
1. 修复 getServerSideProps 逻辑
删除无效的服务端状态判断,无论分支都统一返回 props:
export const getServerSideProps = wrapper.getServerSideProps( (store) => async (context) => { // 服务端每次都是全新 store,直接拉取当前地址对应数据即可 await store.dispatch(getWalletDetails(context.params.address)); return { props: { addressDetails: store.getState().address, } } } );
2. 调整 HYDRATE 逻辑避免覆盖有效状态
增加地址一致性判断,只有当前客户端存储的地址和服务端返回的地址一致时,才保留客户端状态,否则更新为新地址的数据:
const rootReducer = (state, action) => { if (action.type === HYDRATE) { const nextState = { ...state, ...action.payload, }; if (state.address?.id && state.address.id === action.payload.address?.id) { // 同一个地址,保留客户端已有的状态避免重复请求 nextState.address = state.address; } else { // 不同地址,用服务端返回的新数据 nextState.address = action.payload.address; } return nextState; } else { return combinedReducer(state, action); } };
3. 可选:客户端拉取兜底(推荐)
如果你的页面不需要强 SEO 需求,更推荐把数据拉取逻辑移到客户端,用 useEffect 判断是否需要拉取,彻底避免服务端重复请求:
import { useRouter } from 'next/router' import { useEffect } from 'react' import { useDispatch, useSelector } from 'react-redux' function Address(props) { const router = useRouter() const currentAddress = router.query.address const dispatch = useDispatch() const storedAddress = useSelector(state => state.address) useEffect(() => { // 只有当前存储的地址和路由地址不一致时才发起请求 if (storedAddress.id !== currentAddress) { dispatch(getWalletDetails(currentAddress)) } }, [currentAddress, storedAddress.id, dispatch]) // 原有组件渲染逻辑不变 return ( <Fragment> <Head> <title>RVN</title> <meta name="description" content="RVN Address" /> </Head> <AddressDetails address={storedAddress}></AddressDetails> <AddressTransactions transactions={storedAddress.last_txs} address={storedAddress.address} ></AddressTransactions> </Fragment> ); }
这种方案下你甚至可以删除 getServerSideProps 里的拉取逻辑,进一步减少服务端压力。
内容的提问来源于stack exchange,提问作者James Gagne
相关产品推荐
相关产品推荐

