You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React+React-Router6+Redux-Toolkit页面刷新/跳转后state丢失问题

Redux状态丢失问题:页面刷新/跳转后状态重置

我用React、React-Router 6和Redux-Toolkit练手时碰到个问题——页面刷新或者跳转到其他路由后,Redux里的状态就没了,控制台还会显示之前页面的state。


相关代码片段

Post.js 组件代码

import React, { useEffect } from 'react'
import { useNavigate, useParams } from 'react-router-dom'
import jwtDecode from 'jwt-decode';
import { useSelector, useDispatch } from 'react-redux';
import { getPostAsync, postsSelector, deletePostAsync } from '../redux/slices/postSlice';

const Post = () => {
    const { post } = useSelector(postsSelector);
    const { postId } = useParams();
    const navigate = useNavigate();
    const dispatch = useDispatch();

    useEffect(() => {
        dispatch(getPostAsync(postId));
        // 视频中控制台日志的来源
        console.log(post);
    }, [dispatch, postId]);

    const handleDelete = () => {
        dispatch(deletePostAsync(postId));
        navigate('/posts')
    }

    const handleUpdate = () => {
        navigate(`/posts/${postId}/update-post`)
    }

    //解码token以获取用户名属性,将其指定为帖子作者
    const token = localStorage.getItem('user');
    const decode = jwtDecode(token);

  return (
    <div>
        <h1>{post.title}</h1>
        <h2>{post.body}</h2>
        <p>Author: {post.author}</p>       
        {decode._id === post.user_id && 
            <div className='button-group'>
                <button onClick={handleDelete}>Delete</button> 
                <button onClick={handleUpdate}>Update</button>     
        </div>}
    </div>
  )
}

export default Post

Redux Slice 初始状态

export const postSlice = createSlice({
  name: 'posts',
  initialState: {
    posts: [],
    post: {},
    loading: false,
    error: false
  }
})

Redux 同步reducer(getPost)

getPost: (state, action) => {
    state.post = action.payload;
} 

异步获取帖子逻辑(getPostAsync)

export const getPostAsync = (postId) => async (dispatch) => {
    try {
        const response = await axiosWithAuth().get(`api/posts/${postId}`);
        dispatch(getPost(response.data));
    } catch (error) {
        dispatch(setError(error));
    }
}

问题原因与解决办法

核心原因

Redux状态默认只存在内存中:页面刷新时浏览器重启JS环境,内存里的状态会被清空,直接回到Slice定义的初始状态;路由跳转时,若新页面未及时触发数据请求,会暂时显示旧的state,直到新请求完成。

具体修复步骤

  1. 页面刷新时的状态持久化
    把Redux状态存到localStorage里,推荐用redux-persist库快速实现:

    • 安装依赖:npm install redux-persist
    • 修改Redux store配置:
      // store.js
      import { configureStore } from '@reduxjs/toolkit';
      import { persistStore, persistReducer } from 'redux-persist';
      import storage from 'redux-persist/lib/storage'; // 默认用localStorage
      import { postSlice } from './slices/postSlice';
      
      const persistConfig = {
        key: 'root',
        storage,
        whitelist: ['posts'] // 指定要持久化的slice
      };
      
      const persistedReducer = persistReducer(persistConfig, postSlice.reducer);
      
      export const store = configureStore({
        reducer: {
          posts: persistedReducer,
        },
        middleware: (getDefaultMiddleware) =>
          getDefaultMiddleware({
            serializableCheck: false, // 关闭序列化检查避免警告
          }),
      });
      
      export const persistor = persistStore(store);
      
    • 根组件用PersistGate包裹:
      // index.js
      import { Provider } from 'react-redux';
      import { PersistGate } from 'redux-persist/integration/react';
      import { store, persistor } from './redux/store';
      
      ReactDOM.createRoot(document.getElementById('root')).render(
        <Provider store={store}>
          <PersistGate loading={null} persistor={persistor}>
            <App />
          </PersistGate>
        </Provider>
      );
      
  2. 路由跳转后的状态更新优化
    原代码中useEffect里直接console.log(post)会打印旧值,因为异步请求还没完成,要监听post变化再打印:

    // 替换原有的console.log逻辑
    useEffect(() => {
      console.log(post);
    }, [post]);
    

    另外,你的useEffect已经把postId加入依赖数组,路由跳转后postId变化时会自动重新发起请求,这部分逻辑没问题。

  3. 避免空值渲染
    组件渲染时先判断post是否有数据,防止出现空内容:

    return (
      <div>
        {!post.title ? <div>加载中...</div> : (
          <>
            <h1>{post.title}</h1>
            <h2>{post.body}</h2>
            <p>Author: {post.author}</p>       
            {decode._id === post.user_id && 
              <div className='button-group'>
                <button onClick={handleDelete}>Delete</button> 
                <button onClick={handleUpdate}>Update</button>     
              </div>}
          </>
        )}
      </div>
    )
    

内容的提问来源于stack exchange,提问作者Gerald Thomas

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.14 13:05:30