Immer编写简洁的更新state逻辑

2023-11-01

react官网推荐库use-immer:https://www.npmjs.com/package/use-immer
引入:import { useImmer } from "use-immer";

优点:

  1. 简化代码: 只需要关注需要变动的部分,而 immer 本身将在后台处理其余部分。
  2. 学习成本和替换代价小

一、对象

假如现在有一个嵌套结构的对象:

const personList = {
  name: 'Niki de Saint Phalle',
  artwork: {
    title: 'Blue Nana',
    city: 'Hamburg',
    image: {
        url: 'https://i.imgur.com/Sd1AgUOm.jpg',
        alt: 'test',
    }
  }
}

正常写法

const [person, setPerson] = 
    useState(personList)

setPerson({
  ...person, 
  artwork: { 
    ...person.artwork, 
    image: {
      ...person.artwork.image,
      alt: 'test1'
    }
  }
});

使用use-immer:

const [person, updatePerson] = 
    useImmer(personList)

updatePerson(draft => {
  draft.artwork.image.alt = 'test1';
});
  • draft:一种特殊类型的对象,Proxy,可以保留一份之前的对象
  • Immer 找出哪些部分draft已被更改,并生成一个包含您的编辑的全新对象。

二、数据的双向绑定:immer中的核心 api ——produce

Immer.jsmobx 的作者写的一个 Immutable(不可变数据) 库,核心实现是利用 ES6 的proxy,几乎以最小的成本实现了JavaScript的不可变数据结构。

[图片]

api介绍:

produce(baseState, recipe: (draftState) => void): nextState

基本概念:

  • baseState:被操作对象的最初状态
  • draftState: 根据currentState生成的草稿、是currentState的代理、对draftState所有的修改都被记录并用于生成nextState。在此过程中,currentState不可变
  • recipe:用于操作draftState的函数
  • nextState: 根据draftState生成的最终状态
  • produce: 用于生成nextState或者producer的函数
import produce from "immer"

const baseState = personList

const nextState = produce(baseState, draftState => {
    draftState.artwork.image.alt = 'test1';
})

draftState的修改最终都会体现在nextState,但并不会修改baseState
需要注意的是nextStatebaseState共享未修改的部分。通过produce生成的nextState是被冻结的(使用Object.freeze实现,仅冻结nextStatecurrentState相比更改的部分),直接修改nextstate会报错。

2.1 Proxy 对象

用于创建一个对象的代理,实现基本操作的拦截和自定义(如属性查找、赋值、枚举、函数调用等)
Proxy 对象接受两个参数,

  • 第一个参数:需要操作的对象
  • 第二个参数是设置对应拦截的属性,支持getset(劫持了对应元素的读和写),能够在其中进行一些操作,最终返回一个 Proxy 对象实例
const handle = {     
    get(target, key) {       
        // 这里的 target 就是 Proxy 的第一个参数对象
        console.log('proxy get key', key)       
        return '返回1'     
    },     
    set(target, key, value) {       
        console.log('proxy set key', value)     
    }   
}   
const target = {a:1}   
const p = new Proxy(target, handle)   
p.a = 2 // 所有设置操作都被转发到了 set 方法内部 

2.2 produce

源码:

[图片]

主流程主要根据base创建draft对象、执行用户传入的recipe拦截读写操作,走到自定义的gettersetter最后再解析组装结果返回给用户。

2.3 hook——useImmer

use-Immer库把上述setState+produce的用法封装起来。
它接收一个初始状态,返回一个数组。
数组解构出的第一个值为当前状态,第二个值为状态更新函数(produce 中的 recipe )。

