
在使用react和redux toolkit构建应用时,开发者可能会遇到状态在多次渲染后变为undefined或nan的问题,尤其是在处理数值类型状态时。这通常是由于对redux toolkit中createslice的reducer函数工作原理理解不当造成的。
以一个打字练习工具为例,其中Result slice管理着Accuracy、WPM等性能指标。当用户输入错误时,Accuracy理应递减。然而,在实际运行中,Accuracy的值在多次更新后却出现了100, 99, 99, undefined, NaN的异常序列。通过控制台日志,可以发现state.Result在某个时刻从一个对象变为了一个数字,随后尝试对一个非数字属性进行数学运算,最终导致NaN。
// 原始的 Result slice 代码 (存在问题)
import {createSlice} from "@reduxjs/toolkit"
const ResultSlice = createSlice({
name:"Result",
initialState: {
Accuracy:100,
WPM:40,
WPMAverage:[]
},
reducers:{
setAccuracy(state,action){
// 问题所在:reducer直接返回了一个原始值
return state.Accuracy-1;
}
}
})
export const ResultReducer = ResultSlice.reducer;
export const {setAccuracy} = ResultSlice.actions;问题的核心在于setAccuracy这个reducer函数。在Redux Toolkit中,createSlice内部集成了Immer.js库,这允许我们在reducer中以“可变”的方式直接修改state对象,而Immer会在底层确保生成一个新的不可变状态。然而,如果reducer函数显式地返回了一个值,那么这个返回值将完全替换当前的整个state。
在上述有问题的代码中,setAccuracy reducer返回的是state.Accuracy - 1,这是一个原始的数字值。这意味着,当setAccuracy被调用时,Result slice的整个状态不再是{ Accuracy: ..., WPM: ..., WPMAverage: ... }这样的对象,而是被替换成了Accuracy的当前值(一个数字)。
例如:
为了避免此类问题,Redux Toolkit的reducer函数有两种正确的实现方式:
这是Redux Toolkit结合Immer.js最推荐的方式。在reducer函数内部,你可以直接对传入的state参数(实际上是Immer生成的草稿draft状态)进行修改,就像它是一个可变对象一样。Immer会在背后处理不可变更新的逻辑。
import {createSlice} from "@reduxjs/toolkit"
const ResultSlice = createSlice({
name:"Result",
initialState: {
Accuracy:100,
WPM:40,
WPMAverage:[]
},
reducers:{
setAccuracy(state) { // action参数如果未使用可以省略
// 直接修改 state 对象的属性
state.Accuracy = state.Accuracy - 1;
}
}
})
export const ResultReducer = ResultSlice.reducer;
export const {setAccuracy} = ResultSlice.actions;这种方式代码简洁,易于理解,并且符合直观的“修改”操作。
YouMind
AI内容创作和信息整理平台
207
查看详情
如果你更倾向于传统的不可变更新模式,或者在某些复杂场景下需要完全替换状态,你可以从reducer中返回一个全新的状态对象。在这种情况下,你需要确保返回的是一个包含所有必要属性的完整状态对象。
import {createSlice} from "@reduxjs/toolkit"
const ResultSlice = createSlice({
name:"Result",
initialState: {
Accuracy:100,
WPM:40,
WPMAverage:[]
},
reducers:{
setAccuracy(state) {
// 返回一个新的状态对象,确保包含所有必要的属性
return {
...state, // 展开现有状态,保留其他属性
Accuracy: state.Accuracy - 1
};
}
}
})
export const ResultReducer = ResultSlice.reducer;
export const {setAccuracy} = ResultSlice.actions;虽然这种方法也能正常工作,但与直接修改draft状态相比,它通常需要更多的代码,并且在Redux Toolkit的上下文中,直接修改draft状态是更惯用且推荐的做法。
在组件中,我们通过useSelector钩子从Redux store中获取状态,并通过useDispatch钩子调度action来更新状态。
import React, { useEffect } from 'react';
import { useDispatch,useSelector } from 'react-redux';
import { setValue,setAccuracy } from '../store'; // 导入正确的 action creator
const TextBox = () => {
// ... 其他 useSelector 钩子
const Accuracy = useSelector((state)=>{
console.log(state.Result); // 观察 state.Result 的变化
return state.Result.Accuracy;
})
const dispatch = useDispatch();
const handleChange=(e)=>{
dispatch(setValue(e.target.value));
}
useEffect(()=>{
// 注意:将 handleChange 作为依赖项是不稳定的,因为它会在每次渲染时重新创建。
// 更好的做法是将 handleMatch 逻辑放在 useEffect 内部,并将其依赖项设为 InputText 和 Test。
handleMatch();
// eslint-disable-next-line react-hooks/exhaustive-deps
},[InputText, Test]) // 修正依赖项,确保在输入或测试文本变化时触发匹配逻辑
function handleMatch(){
if(Test === InputText){
console.log( "a complete match");
dispatch(setValue(""));
return;
}
if(Test.includes(InputText)){
console.log("good going");
return;
}
else{
console.log("Current Accuracy:", Accuracy); // 修正日志输出
dispatch(setAccuracy()); // 调度 action
return;
}
}
return (
<div className='TextBox'>
{/* ... 其他 JSX 元素 */}
<div className='performance'>
<h4 className='Tags'>WPM:</h4>
<h4 className='Tags'>Accuracy: {Accuracy}</h4> {/* 显示 Accuracy */}
<h4 className='Tags'>Average WPM:</h4>
</div>
</div>
)
}
export default TextBox;在上述组件代码中,useEffect的依赖项也需要注意。将handleChange作为依赖项是不正确的,因为函数在每次渲染时都会重新创建,导致useEffect无限循环或不按预期触发。正确的做法是将handleMatch的逻辑所依赖的状态(如InputText和Test)作为useEffect的依赖项。
遵循这些原则,可以有效避免Redux Toolkit中常见的状态更新问题,确保应用状态的稳定性和可预测性。
以上就是Redux Toolkit中createSlice状态更新的常见陷阱与解决方案的详细内容,更多请关注其它相关文章!
# js
# 益阳网站建设哪家便宜点
# 亳州seo推广公司报价
# 保定天猫网站建设选择
# SEO站内优化细节总结
# 7元网站建设
# 山西娄烦县免费网站推广
# 山东化妆品积分营销推广
# 东源网站制作推广运营
# 河南一站式营销推广
# 输入框
# 与非
# 表单
# 此类
# 你可以
# 如果你
# 这是
# 是一个
# 的是
# 会在
# red
# 常见问题
# 工具
# go
# react
# seo和ssm
相关栏目:
【
Google疑问12 】
【
Facebook疑问10 】
【
优化推广96088 】
【
技术知识133117 】
【
IDC资讯59369 】
【
网络运营7196 】
【
IT资讯61894 】
相关推荐:
邮编号码查询app有哪些_邮编号码查询推荐app及使用体验
淘口令快速解析技巧
百度小说看书时如何翻页_百度小说手动翻页与自动翻页设置
海外搜索引擎推广效果怎么样,怎么分析效果!
Python csv 模块处理非字符串数据:列表写入 CSV 文件的机制解析
空腹吃苹果好吗 苹果空腹摄入指南
Go语言中方法接收器的选择:值类型还是指针类型?
如何在Python中安全地将环境变量转换为整数并满足Mypy类型检查
VS Code的时间线(Timeline)视图:您的代码时光机
宝妈做视频号该写什么标签话题?宝妈关注的话题有哪些?
《鹿路通》退余额方法
铁拳8在线玩 铁拳8在线秒玩入口
QQ邮箱注册地址 免费获取QQ邮箱账号
OPPO手机参数配置如何开启护眼模式_OPPO手机参数配置护眼模式开启指南
AffinityDesigner图层蒙版怎么用_AffinityDesigner图层蒙版设计应用
Excel如何快速合并单元格内容_Excel文本合并与函数操作技巧
英雄联盟争者留名活动介绍
电脑没有声音了怎么办 电脑声音问题的全面排查与修复指南【详解】
VS Code快捷键when上下文子句的妙用
花生壳内网映射新方案
J*a中的值传递到底指什么_值传递模型在参数传递中的真正含义说明
风车动漫官网首页入口登录 风车动漫在线观看正版地址
《长生:天机降世》火塔小怪大全
谷歌邮箱官方入口链接 谷歌邮箱网页版电脑端快速登录
iQOO手机信号差网络不稳定怎么办 信号问题原因排查与增强设置【攻略】
TikTok搜索结果不显示怎么办 TikTok搜索刷新与优化方法
自定义你的VS Code状态栏,监控关键信息
J*aScript深度克隆:实现高效、健壮与安全的复杂对象复制
国际经济与贸易就业方向解析
火柴人战争网页版在线玩
学习通网页版课程打不开_课程无法访问时的解决方法
5G和6G的连接密度有什么区别 6G每平方公里能连接多少设备
sublime怎么快速在浏览器中预览HTML_sublime配置View in Browser教程
poki官网最新入口 poki小游戏大全入口
Selenium自动化:利用键盘模拟解决复杂日期输入框输入问题
谷歌浏览器官方镜像获取方法_谷歌浏览器网页版入口极速直达
RxJS中如何高效地在一个函数内处理和合并多个数据集合
使用VS Code作为你的个人知识管理系统
PSD转AI文件的简单方法
偃武诸葛亮阵容搭配推荐
外媒评《燕云十六声》DIY载具新玩法:很像《塞尔达传说王国之泪》!
圆通快递官方入口不需要登录 在线查询入口快速查询
PHP中获取HTTP响应状态消息:方法与限制
word页码灰色不能用如何解决
J*aScript与HTML元素交互:图片点击事件与链接处理教程
Win10显卡驱动安装失败怎么办 Win10使用DDU彻底卸载驱动【解决】
批改网网页版登录 批改网电脑版学生登录入口
《三角洲行动》战斗步枪与机枪类改装代码分享
晓晓优选app支付宝绑定方法
Win10怎么设置快速启动 Win10开启快速启动设置方法
2025-10-01
运城市盐湖区信雨科技有限公司是一家深耕海外推广领域十年的专业服务商,作为谷歌推广与Facebook广告全球合作伙伴,聚焦外贸企业出海痛点,以数字化营销为核心,提供一站式海外营销解决方案。公司凭借十年行业沉淀与平台官方资源加持,打破传统外贸获客壁垒,助力企业高效开拓全球市场,成为中小企业出海的可靠合作伙伴。