Redux状态未变更却触发useEffect重复执行问题求助
问题描述
我花了3小时试图解决这个问题:我的Redux状态通过redux-persist持久化到localStorage中,我希望在状态变更时显示欢迎提示,因此将该Redux状态作为useEffect的依赖项传入。但每次从菜单返回包含该欢迎提示的页面时,useEffect都会触发并显示欢迎消息,我完全不清楚原因。
Store代码
import { configureStore } from '@reduxjs/toolkit' import counterReducer from '../components/main/childCount' import animalReducer from '../components/animal/animalType' import storage from 'redux-persist/lib/storage'; import {combineReducers} from "redux"; import { persistReducer } from 'redux-persist'; import thunk from 'redux-thunk'; const reducers = combineReducers({ counter: counterReducer, animal: animalReducer, }) const persistConfig = { key: 'root', storage }; const persistedReducer = persistReducer(persistConfig, reducers); export const store = configureStore({ reducer: persistedReducer, middleware: [thunk] });
Dispatch相关组件代码
import React from "react"; import { useSelector, useDispatch } from "react-redux"; import { changeAnimal } from './animalType' import { reset } from '../main/childCount' export default function Animal() { const count = useSelector((state) => state.counter.value); const Animal = useSelector((state) => state.animal.value); const dispatch = useDispatch(); return ( <div> <div className="container-fluid w-50 mt-5"> <select className="form-select" aria-label="Default select example" defaultValue={Animal} onChange={(e) => dispatch(changeAnimal(e.target.value))} > <option value="Lion">Lion</option> <option value="Cat">Cat</option> <option value="Snake">Snake</option> <option value="Panda">Panda</option> <option value="Dog">Dog</option> <option value="Penguin">Penguin</option> </select> </div> </div> ); }
欢迎提示组件代码
import React, { useEffect, useState, useLayoutEffect } from "react"; import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import { useSelector } from 'react-redux'; export default function Child() { const count = useSelector((state) => state.counter.value) const Animal = useSelector((state) => state.animal.value); useEffect(() => { toast.info('Welcome to my family, I am ' + Animal + ' Parent!', { position: "top-left" }); }, [Animal]); return ( <div className="border border-3 border-success m-5"> <div className="badge text-bg-warning fs-5 m-4">{Animal} has {count} child</div> <ToastContainer /> </div> ); }
原因分析
问题出在redux-persist的状态恢复机制上:当你从菜单返回页面时,组件会重新挂载,redux-persist会从localStorage中读取持久化的状态并更新Redux store。这个更新过程会导致Animal的值从组件初始挂载时的默认值(比如reducer里的初始值)变为持久化后的值,触发useEffect的依赖变化,从而弹出提示。
解决方案
用useRef存储组件首次挂载时的Animal值,只在用户主动修改状态(而非persist恢复)时触发提示:
修改后的欢迎提示组件代码:
import React, { useEffect, useRef } from "react"; import { ToastContainer, toast } from "react-toastify"; import "react-toastify/dist/ReactToastify.css"; import { useSelector } from 'react-redux'; export default function Child() { const Animal = useSelector((state) => state.animal.value); // 存储组件首次挂载时的Animal值(即persist恢复后的最终值) const initialAnimalRef = useRef(Animal); const count = useSelector((state) => state.counter.value); useEffect(() => { // 只有当当前Animal值和初始存储的值不同时,才触发提示 // 排除persist恢复时的状态更新,只响应用户主动操作 if (Animal !== initialAnimalRef.current) { toast.info('Welcome to my family, I am ' + Animal + ' Parent!', { position: "top-left" }); // 更新ref,下次变更时以最新值为基准 initialAnimalRef.current = Animal; } }, [Animal]); return ( <div className="border border-3 border-success m-5"> <div className="badge text-bg-warning fs-5 m-4">{Animal} has {count} child</div> <ToastContainer /> </div> ); }
这个方法的核心是:组件首次挂载时,useRef会记录persist恢复完成后的Animal值。当用户通过下拉框修改状态时,Animal值变化,和ref中的初始值不同,触发提示;而页面返回重新挂载时,ref会重新记录当前persist的Animal值,此时useEffect中比较的是同一个值,不会触发提示。
内容的提问来源于stack exchange,提问作者Anchal Gupta
相关产品推荐
相关产品推荐