“一”中修改后的

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Immer编写简洁的更新state逻辑 的相关文章

  • 验证以防止角度形式出现重复的形式值

    我有几个表单数组 我需要进行验证 以便每个表单行中的特定字段在所有表单数组中必须是唯一的 如果任何值出现多次 则两个表单字段都必须标记为红色 我设法编写了一个函数 以便如果这些字段有任何更改 该函数将返回 true false 但我不确定如
  • 如何使用 Angular 1.5 中的组件为每个页面设置标题

    我最近开始使用 Angular 1 5 组件 我的应用程序中有多个页面 所以我决定创建一个
  • 嵌套 .ajax() 调用的 JavaScript/jQuery 变量作用域问题

    我很难传递变量postData这是一个嵌套子级的序列化 jQuery 数组对象 ajax call postData成功传递给第一个 ajax 打电话 但是当我尝试在第二次使用它时 ajax 调用时 它不会发布任何表单元素 因为变量在该级别
  • Web Worker 中的 RequireJS

    我正在尝试在网络工作者中使用 RequireJS 问题是我在使用它时不断收到以下错误 Uncaught Error importScripts failed for underscore at lib underscore js 我已经测试
  • 裁剪响应式全宽图像

    我必须剪辑跨越整个宽度的图像 以下事情对我不起作用 剪辑 这需要绝对位置 因此块元素不会堆叠在下面 背景位置 缩放时无法正确剪辑 放大时剪辑的部分会增加 反之亦然 包装器 包装器高度取决于浏览器宽度 因此其值应该是动态的 我使用了 seti
  • div 准备好后如何调用函数?

    我的 javascript 文件中有以下内容 var divId divIDer jQuery divId ready function createGrid Adds a grid to the html html 看起来像这样 div
  • 如何使用 JavaScript 或 jQuery 清除 Google Chrome、Mozilla Firefox 和 Safari 中的剪贴板数据

    我正在开发一个网站 我想在使用 JavaScript 或 jQuery 查看我的网站时按下打印屏幕按钮时清除剪贴板数据 谁能帮我解决这个问题 我在 Internet Explorer 中成功处理了这个问题 提前致谢 由于安全原因 您无法使用
  • 热成像调色板

    自热成像早期以来 红外热像仪经常使用独特的调色板 从黑色到蓝色 品红色 橙色 黄色到亮白色 这个调色板通常被称为Iron or Ironbow 这是使用前视红外相机拍摄的图像的典型假彩色可视化 来源 维基百科 术语科特 http commo
  • Nightmare.js 截图缓冲区长度 0

    我正在运行一个 night js 脚本 我试图在其中截取页面上多个元素的屏幕截图 The first元素被捕获得很好 但折叠下方的所有其他元素都以零长度捕获 我正在努力调试这个问题 任何帮助将非常感激 基本上这个脚本会遍历一个页面并选择al
  • 动画和过渡的组合无法正常工作

    我一直在尝试添加一些基本的 CSS3 动画 目标是在按钮的单击事件上切换类 并根据添加的类对 div 进行动画处理 该代码对于 Firefox 中切换的第一次迭代完美运行 但对于 Chrome 等其他浏览器以及 Firefox 中的下一次迭
  • Xml、xsl Javascript 排序

    我正在寻找一种使用 javascript 对 xml 数据进行排序的方法 并希望最终过滤掉数据 我知道这一切都可以在 xsl 文件中实现 但我想在客户端进行 我已经搜索了多个使用 javascript 进行排序的地方 但其中大部分要么太特定
  • 从 mvc web api httpresponse 生成 csv 并通过 angularjs 接收以供下载

    我正在尝试从我的 Web api 生成一个 CSV 文件并通过 angularjs 接收该文件 我有一个如下所示的 API 控制器 HttpPost public HttpResponseMessage GenerateCSV FieldP
  • Meteor:即使设置了 ANDROID_HOME 也未设置

    操作系统 Ubuntu 14 04 框架 流星1 1 0 2 应用名称 Songofy 这是输出meteor install sdk android meteor install sdk android Found Android bund
  • 无法使用 Excel JavaScript API 设置 NumberFormat

    我正在使用 Excel Javascript API 在搜索文档后 仍然找不到我想要实现的解决方案 因此 我想将所有内容设置为数字格式 文本 这样 Excel 的自动格式设置就不会与任何单元格的内容混淆 不会删除前导零或更改日期格式 文档建
  • Ace Editor 自动完成和多种语言

    如何为 Ace 编辑器创建自动完成功能以及如何突出显示 php 中的 html javascript 和 csshttp ace ajax org http ace ajax org
  • 如何在vuetify中设置固定工具栏?

    在 vuetify 中我使用工具栏
  • Web 文本编辑器中的 RTF 格式

    网络上是否有支持 RTF 格式文档输入的文本编辑器 我知道这对 webdev 来说有点奇怪 但我需要从数据库中读取 RTF 文档 并在基于 Web 的文本编辑器中对其进行编辑 然后将其存储回 RTF 中 在我在转换工具上投入太多资金之前 我
  • 如何使用 Firebase Cloud Functions 在 DataSnapshot 中查找特定值

    我正在尝试创建一个云函数 该函数将在 HTTP 请求 在计时器上发送 上触发 这将删除具有特定值的所有子项 数据库节点如下所示 activities 4GI1QXUJG0MeQ8Bq19WOdCQFo9r1 uid activity ham
  • Beforeunload 无法将用户重定向到另一个页面,当用户尝试关闭窗口/选项卡时,如何将用户重定向到另一个页面/URL?

    我的以下代码无法将用户重定向到另一个页面 window on beforeunload function window location href http www google com 我希望用户在尝试关闭选项卡时被重定向到另一个页面 实
  • 如何在不接受焦点的元素上捕获键盘事件?

    我知道要处理输入字段中的键盘事件 您可以使用 input keyup function e var code e keyCode and 13 is the keyCode for Enter 但是 现在 我有一些div and li元素

