首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >Reducer:让代码更灵活&简洁

Reducer:让代码更灵活&简洁

作者头像
奋飛
发布于 2024-05-25 11:35:43
发布于 2024-05-25 11:35:43
20600
代码可运行
举报
文章被收录于专栏:Super 前端Super 前端
运行总次数:0
代码可运行

解决问题: 🌿 分散的 state,导致代码扩展&维护困难; 🌾 对于输入值的控制/转换等(如希望限制age在1-120之间)

React 表单场景的开发中,往往需要维护众多 state (如,表单数据),过多的 state 会导致源代码冗长,可读性比较差;且未来增删改字段,需要修改的地方也较多,难以维护。

举例:下述表单有三个字段,需要提交给服务

常规写法

针对每个字段封装单独的 state 管理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default () => {
    const [name, setName] = useState('');
    const [age, setAge] = useState(null);
    const [address, setAddress] = useState('');

    return (
        <div>
            <label htmlFor="name">name</label>
            <input type="text" value={name} onChange={(e) => setName(e.target.value)} /><br/>
            <label htmlFor="age">age</label>
            <input type="number" value={age} onChange={(e) => setAge(e.target.value)} /><br/>
            <label htmlFor="address">address</label>
            <input type="text" value={address} onChange={(e) => setAddress(e.target.value)} /><br/>
            {name}-{age}-{address}
        </div>
    )
}

每个表单项有自己的 state 及对应的修改值的方法,如果未来对某个表单项进行增删改,与 state 配套的 DOM 需要同步处理。

统一 state

将字段封装到一个 state 管理。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default () => {
    const  [personalInfo, setPersonalInfo] = useState({
        name: '',
        age: null,
        address: ''
    })

    return (
        <div>
            {
                Object.keys(personalInfo).map((key) => {
                    return <div key={key}>
                        <label htmlFor={key}>{key}</label>
                        <input type="text" value={personalInfo[key]} onChange={(e) => setPersonalInfo({...personalInfo, [key]: e.target.value})} />
                    </div>
                 })
            }
            {personalInfo.name}-{personalInfo.age}-{personalInfo.address}
        </div>
    )
}

这种方式可以精简代码,但需要注意不能直接改变原对象,需要通过 ==...personalInfo来处理。

如果需要对某个值从“数据”层面(如age只允许1-120)做判断,使用这种方式无法完成。

当然,首先要在UI中提供验证

reducer 封装

使用 reducer 进行封装管理。如果对 reducer 还不熟悉,可以跳转到文章尾部,查看相关介绍(来自官网)。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
export default () => {
    const [personalInfo, setPersonalInfo] = useReducer((state, next) => {
        return {...state, ...next};
    }, {name: '', age: null, address: ''})

    return (
        <div>
            {
                Object.keys(personalInfo).map((key) => {
                    return <div key={key}>
                        <label htmlFor={key}>{key}</label>
                        <input type="text" value={personalInfo[key]} onChange={(e) => setPersonalInfo({[key]: e.target.value})} />
                    </div>
                 })
            }
            {personalInfo.name}-{personalInfo.age}-{personalInfo.address}
        </div>
    )
}

以一种集中的方式且可以确保 state 总是有效的。并提供了一个控制 state 的函数能力(可以控制无效的数据,避免无效的渲染)。

如:上述提到的,希望age控制在1-120之间

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const [personalInfo, setPersonalInfo] = useReducer((state, next) => {
    const newState = {...state, ...next};
    if (newState.age > 120) newState.age = 120;
    if (newState.age < 1) newState.age = 1;
    return newState;
}, {name: '', age: null, address: ''})

当然,这里也可以使用官方推荐的方式:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const [personalInfo, setPersonalInfo] = useReducer((state, action) => {
    const newState = {...state};
  	switch (action.type) {
        case 'updateAge': {
           newState.age = action.age;
           if (newState.age > 120) newState.age = 120;
    			 if (newState.age < 1) newState.age = 1;
           break;
        }
    }
    return newState;
}, {name: '', age: null, address: ''})

其调用 onChange={(e) => setPersonalInfo({type: 'updateAge', age: e.target.value})}

‼️ useReducer 的状态值(state)是不可变的,不能更改!

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
useReducer((state, next) => {
  // ❌ 改变现存 state 对象
  state.age = next.age;
  return state
  
  // ✔️ 创建新的对象
	return {...state, ...next};
}, {name: '', age: null, address: ''})

