当前位置: 首页 > news >正文

【React】React18 Hooks 之 useReducer

目录

  • useReducer
    • 案例1:useReducer不带初始化函数
    • 案例2:useReducer带初始化函数
    • 注意事项1:dispatch函数不会改变正在运行的代码的状态
    • 注意事项2:获取dispatch函数触发后 JavaScript 变量的值
    • 注意事项3:触发了reducer,但页面没有更新

在这里插入图片描述

React官方文档

useReducer

useReducer是一个 React Hook,可让你向组件添加一个Reducer 。
用法:

const [state, dispatch] = useReducer(reducer, initialArg, init?)
  • reducer:指定状态如何更新的 Reducer 函数,接受两个参数state(状态)和action(操作)两个参数,并返回下一个状态
  • initialArg:初始值,可以是任何类型的值
  • 可选 init:应返回初始状态的初始化函数。如果未指定,则将初始状态设置为initialArg。否则,将初始状态设置为调用的结果init(initialArg)

useReducer返回一个包含两个值的数组:

  • state(当前状态):在第一次渲染期间,它被设置为init(initialArg)或initialArg(如果没有init)
  • dispatch:该dispatch函数可让您将状态更新为不同的值并触发重新渲染

案例1:useReducer不带初始化函数

步骤:
1、定义一个reducer函数,根据不同的action返回不同的状态
2、组件中调用userReducer(reducer,initialArg)
3、调用dispatch({type:“INC”})通知reducer产生一个新的状态,随后更新UI


const idata = {count:0};
function reducer(state, action) {console.log(state,"state")console.log(action,"action")switch (action.type) {case "INC":return {count:state.count+1}case "DEC":return {count:state.count-1}case "SET":return {count:action.payload}default:return {count:idata}}
}
function App() {const [state, dispatch] = useReducer(reducer, idata);return (<div className="App">this is App{state.count}<button onClick={() => dispatch({ type: "INC" })}>+</button><button onClick={() => dispatch({ type: "DEC" })}>-</button><button onClick={() => dispatch({ type: "SET", payload: 100 })}>update</button></div>);
}export default App;

案例2:useReducer带初始化函数

设置initData为初始化函数,设置state初始状态

#App.js
import Son from "./Son.js";
function App() {return (<div className="App"><Son idata={{count:1}}></Son></div>);}export default App;
#Son.js
import { useReducer } from "react";const initData=()=>{return {count:0}
}function reducer(state, action) {console.log(state,"state")console.log(action,"action")switch (action.type) {case "INC":return {count:state.count+1}case "DEC":return {count:state.count-1}case "SET":return {count:action.payload}default:return initData() }
}const  Son = ({idata})=> {console.log(idata,"idata")const [state, dispatch] = useReducer(reducer, idata,initData);return (<div className="App">this is App<div>Count: {state.count}</div><button onClick={() => dispatch({ type: "INC" })}>+</button><button onClick={() => dispatch({ type: "default" })}>default</button><button onClick={() => dispatch({ type: "DEC" })}>-</button><button onClick={() => dispatch({ type: "SET", payload: 100 })}>update</button></div>);
}export default Son;

注意事项1:dispatch函数不会改变正在运行的代码的状态

点击update按钮,handler函数触发之后,页面Count显示为100,但是打印出来state.count为0

dispatch函数不会改变正在运行的代码的状态,更新状态会请求使用新状态值进行另一次渲染,但不会影响state已在运行的事件处理程序中的 JavaScript 变量。

#Son.js
import { useReducer } from "react";
const initData = () => {return { count: 0 }
}
function reducer(state, action) {switch (action.type) {case "INC":return { count: state.count + 1 }case "DEC":return { count: state.count - 1 }case "SET":return { count: action.payload }default:return initData()}
}const Son = ({ idata }) => {
const [state, dispatch] = useReducer(reducer, idata, initData);const handler =()=>{dispatch({ type: "SET", payload: 100 })console.log(state.count,"state")setTimeout(()=>{console.log(state.count,"state")},1000)}return (<div className="App">this is App<div>Count: {state.count}</div><button onClick={() => dispatch({ type: "INC" })}>+</button><button onClick={() =>  dispatch({ type: "default" })}>default</button><button onClick={() => dispatch({ type: "DEC" })}>-</button><button onClick={() => handler()}>update</button></div >);
}export default Son;

