Redux状态对象多次渲染后变为undefined问题求助
我用React+Redux开发打字练习工具,拆分了三个slice:Test-text(输出测试文本)、Input-text(读取输入文本)、Result(包含accuracy、WPM、WPMaverage的对象)。在获取Result的Accuracy值时,组件出现多次渲染,值依次为100、99、99、undefined、NaN,怀疑和useEffect有关,但不确定具体原因。
相关代码
Result切片
import {createSlice} from "@reduxjs/toolkit" const ResultSlice = createSlice({ name:"Result", initialState: { Accuracy:100, WPM:40, WPMAverage:[] }, reducers:{ setAccuracy(state,action){ return state.Accuracy-1; } } }) export const ResultReducer = ResultSlice.reducer; export const {setAccuracy} = ResultSlice.actions;
InputText切片
import { createSlice } from "@reduxjs/toolkit"; const InputTextSlice = createSlice({ name:"InputText", initialState:[], reducers:{ setValue(State,action){ return action.payload; } } }) export const InputTextReducer = InputTextSlice.reducer; export const {setValue} = InputTextSlice.actions;
Store配置
import { configureStore } from "@reduxjs/toolkit"; import {TestTextReducer} from './slices/TestText'; import { InputTextReducer } from "./slices/InputText"; import { ResultReducer } from "./slices/Result"; import { setTest} from "./slices/TestText"; import { setValue } from "./slices/InputText"; import { setAccuracy } from "./slices/Result"; const store = configureStore({ reducer:{ TestText:TestTextReducer, InputText:InputTextReducer, Result:ResultReducer } }); export {store, setTest, setValue, setAccuracy};
TextBox组件
import React, { useEffect } from 'react'; import { useDispatch,useSelector } from 'react-redux'; import { setValue,setAccuracy } from '../store'; const TextBox = () => { const Test = useSelector((state)=>{ return state.TestText; }) const InputText = useSelector((state)=>{ return state.InputText; }) const Accuracy = useSelector((state)=>{ console.log(state.Result); return state.Result.Accuracy; }) const dispatch = useDispatch(); const handleChange=(e)=>{ dispatch(setValue(e.target.value)); } useEffect(()=>{ handleMatch(); // eslint-disable-next-line react-hooks/exhaustive-deps },[handleChange]) function handleMatch(){ if(Test === InputText){ console.log( "a cmoplete match"); dispatch(setValue("")); return; } if(Test.includes(InputText)){ console.log("good going"); return; } else{ console.log(Accuracy); dispatch(setAccuracy()); return; } } return ( <div className='TextBox'> <h2>Lesson 1</h2> <input type="text" className='text-input' value={Test} style={{backgroundColor:"rgba(55,90,127,255)"}}/> <input type="Text" className='text-input user' onChange={handleChange} value={InputText} /> <div className='performance'> <h4 className='Tags'>WPM:</h4> <h4 className='Tags'>Accuracy:</h4> <h4 className='Tags'>Average WPM:</h4> </div> </div> ) } export default TextBox;
问题原因分析
Result切片状态结构被破坏
setAccuracyreducer中直接返回state.Accuracy-1的数值,而非修改原有的对象结构。第一次调用后,Result状态从包含Accuracy的对象变成了纯数值99,后续再调用时state.Accuracy会变成undefined,计算undefined-1就得到NaN,这就是出现undefined和NaN的核心原因。useEffect依赖错误导致重复触发
将handleChange作为useEffect依赖,但handleChange是组件每次渲染都会重新创建的函数,这会导致useEffect在每次渲染时都执行,重复调用handleMatch并触发setAccuracy,造成多次渲染。加上屏蔽了ESLint的依赖检查,进一步掩盖了问题。匹配逻辑触发时机不合理
实际应该监听InputText的变化来执行匹配检查,而非依赖handleChange函数,因为handleMatch的逻辑完全基于输入文本和测试文本的对比。
修复方案
1. 修正Result切片的reducer
保持state的对象结构,正确更新Accuracy值:
reducers:{ setAccuracy(state,action){ // Redux Toolkit的Immer允许直接修改state state.Accuracy -= 1; // 或者返回新对象:return {...state, Accuracy: state.Accuracy - 1} } }
2. 修复useEffect的依赖和触发逻辑
用useCallback包裹handleMatch,并将依赖改为InputText和Test:
import React, { useEffect, useCallback } from 'react'; // ... const handleMatch = useCallback(() => { if(Test === InputText){ console.log( "a complete match"); dispatch(setValue("")); return; } if(Test.includes(InputText)){ console.log("good going"); return; } else{ console.log(Accuracy); dispatch(setAccuracy()); return; } }, [Test, InputText, Accuracy, dispatch]); useEffect(()=>{ handleMatch(); },[handleMatch])
3. 统一InputText的初始状态类型
InputText存储的是字符串输入,将初始状态从数组[]改为空字符串"",避免类型不一致:
const InputTextSlice = createSlice({ name:"InputText", initialState:"", reducers:{ setValue(state,action){ return action.payload; } } })
内容的提问来源于stack exchange,提问作者vishwa Tj