这个问题可以通过 Immer 解决。

useReducer

对于拥有许多状态更新逻辑的组件来说,过于分散的事件处理程序可能会令人不知所措。 对于这种情况,可以将组件的所有状态更新逻辑整合到一个外部函数中,这个函数叫作 reducer

useReducer 是一个 React Hook,允许向组件里面添加一个 reducer

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const [state, dispatch] = useReducer(reducer, initialArg, init?) 

参数:

  • reducer:用于更新 state 的纯函数。参数为 state 和 action,返回值是更新后的 state。state 与 action 可以是任意合法值。
  • initialArg:用于初始化 state 的任意值。初始值的计算逻辑取决于接下来的 init 参数。
  • [可选参数] init:用于计算初始值的函数。如果存在,使用 init(initialArg) 的执行结果作为初始值,否则使用 initialArg

返回值:

  • state: 初次渲染时,它是 init(initialArg)initialArg (如果没有 init 函数)。
  • dispatch 函数:用于更新 state 并触发组件的重新渲染。
入参:reducer
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function myReducer (state, action) {
  // 给 React 返回更新后的状态
  return {...}
}
  1. 声明当前状态(state)作为第一个参数;
  2. 声明 action 对象作为第二个参数;
  3. reducer 返回 下一个 状态(React 会将旧的状态设置为这个最新的状态「返回值 state」)。
返回值:dispatch

dispatch 函数允许更新 state 并触发组件的重新渲染。它需要传入一个 action 作为参数:

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
dispatch({ type: 'incremented_age' });

可以是任意类型的值。通常来说 action 是一个对象,其中 type 属性标识类型,其它属性携带额外信息。

  • dispatch 函数 是为下一次渲染而更新 state。因此在调用 dispatch 函数后读取 state 并不会拿到更新后的值,也就是说只能获取到调用前的值。
  • 如果你提供的新值与当前的 state 相同(使用 Object.is 比较),React 会 跳过组件和子组件的重新渲染,这是一种优化手段。虽然在跳过重新渲染前 React 可能会调用你的组件,但是这不应该影响你的代码。
  • React 会批量更新 state。state 会在 所有事件函数执行完毕 并且已经调用过它的 set 函数后进行更新,这可以防止在一个事件中多次进行重新渲染。如果在访问 DOM 等极少数情况下需要强制 React 提前更新,可以使用 flushSync。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-04-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
