React和Redux中的不变性
https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/
一、不变性和副作用
1.不变:不断创造新值来替换旧值
2.不变性规则:
(1)当给定相同的输入时,纯函数必须始终返回相同的值
(2)纯函数不能有任何副作用
3.副作用:修改直接函数范围之外的东西
改变/修改传入的参数(的属性)
修改函数外部的任何其他状态,例如全局变量
进行API调用
console.log()
Math.random()
4.会改变数组的数组方法:push,pop,shift,unshift,sort,reverse,splic
如果想对数组进行不可变的操作,可以先复制该数组,再对副本进行操作
5.纯函数只能调用其他纯函数
二、React更喜欢不变性
1.不变性和PureComponent
继承了React.Component的function和class类型的react组件会在父级组件重新渲染或者使用setState时重新渲染。
继承了React.PureComponent的class仅在其状态更新或者其props更新时才会重新渲染。
将props传入到PureComponent中时,需要保证不可变的更新,因为如果直接修改内部或者属性,但是引用不变,则组件无法注意到它已经改变,则不会重新渲染。
2.JS中的引用相等性
对象和数组存储在内存中,当重新分配变量时,变量会指向新的内存地址,但如果仅改变变量的内部结构,变量仍指向相同的地址,地址里面的内容发生变化。
使用===比较对象和数组时,本质是在比较引用地址,即“引用相等”。
修改一个对象时,会修改对象的内容,但不会更改其引用。将一个对象分配给另一个对象时,指向相同的内存位置,对第二个对象的操作也会影响第一个对象的值。
为什么不深入检查是否相等:速度慢,时间复杂度O(N)
比较引用:O(1),不管对象内部有多复杂
3.const只阻止重新分配引用, 不阻止改变对象内容
4.思考:React框架从性能方面考虑,为了保证复杂场景下的性能,在比较的时候没有挨个比较object内部的值,而是比较引用地址,保证每次比较的时间复杂度都是O(1)。因此从这个设计思想出发,在更新State的时候,都是基于旧值返回新值(引用地址改变),而不是直接通过object.属性=xxx来直接修改object的内容。所以大部分语言修改一个object的属性的时候是通过object.属性=xxx来修改,React是基于旧值返回新值。
三、在Redux中更新state(主要内容,前面都是为了解释这个)
1.要求reducers是纯函数,不能直接修改state:接受state和action,基于旧的state,返回一个新的state。上面的部分解释了可变和不可变,下面介绍了,如何不可变的更新state
- 对象扩展运算符…:创建包含与另一个对象或数组完全相同的内容的新对象或数组
3.更新state:会浅合并传入的this.setState()对象
在redux的reducer中:
(1)更新普通的state
return {
…state,
(updates here)
}
(2)更新对象最顶层的属性时,需要复制现有的state,通过…展开对象,然后加入想要更改的属性及其值
function reducer(state, action) {
/*
State looks like:
state = {clicks: 0,count: 0
}
*/
return {
…state,
clicks: state.clicks + 1,
count: state.count - 1
}
}
(3)更新对象中的对象,当想要更新的部分位于深层时,需要把每一级展开并创建副本
function reducer(state, action) {
/*
State looks like:
state = {house: {name: "Ravenclaw",points: 17}
}
*/
// Two points for Ravenclaw
return {
…state, // copy the state (level 0)
house: {
…state.house, // copy the nested object (level 1)
points: state.house.points + 2
}
}
(4)通过key来更新对象
function reducer(state, action) {
/*
State looks like:
const state = {houses: {gryffindor: {points: 15},ravenclaw: {points: 18},hufflepuff: {points: 7},slytherin: {points: 5}}
}
*/
// Add 3 points to Ravenclaw,
// when the name is stored in a variable
const key = “ravenclaw”;
return {
…state, // copy state
houses: {
…state.houses, // copy houses
[key]: { // update one specific house (using Computed Property syntax)
…state.houses[key], // copy that specific house’s properties
points: state.houses[key].points + 3 // update its points property
}
}
}
(5)将一个Item添加到数组中
通过Array.prototype.unshift和push将Item添加到数组前面/后面会改变数组,希望通过不可变的方式添加Item(对象展开复制,或者通过.slice复制后再push)
function reducer(state, action) {
/*
State looks like:
state = [1, 2, 3];
*/
const newItem = 0;
return [ // a new array
newItem, // add the new item first
…state // then explode the old state at the end 添加到前面
];
return [ // a new array
newItem, // add the new item first
…state // then explode the old state at the end 添加到后面
];
//或者通过.slice复制数组,在push到末尾
function reducer(state, action) {
const newItem = 0;
const newState = state.slice();
newState.push(newItem);
return newState;
(6)通过map更新数组中的item
通过.map来遍历每个item,找到要修改的item,使用返回值作为这个item新的值,最后map返回一个新的数组,需要筛选则使用.filter
function reducer(state, action) {
/*
State looks like:
state = [1, 2, "X", 4];
*/
return state.map((item, index) => {
// Replace “X” with 3
// alternatively: you could look for a specific index
if(item === “X”) {
return 3;
}
// Leave every other item unchanged
return item;
});
}
(7)更新数组中的对象
通过.map遍历每个item,找到要修改的对象,复制这个对象并对副本进行修改,作为一个新的对象返回,最后map返回一个新的数组,需要筛选则使用.filter
function reducer(state, action) {
/*
State looks like:
state = [{id: 1,email: 'jen@reynholmindustries.com'},{id: 2,email: 'peter@initech.com'}
]Action contains the new info:action = {type: "UPDATE_EMAIL"payload: {userId: 2, // Peter's IDnewEmail: 'peter@construction.co'}
}
*/
//通过map返回的是一个新的数组
return state.map((item, index) => {
// Find the item with the matching id
if(item.id === action.payload.userId) {
// Return a new object 修改后,返回的是一个新对象
return {
…item, // copy the existing item 复制这个对象不需要修改的部分
email: action.payload.newEmail // replace the email addr
}
}
// Leave every other item unchanged
return item;
});
}
(8)在数组中间插入一个item
.splice函数将插入一个item,但会改变数组。可以先试用slice复制数组,再使用splice插入item,或者复制新item之前的元素,插入新item,再复制item之后的元素
function reducer(state, action) {
/*
State looks like:
state = [1, 2, 3, 5, 6];
*/
const newItem = 4;
// make a copy
const newState = state.slice();
// insert the new item at index 3
newState.splice(3, 0, newItem)
return newState;
/*
// You can also do it this way:
return [ // make a new array
…state.slice(0, 3), // copy the first 3 items unchanged
newItem, // insert the new item
…state.slice(3) // copy the rest, starting at index 3
];
*/
}
(9)按索引更新数组中的item
使用map找到这个item并返回新值
function reducer(state, action) {
/*
State looks like:
state = [1, 2, "X", 4];
*/
return state.map((item, index) => {
// Replace the item at index 2
if(index === 2) {
return 3;
}
// Leave every other item unchanged
return item;
});
}
(10)从数组中删除一个item
通过filter,传入每个item,返回一个只包含判断函数返回true的item的新数组
function reducer(state, action) {
/*
State looks like:
state = [1, 2, "X", 4];
*/
return state.filter((item, index) => {
// Remove item “X”
// alternatively: you could look for a specific index
if(item === “X”) {
return false;
}
// Every other item stays
return true;
});
}
相关文章:
React和Redux中的不变性
https://overreacted.io/zh-hans/a-complete-guide-to-useeffect/ 一、不变性和副作用 1.不变:不断创造新值来替换旧值 2.不变性规则: (1)当给定相同的输入时,纯函数必须始终返回相同的值 (2࿰…...
NPM 常用命令(一)
目录 1、npm 1.1 简介 1.2 依赖性 1.3 安装方式 2、npm access 2.1 命令描述 2.2 详情 3、npm adduser 3.1 描述 4、npm audit 4.1 简介 4.2 审计签名 4.3 操作示例 4.4 配置 audit-level dry-run force json package-lock-only omit foreground-scripts …...
【ES6】Promise推荐用法
一般来说,不要在then()方法里面定义 Reject 状态的回调函数(即then的第二个参数),总是使用catch方法。 // bad promise.then(function(data) {// success}, function(err) {// error});// good promise.then(function(data) { //…...
【JavaScript】版本判断
用于客户端和服务端进行版本更新判断使用,如有BUG,还望指出 效果 console.log(isAllowUpdate(1,2.0.0), // trueisAllowUpdate(2.0,2.0.0), // falseisAllowUpdate(2.0,2.0.1), // trueisAllowUpdate(2.1.1,2.1.2), // trueisAllowUpdate(2.1.3,2.1.2),…...
Nano编辑器安装使用指南
关于nano Nano编辑器是一个命令行文本编辑器,具有简单易用的界面和一些基本功能。 Nano小巧友好,提供许多额外的特性,例如交互式的查找和替换、定位到指定的行列、自动缩进、特性切换、国际化支持、文件名标记完成等。 Nano是为了代替闭源的…...
Java版电子招投标管理系统源码-电子招投标认证服务平台-权威认证
项目说明 随着公司的快速发展,企业人员和经营规模不断壮大,公司对内部招采管理的提升提出了更高的要求。在企业里建立一个公平、公开、公正的采购环境,最大限度控制采购成本至关重要。符合国家电子招投标法律法规及相关规范,以及…...
Java String类(1)
String类的重要性 我们之前在C语言中已经涉及到字符串了,但是在C语言中要表示字符串只能使用字符数组或者字符指针,可以使用标准库提供的字符串系列函数完成大部分操作,但是这种将数据和操作数据的方法分离开的方式不符合面向对象的思想&…...
渗透测试漏洞原理之---【CSRF跨站请求伪造】
文章目录 1、CSRF概述1.1、基本原理1.1.1、基本概念1.1.2、关键点1.1.3、目标 1.2、CSRF场景1.2.1、银行支付转账1.2.2构造虚假网站1.2.3、场景建模 1.3、CSRF类别1.3.1、POST方式 1.4、CSRF验证1.4.1、CSRF PoC Generator 2、CSRF攻防2.1、CSRF实战2.1.1、与XSS 漏洞相结合 2.…...
带量采购药品数据查询集采分析平台(建议收藏!)
药品集采常态化下对不同中标企业的影响不尽相同,对于市场份额较大且拥有多款重要药品的大型企业来说,集采能够保持其市场份额,尽管被集采的药品可能会面临销售下降的局面,但该企业还有其他产品可以填补,整体影响不大。…...
概念解析 | 无线感知的新篇章:异构网络感知的原理与挑战
注1:本文系“概念解析”系列之一,致力于简洁清晰地解释、辨析复杂而专业的概念。本次辨析的概念是:异构网络感知。 无线感知的新篇章:异构网络感知的原理与挑战 Interference Management in HetNets 在当今的无线通信领域,我们面临着一个重大的挑战:如何在有限的频谱资源…...
【大数据模型】让chatgpt为开发增速(开发专用提示词)
汝之观览,吾之幸也!本文主要聊聊怎样才能更好的使用提示词,给开发提速,大大缩减我们的开发时间,比如在开发中使用生成表结构脚本的提示词,生成代码的提示词等等。 一、准备 本文主要根据Claude进行演示&am…...
读书笔记-《ON JAVA 中文版》-摘要23[第二十章 泛型-2]
文章目录 第二十章 泛型5. 泛型擦除5.1 泛型擦除5.2 迁移兼容性5.3 擦除的问题5.4 边界处的动作 6. 补偿擦除7. 边界8. 通配符8.1 通配符8.2 逆变 9. 问题10. 动态类型安全11. 泛型异常 第二十章 泛型 普通的类和方法只能使用特定的类型:基本数据类型或类类型。如果…...
【爬虫】5.6 Selenium等待HTML元素
目录 任务目标 创建Ajax网站 创建服务器程序 Selenium XX 等待 1. Selenium强制等待 2. Selenium隐性等待 3. Selenium循环等待 4. Selenium显示等待 等待方法 任务目标 在浏览器加载网页的过程中,网页的有些元素时常会有延迟的现象,在HTML元素…...
0102阿里云配置3台ECS服务器-大数据学习
文章目录 1 前言1 配置VPC和子网2 创建安全组3 创建云服务器ECS3.1 规划配置3.2 配置 4 xshell连接服务器5 配置基础环境5.1 主机名映射5.2 ssh免密登录5.3 jdk 6 问题集6.1 Permission denied (publickey,gssapi-keyex,gssapi-with-mic).6.2 用tar解压文件出现错误Not found i…...
android 输入法demo
背景: 一个简单的android输入法demo,支持输入png、gif,jpeg、webp等格式。 此示例演示如何编写一个应用程序,该应用程序接受使用 Commit Content API 从键盘发送的丰富内容(例如图像)。 用户通常希望通过表…...
【经验分享】Markdown中如何显示空格和回车
Markdown中如何显示空格和回车 空格 利用html中的空格实体引用: eg: 这是一些 额外的空格。回车: 方法一:在你想要回车的地方连续按两次回车键 方法二:使用<br>标签 eg: 我想显示<br>…...
深入篇【C++】set和map(multiset/multimap)特性总结与使用
深入篇【C】set和map(multiset/multimap)特性总结与使用 一.set/multiset总结二.map/multiset总结三.set/map应用 一.set/multiset总结 set是按照一定次序存储元素的容器在set中,元素的value也标识它(value就是key,类型为T),并且每…...
OpenAI推出ChatGPT企业版,提供更高安全和隐私保障
🦉 AI新闻 🚀 OpenAI推出ChatGPT企业版,提供更高安全和隐私保障 摘要:OpenAI发布了面向企业用户的ChatGPT企业版,用户可以无限制地访问强大的GPT-4模型,进行更深入的数据分析,并且拥有完全控制…...
Linux虚拟机磁盘扩容
Linux虚拟机磁盘扩容 问题起源 在使用linux系统开发时遇到文件无法创建的问题,根据提示发现是磁盘空间不足。 使用df -h查看具体磁盘使用情况。 针对这个问题,有两种解决方案: 使用du -sh ./*可以查看当前工作目录下各文件的占用空间大小…...
【Go 基础篇】Go语言结构体实例的创建详解
在Go语言中,结构体是一种强大的数据类型,允许我们定义自己的复杂数据结构。通过结构体,我们可以将不同类型的数据字段组合成一个单一的实例,从而更好地组织和管理数据。然而,在创建结构体实例时,有一些注意…...
突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
工程地质软件市场:发展现状、趋势与策略建议
一、引言 在工程建设领域,准确把握地质条件是确保项目顺利推进和安全运营的关键。工程地质软件作为处理、分析、模拟和展示工程地质数据的重要工具,正发挥着日益重要的作用。它凭借强大的数据处理能力、三维建模功能、空间分析工具和可视化展示手段&…...
《通信之道——从微积分到 5G》读书总结
第1章 绪 论 1.1 这是一本什么样的书 通信技术,说到底就是数学。 那些最基础、最本质的部分。 1.2 什么是通信 通信 发送方 接收方 承载信息的信号 解调出其中承载的信息 信息在发送方那里被加工成信号(调制) 把信息从信号中抽取出来&am…...
论文浅尝 | 基于判别指令微调生成式大语言模型的知识图谱补全方法(ISWC2024)
笔记整理:刘治强,浙江大学硕士生,研究方向为知识图谱表示学习,大语言模型 论文链接:http://arxiv.org/abs/2407.16127 发表会议:ISWC 2024 1. 动机 传统的知识图谱补全(KGC)模型通过…...
现代密码学 | 椭圆曲线密码学—附py代码
Elliptic Curve Cryptography 椭圆曲线密码学(ECC)是一种基于有限域上椭圆曲线数学特性的公钥加密技术。其核心原理涉及椭圆曲线的代数性质、离散对数问题以及有限域上的运算。 椭圆曲线密码学是多种数字签名算法的基础,例如椭圆曲线数字签…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...
【Java学习笔记】BigInteger 和 BigDecimal 类
BigInteger 和 BigDecimal 类 二者共有的常见方法 方法功能add加subtract减multiply乘divide除 注意点:传参类型必须是类对象 一、BigInteger 1. 作用:适合保存比较大的整型数 2. 使用说明 创建BigInteger对象 传入字符串 3. 代码示例 import j…...
解决:Android studio 编译后报错\app\src\main\cpp\CMakeLists.txt‘ to exist
现象: android studio报错: [CXX1409] D:\GitLab\xxxxx\app.cxx\Debug\3f3w4y1i\arm64-v8a\android_gradle_build.json : expected buildFiles file ‘D:\GitLab\xxxxx\app\src\main\cpp\CMakeLists.txt’ to exist 解决: 不要动CMakeLists.…...
