Typescript 如何在页面刷新时在NextJS中正确地添加Redux状态?
我遇到的问题是在应用程序重新加载/页面刷新时从本地存储水合用户数据 在我的项目中,我将NextJS用于前端,对于支持库,我将使用Typescript 如何在页面刷新时在NextJS中正确地添加Redux状态?,typescript,react-redux,next.js,redux-toolkit,Typescript,React Redux,Next.js,Redux Toolkit,我遇到的问题是在应用程序重新加载/页面刷新时从本地存储水合用户数据 在我的项目中,我将NextJS用于前端,对于支持库,我将使用redux toolkit用于整个应用程序的redux管理,并使用next redux wrapper用于包装页面的状态管理 用户可以登录,在这种情况下,我将isLoggedIn布尔值存储在本地存储中并处于redux状态。根据isLoggedIn布尔值,我更改Navbar组件样式(Navbar直接包含在\u app.tsx中) 当用户刷新任何页面时,isLoggedIn
redux toolkit
用于整个应用程序的redux管理,并使用next redux wrapper
用于包装页面的状态管理
用户可以登录,在这种情况下,我将isLoggedIn
布尔值存储在本地存储中并处于redux状态。根据isLoggedIn
布尔值,我更改Navbar
组件样式(Navbar
直接包含在\u app.tsx
中)
当用户刷新任何页面时,isLoggedIn
boolean不会加载到状态,而是存在于本地存储器中
在过去,我一直在使用redux persist
,但我选择不使用它,因为PersistGate
会阻止UI呈现,直到从存储中获取持久化数据,这与SSR的思想相冲突
目前我使用\u App.ts
中的App.getInitialProps
方法解决了isLoggedIn
加载问题,这会导致为每个加载的页面调用下一个redux persist
,但这带来了另一个问题:所有页面现在都是服务器端呈现的,没有NextJS的静态页面优化
有没有办法不丢失NextJS的静态页面优化,不使用redux persist
库,并且在刷新任何页面时仍然能够在客户端存储中添加水合物
当前代码结构(为了简单起见,省略了一些代码):
文件:_app.tsx
从“存储”导入{wrapper};
常量MyApp=({Component,pageProps}:AppProps)=>{
返回(
);
};
MyApp.getInitialProps=async(appContext)=>{
const-appProps=await-App.getInitialProps(appContext);
返回{…appProps};
};
导出默认包装器。withRedux(MyApp);
文件:store.ts
导入{
联合传感器,
配置存储,
EnhancedStore,
getDefaultMiddleware
}来自“@reduxjs/toolkit”;
从“下一个redux包装器”导入{createWrapper,MakeStore};
从“lib/slices/userSlice”导入userReducer;
const rootReducer=combinereducer({
用户:userReducer
});
const setupStore=(上下文):EnhancedStore=>{
常量中间件=[…getDefaultMiddleware(),thunkMiddleware];
if(process.env.NODE_env===‘development’){
推送(记录器);
}
返回配置存储({
还原剂:根还原剂,
中间件,
//预加载状态,
devTools:process.env.NODE_env==='development'
});
};
const makeStore:makeStore=(上下文)=>setupStore(上下文);
export const wrapper=createWrapper(makeStore{
调试:process.env.NODE_env==='development'
});
文件:userSlice.ts
从'@reduxjs/toolkit'导入{createSlice};
从“下一个redux包装器”导入{HYDRATE};
常量初始状态={
伊斯洛格丁:错
}
export const userSlice=createSlice({
名称:“用户”,
初始状态,
减速器:{
登录:(状态)=>{
state.isLoggedIn=true;
setItem('loggedInData',{isLoggedIn:true});
}
},
外部减速器:(生成器)=>{
建设者
.addCase(水合物)(状态、作用:任何)=>{
如果(窗口类型!==“未定义”){
const storedLoggedInData=localStorage.getItem('loggedInData');
if(storedLoggedInData!=null&&storedLoggedInData){
const parsedJson=JSON.parse(storedLoggedInData);
state.isLoggedIn=parsedJson.isLoggedIn??false;
}否则{
state.isLoggedIn=false
}
}
});
}
});
export const isLoggedInSelector=(state:RootState)=>state.user.isLoggedIn;
导出默认的userSlice.reducer;
文件:Navbar.tsx
从'react redux'导入{useSelector};
从'lib/slices/userSlice'导入{isLoggedInSelector};
导出默认函数Navbar(){
const isLoggedIn=使用选择器(isLoggedInSelector);
返回(
...
)
}
文档中提到,如果在_app.js中使用getInitialProps,您将失去静态优化。我不知道你为什么在服务器端使用redux,我个人会建议你只在客户端使用它,你不再需要使用next redux包装器,因为它使用getInitialProps
带有的示例今天也有同样的问题。问题是我们需要将客户端存储与页面呈现分离,并将其移动到安装组件的
useffect
中。基本思想是,首先完全呈现页面,然后使用客户机存储信息更新页面
直接结合客户机本地存储可能/将干扰水合作用
下面是我使用的一个代码示例
export default const MenuBar = () => {
const isLoggedIn = useSelector((state) => state.isLoggedIn);
useEffect(() => {
// loads from clients local storage
const auth = loadAuthenticationToken();
if (auth !== null) {
// updates the store with local storage data
dispatch(actions.jwtTokenUpdate(auth));
}
}, [dispatch]);
if (isLoggedIn) {
return <p>you are logged in</p>;
} else {
return <p>please log in</p>;
}
}
导出默认常量菜单栏=()=>{
const isLoggedIn=useSelector((state)=>state.isLoggedIn);
useffect(()=>{
//从客户端本地存储加载
const auth=loadAuthenticationToken();
if(auth!==null){
//使用本地存储数据更新存储
调度(actions.jwtTokenUpdate(auth));
}
},[发送];
如果(isLoggedIn){
返回您已登录的;
}否则{
返回请登录;
}
}
作为参考,NextJS上的github问题:
还有一篇需要使用窗口进行渲染的博文:我已经阅读了关于
App.getInitialProps
的文档,但我不确定在这种情况下如何避免它。对于某些页面,我使用getServerSideProps
获取SSR的数据。我使用redux thunk进行API调用,它们将响应直接路由到redux。我不想跳过redux作为一个单一的真相来源。这可能是个不好的理由吗