用动画和实战打开 React Hooks(三):useReducer 和 useContext
随着应用状态越来越复杂,我们迫切需要状态与数据流管理的解决方案。熟悉 React 开发的同学一定听说过 Redux,而在这篇文章中,我们将通过 useReducer + useContext 的组合实现一个简易版的 Redux。首先,我们将带你重新认识“老朋友”useState,并借此引出这篇文章的主角:Reducer 函数与 useReducer 钩子,并通过实战一步步带你理清数据流和状态管理的基本思想。
一只图雀
2020/05/08
1.6K0
全网最简单的React Hooks源码解析!
从React Hooks发布以来,整个社区都以积极的态度去拥抱它、学习它。期间也涌现了很多关于React Hooks 源码解析的文章。本文就以笔者自己的角度来写一篇属于自己的文章吧。希望可以深入浅出、图文并茂的帮助大家对React Hooks的实现原理进行学习与理解。本文将以文字、代码、图画的形式来呈现内容。主要对常用Hooks中的 useState、useReducer、useEffect 进行学习,尽可能的揭开Hooks的面纱。
Nealyang
2022/04/11
2.2K0
全网最简单的React Hooks源码解析!
这个 hook api,曾吓退许多前端开发者
在 React 的学习过程中,有一个大 boss 拦路虎。他不仅概念多,理解起来困难,使用起来也很麻烦,他给 React 学习者带来了巨大的痛苦。因此他臭名昭著。有许多前端开发者因为讨厌他而放弃了 React。但怪就怪在,很多大佬会觉得这个方案非常厉害。
用户6901603
2023/12/19
2300
这个 hook api,曾吓退许多前端开发者
react hook 那些事儿
首先,它是在react16.8版本中引入的概念,也就说如果你的react版本低于16.8,你是不能使用的,因此在使用它的时候,一定要注意react的版本。
程序那些事儿
2023/03/07
5720
react hook 那些事儿
useState避坑指南
React的useState钩子是开发人员在处理函数组件状态时不可或缺的工具。尽管它看起来似乎很简单,但即使是经验丰富的开发人员也可能犯一些常见的错误,导致意外行为和错误。在本文中,我们将探讨八个常见的useState错误,并提供详细的解释和示例,以帮助你避免这些陷阱。
泽霖
2023/11/27
3370
React-Hooks源码深度解读
这个代码有一个问题,在执行 useState 的时候每次都会 var _val = initialValue,初始化数据;
goClient1992
2022/10/03
1.2K0
React Hook实践总结
最近一年几乎都在使用 TypeScript + Hooks 编写函数式组件,这一篇是我使用 hooks 的一些总结。
jadeCarver
2021/01/08
1.1K0
React Hook实践总结
97.精读《编写有弹性的组件》
读了 精读《useEffect 完全指南》 之后,是不是对 Function Component 的理解又加深了一些呢?
黄子毅
2022/03/14
5610
【Hooks】:[组]How to useReducer in React
The concept of a Reducer became popular in JavaScript with the rise of Redux as state management solution for React. But no worries, you don't need to learn Redux to understand Reducers. Basically reducers are there to manage state in an application. For instance, if a user writes something in an HTML input field, the application has to manage this UI state (e.g. controlled components).
WEBJ2EE
2021/02/26
3370
【Hooks】:[组]How to useReducer in React
React Hooks 万字总结
每个 hook 都会有一个 next 指针,hook 对象之间以单向链表的形式相互串联, 同时也能发现 useState 底层依然是 useReducer 再看看更新阶段发生了什么
ConardLi
2021/04/23
1K0
React useReducer 终极使用教程
useReducer 是在 react V 16.8 推出的钩子函数,从用法层面来说是可以代替useState。相信前期使用过 React 的前端同学,大都会经历从 class 语法向 hooks 用法的转变,react 的 hooks 编程给我们带来了丝滑的函数式编程体验,同时很多前端著名的文章也讲述了 hooks 带来的前端心智的转变,这里就不再着重强调,本文则是聚焦于 useReducer 这个钩子函数的原理和用法,笔者带领大家再一次深入认识 useReducer。
蒋川@卡拉云
2022/08/31
4K0
React useReducer 终极使用教程
从react源码看hooks的原理_2023-03-01
其实hooks的定义都来自dispatcher,那我们根据Dispatcher依次去看看他们的实际实现。
flyzz177
2023/03/01
9290
Note·React Hook
React Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
数媒派
2022/12/01
2.3K0
React 组件优化
useReducer 是 useState 的替代品,它可以更好的管理组件的状态。
多云转晴
2020/04/27
7.8K0
React 组件优化
React Hooks教程之基础篇
Hook 是 React 16.8 的新增特性。它可以让你在不编写 class 的情况下使用 state 以及其他的 React 特性。
乐圣
2022/11/19
3.1K0
React Hook实践指南
在React为什么需要Hook这篇文章中我们探讨了React开发团队为什么要为Function Component添加Hook的原因,在本篇文章中我将会为大家提供一份较为全面的React Hook实践指南,其中包括以下方面的内容:
进击的大葱
2022/08/22
2.7K0
从react源码看hooks的原理
其实hooks的定义都来自dispatcher,那我们根据Dispatcher依次去看看他们的实际实现。
flyzz177
2022/10/18
9600
React hooks 最佳实践【更新中】
导语 随着目前需求更新的节奏越来越快,我们目前更多时候原因使用 function component 来代替类的写法,在 hooks 推出之后,我们也可以完全使用 function component 来代替类的写法;但是俗话说的好,没有什么东西是十全十美的,在本次整理总结 hooks 库的过程中,有体验到 hooks 带来的体验提升,同时也存在对比类生命周期写法中不足的地方。 01 React hooks的思想 首先对于原先的类组件而言,最好的思想是封装,我们使用的constructor、componen
用户1097444
2022/06/29
1.5K0
React hooks 最佳实践【更新中】
React Hooks-useTypescript!
在React v16.8新增了Hook,它提供了在函数组件中访问状态和React生命周期等能力,这些函数可以在程序的各个组件之间复用,达到共享逻辑的目的。
写代码的阿宗
2020/09/22
4.3K0
React 设计模式 0x1:组件
驼峰式命名法(Camel Case),也叫小驼峰式命名法(Lower Camel Case)
Cellinlab
2023/05/17
1.1K0
相关推荐
用动画和实战打开 React Hooks(三):useReducer 和 useContext
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验