随机推荐

  • 用 construct 2 制作简易弹幕游戏

    用 construct 2 制作简易弹幕游戏 1 打开construct 2 加入背景 3 建立新的图层 4 在新的图层里加入素材 超人 弹幕 4 加入鼠标 5 给超人和弹幕设置动作 超人的 弹幕的 6 加入文字框 7 编写代码 完成啦
  • TCP/UDP报文格式及各种通信机制简介

    TCP UDP报文格式及各种通信机制简介 一 UDP报文 二 TCP报文 三 TCP通信机制 1 确认应答机制 2 超时重传机制 3 滑动窗口及快重传机制 4 流量控制 5 拥塞控制及慢启动机制 6 延迟应答 7 捎带应答 8 粘包问题 一
  • PLC中的定时器

    1 脉冲定时器 将指令列表中的 生成脉冲 指令TP拖放到梯形图中 在出现的 调用选项 对话框中 将默认的背景数据块的名称改为T1 可以用它来做定时器的标示符 单击 确定 按钮 自动生成背景数据块 定时器的输入IN为启动输入端 PT为预设时间
  • 二叉搜索树的概念 及 功能代码实现

    1 概念 二叉搜索树 又称 二叉排序树 特点 二叉树 每个节点中保存关键字 key 关键字需要具备 比较 的能力 每个节点 都是 大于左子树 小于右子树 二叉树搜索树中 不会出现 相等的 key 中序遍历 一定是 有序的 时间复杂度 最好和
  • 利用Hbuilder将Vue项目打包成apk

    一 配置config index js 本人没有配置index js文件 就开始进行了打包 结果最终效果是页面空白 解决了空白 接着底部图标 我是用的阿里巴巴图片 资源找不到 所以配置这步比较重要 1 页面空白的解决 打开config in
  • uboot2014移植到QT2440

    http bbs chinaunix net thread 4143968 1 1 html
  • Kotlin 协程(Coroutines)配合使用 Retrofit,网络请求

    第一步 添加所需依赖 管理生命周期 implementation androidx lifecycle lifecycle livedata ktx 2 2 0 implementation androidx lifecycle lifec
  • K-近邻法(KNN算法)

    1 kNN算法 K 最近邻 k Nearest Neighbors 描述 简单地说 k 近邻算法采用测量不同特征值之间的距离方法进行分类 k 近邻算法 是一种基本 分类与回归 方法 它是是 监督学习 中分类方法的一种 属于 懒散学习法 惰性
  • 【实验四】【使用Select 语句查询数据】

    文章目录 数据 一 简单查询 二 汇总查询 三 连接查询和子查询 数据 这里为了体现查询语句的效果 下面根据查询语句的要求设计数据 结果如下 KC表 XSQK表 XS KC表 打开 SQL Server Management Studio
  • 【数据结构与算法】--二叉树OJ题

    单值二叉树 如果二叉树每个节点都具有相同的值 那么该二叉树就是单值二叉树 只有给定的树是单值二叉树时 才返回 true 否则返回 false 示例 1 输入 1 1 1 1 1 null 1 输出 true 示例 2 输入 2 2 2 5
  • 【C语言技巧】滑动滤波算法滤除抖动

    简易滑动滤波算法 算法原理 将新数据放入到数组的最后 每次在得到数据之前先将数据左移一个元素 踢掉第一个元素最旧的数据 最后数组计算平均 include
  • 解决adb push时出现的“Read-only file system“问题

    出现Read only file system问题 不是因为文件或者文件夹的权限不对 而是要push的目录对应的分区是以只读方式挂载的 网上给出的解决办法是重新以读写方式挂载对应分区 以 system分区为例 使用命令 mount o re
  • 手写数字识别画板前后端实现

    1 系统概要 手写数字识别画板系统 按照MVC原则开发 主要由两部分组成 交互界面 视图View 部分是传统的HTML CSS JS网页 这同样也是一种遵循MVC开发方式 手写数字识别部分 模型Model 是使用Python开发的深度学习的
  • 【网络原理】传输层重点协议 TCP与UDP协议详解

    文章目录 一 UDP协议 1 UDP特点 2 UDP协议报文格式 3 基于UDP的应用层协议 4 关于UDP协议的一个拓展问题 经典面试题 二 TCP协议 1 TCP协议报文格式 2 TCP原理 1 确认应答机制 安全机制 2 超时重传机制
  • 【C++STL】快速排序算法(sort)的原理与使用

    一 sort算法原理 std sort 是 C 标准库中提供的排序算法 它使用的是一种经典的排序算法 快速排序 Quicksort 或者是其变种 快速排序是一种基于比较的排序算法 通过不断地选择一个基准值 pivot 将待排序序列分割为两个
  • 做好参加蓝桥杯省赛的准备

    1 选择方向 在除此选择要参加蓝桥杯的方向时是刚学完Java程序设计 对Java产生了比较大的兴趣 也觉得Java是一个特别灵活好用的语言 特别是eclipse的强大快捷键和找错功能使得编程快了很多 也有部分原因是因为C 好长时间没用 都快
  • android oaid

    Oaid获取接入流程 移动智能设备标识公共服务平台 AndroidID IMEI OAID获取 oaid sdk 1 1 0的aar 随着Google对隐私的重视以及Android10的逐渐普及 获取设备的唯一标识越来越来难 在Androi
  • python爬取豆瓣电影并分析_爬取豆瓣电影top250提取电影分类进行数据分析

    标签 空格分隔 python爬虫 一 爬取网页 获取需要内容 我们今天要爬取的是豆瓣电影top250 页面如下所示 我们需要的是里面的电影分类 通过查看源代码观察可以分析出我们需要的东西 直接进入主题吧 知道我们需要的内容在哪里了 接下来就
  • echarts实现横向柱图文字在柱图上面

    前言 echarts实现横向柱图文字在柱图上面 效果图 实现源代码 div style width 100 height 800px div
  • Immer编写简洁的更新state逻辑

    react官网推荐库use immer https www npmjs com package use immer 引入 import useImmer from use immer 优点 简化代码 只需要关注需要变动的部分 而 immer