注意事项2:获取dispatch函数触发后 JavaScript 变量的值

执行reducer(state, action)之后,就可以拿到最新的变量的值

  const handler =()=>{let action = { type: "SET", payload: 100 };dispatch(action)console.log(state,"state") //打印0setTimeout(()=>{console.log(state,"state")  //打印0},1000)const nextState = reducer(state, action);console.log(nextState,'nextState')  //打印100}

注意事项3:触发了reducer,但页面没有更新

直接更改状态中的对象或数组,并不会重新渲染。因为下一个状态等于前一个状态,则React 将忽略您的更新Object.is,指向的还是同一个引用地址。所以需要始终更新状态中的对象和状态中的数组。如下:

function reducer(state, action) {switch (action.type) {case 'incremented_age': {// ✅ Correct: creating a new objectreturn {...state,age: state.age + 1};}case 'changed_name': {// ✅ Correct: creating a new objectreturn {...state,name: action.nextName};}// ...}
}

相关文章:

  • C++--智能指针
  • 洛谷 数学进制 7.9
  • C++八股(五)之Linux常用命令
  • Linux内核 -- 内存管理之scatterlist结构使用
  • 实现了 ApplicationContextAware 接口的bean可以接收到 ApplicationContext 的引用
  • 面试经典 150 题
  • 深入理解 Qt 的 `moveToThread`:提升多线程应用性能的关键
  • MySQL GROUP_CONCAT 函数详解与实战应用
  • 基于Java技术的B/S模式书籍学习平台
  • Python中的格式化输出
  • AntDesign上传组件upload二次封装+全局上传hook使用
  • 美国大带宽服务器租用优势和注意事项
  • git配置ssh-keygen -t rsa -c“xxxx@xxxx.com.cn出现Too many arguments.解决办法
  • ChatGPT提问提示指南PDF下载经典分享推荐书籍
  • react-fiber
  • 【划重点】MySQL技术内幕:InnoDB存储引擎
  • Angular2开发踩坑系列-生产环境编译
  • ES6 ...操作符
  • iBatis和MyBatis在使用ResultMap对应关系时的区别
  • JAVA_NIO系列——Channel和Buffer详解
  • java架构面试锦集:开源框架+并发+数据结构+大企必备面试题
  • js数组之filter
  • Solarized Scheme
  • vue自定义指令实现v-tap插件
  • 前端性能优化--懒加载和预加载
  • 嵌入式文件系统
  • 如何在GitHub上创建个人博客
  • 中文输入法与React文本输入框的问题与解决方案
  • 自定义函数
  • 分布式关系型数据库服务 DRDS 支持显示的 Prepare 及逻辑库锁功能等多项能力 ...
  • #QT(QCharts绘制曲线)
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (70min)字节暑假实习二面(已挂)
  • (C语言)球球大作战
  • (delphi11最新学习资料) Object Pascal 学习笔记---第8章第5节(封闭类和Final方法)
  • (react踩过的坑)antd 如何同时获取一个select 的value和 label值
  • (八)Flask之app.route装饰器函数的参数
  • (第9篇)大数据的的超级应用——数据挖掘-推荐系统
  • (动态规划)5. 最长回文子串 java解决
  • (九)c52学习之旅-定时器
  • (九)One-Wire总线-DS18B20
  • (区间dp) (经典例题) 石子合并
  • (算法)N皇后问题
  • (原创)攻击方式学习之(4) - 拒绝服务(DOS/DDOS/DRDOS)
  • (转)创业家杂志:UCWEB天使第一步
  • ./configure,make,make install的作用
  • .net MVC中使用angularJs刷新页面数据列表
  • .Net 基于.Net8开发的一个Asp.Net Core Webapi小型易用框架
  • .NET开发人员必知的八个网站
  • .NET企业级应用架构设计系列之应用服务器
  • .Net转Java自学之路—SpringMVC框架篇六(异常处理)
  • [ACM独立出版]2024年虚拟现实、图像和信号处理国际学术会议(ICVISP 2024)
  • [C#]科学计数法(scientific notation)显示为正常数字
  • [C++] 多线程编程-thread::yield()-sleep_for()
  • [docker] Docker容器服务更新与发现之consul