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

  1. 对象扩展运算符…:创建包含与另一个对象或数组完全相同的内容的新对象或数组

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;

});
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/61612.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何利用Python代码优雅的进行文件下载

如何利用Python代码优雅的进行文件下载 一、什么是wget?二、使用wget.exe客户端进行文件下载三、使用Python脚本进行文件下载 欢迎学习交流! 邮箱: z…1…6.com 网站: https://zephyrhours.github.io/ 一、什么是wget?…

JavaWeb_LeadNews_Day9-Redis实现用户行为

JavaWeb_LeadNews_Day9-Redis实现用户行为 网关配置点赞阅读不喜欢关注收藏文章详情-行为数据回显来源Gitee 网关配置 nacos: leadnews-app-gateway # 用户行为微服务 - id: leadnews-behavioruri: lb://leadnews-behaviorpredicates:- Path/behavior/**filters:- StripPrefi…

yolov3

yolov1 传统的算法 最主要的是先猜很多候选框,然后使用特征工程来提取特征(特征向量),最后使用传统的机器学习工具进行训练。然而复杂的过程可能会导致引入大量的噪声,丢失很多信息。 从传统的可以总结出目标检测可以分为两个阶…

Java 读取TIFF JPEG GIF PNG PDF

Java 读取TIFF JPEG GIF PNG PDF 本文解决方法基于开源 tesseract 下载适合自己系统版本的tesseract ,官网链接:https://digi.bib.uni-mannheim.de/tesseract/ 2. 下载之后安装,安装的时候选择选择语言包,我选择了中文和英文 3.…

提高Python并发性能 - asyncio/aiohttp介绍

在进行大规模数据采集时,如何提高Python爬虫的并发性能是一个关键问题。本文将向您介绍使用asyncio和aiohttp库实现异步网络请求的方法,并通过具体结果和结论展示它们对于优化爬虫效率所带来的效果。 1. 什么是异步编程? 异步编程是一种非阻…

vue使用打印组件print-js

项目场景&#xff1a; 由于甲方要求&#xff0c;项目需要打印二维码标签&#xff0c;故开发此功能 开发流程 安装包&#xff1a;npm install print-js --saveprint-js的使用 <template><div id"print" ref"print" ><p>打印内容<p&…

树的介绍(C语言版)

前言 在数据结构中树是一种很重要的数据结构&#xff0c;很多其他的数据结构和算法都是通过树衍生出来的&#xff0c;比如&#xff1a;堆&#xff0c;AVL树&#xff0c;红黑色等本质上都是一棵树&#xff0c;他们只是树的一种特殊结构&#xff0c;还有其他比如linux系统的文件系…

CocosCreator3.8研究笔记(二)windows环境 VS Code 编辑器的配置

一、设置文件显示和搜索过滤步骤 为了提高搜索效率以及文件列表中隐藏不需要显示的文件&#xff0c; VS Code 需要设置排除目录用于过滤。 比如 cocoscreator 中&#xff0c;编辑器运行时会自动生成一些目录&#xff1a;build、temp、library&#xff0c; 所以应该在搜索中排除…

代码随想录算法训练营第五十一天 | 309.最佳买卖股票时机含冷冻期,714.买卖股票的最佳时机含手续费

代码随想录算法训练营第五十一天 | 309.最佳买卖股票时机含冷冻期&#xff0c;714.买卖股票的最佳时机含手续费 309.最佳买卖股票时机含冷冻期714.买卖股票的最佳时机含手续费 309.最佳买卖股票时机含冷冻期 题目链接 视频讲解 给定一个整数数组prices&#xff0c;其中第 pric…

Mysql-索引查询相关

一、单表查询 1.1 二级索引为null 不论是普通的二级索引&#xff0c;还是唯一二级索引&#xff0c;它们的索引列对包含 NULL 值的数量并不限制&#xff0c;所以我们采用key IS NULL 这种形式的搜索条件最多只能使用 ref 的访问方法&#xff0c;而不是 const 的访问方法 1.2 c…

深入探索PHP编程:连接数据库的完整指南

深入探索PHP编程&#xff1a;连接数据库的完整指南 在现代Web开发中&#xff0c;与数据库进行交互是不可或缺的一部分。PHP作为一种强大的服务器端编程语言&#xff0c;提供了丰富的工具来连接和操作各种数据库系统。本篇教程将带您了解如何在PHP中连接数据库&#xff0c;执行…

并发编程的故事——并发之共享模型

并发之共享模型 文章目录 并发之共享模型一、多线程带来的共享问题二、解决方案三、方法中的synchronize四、变量的线程安全分析五、习题六、Monitor七、synchronize优化八、wait和notify九、sleep和wait十、park和unpark十一、重新理解线程状态十二、多把锁十三、ReentrantLoc…

Window11-Ubuntu双系统安装

一、制作Ubuntu系统盘 1.下载Ubuntu镜像源 阿里云开源镜像站&#xff1a;https://mirrors.aliyun.com/ubuntu-releases/ 清华大学开源软件镜像网站&#xff1a;https://mirrors.tuna.tsinghua.edu.cn/ubuntu-releases/ 选择想要的版本下载&#xff0c;我用的是20.04版本。 2…

关于类和接口

类和接口的区别&#xff0c;去除语法层面&#xff0c;谈谈编程层面的意义。 设计原则SOLID&#xff1a; S&#xff1a;单一职责(SRP)&#xff0c;Single Responsibility Principle O&#xff1a;开-闭原则(OCP)&#xff0c;Open-Closed Principle L&#xff1a;里氏替换(LSP)&…

Facebook登录SDK

一、Facebook SDK接入 官方文档&#xff1a;https://developers.facebook.com/docs/facebook-login/android 按照流程填写完成 1、选择新建应用 如果已经创建了应用就点【搜索你的应用】&#xff0c;忽略2、3步骤 2、选择【允许用户用自己的Facebook账户登录】 3、填写应用…

Qt应用开发(基础篇)——消息对话框 QMessageBox

一、前言 QMessageBox类继承于QDialog&#xff0c;是一个模式对话框&#xff0c;常用于通知用户或向用户提出问题并接收答案。 对话框QDialog QMessageBox消息框主要由四部分组成&#xff0c;一个主要文本text&#xff0c;用于提醒用户注意某种情况;一个信息文本informativeTex…

Redis数据结构应用场景及原理分析

目录 一、Redis介绍 二、应用场景 2.1 String应用场景 2.2 Hash应用场景 2.3 List应用场景 2.4 Set应用场景 2.5 Zset应用场景 一、Redis介绍 单线程多路复用底层数据结构&#xff1a;全局哈希表&#xff08;key-value&#xff09; 二、应用场景 2.1 String应用…

VBA技术资料MF50:VBA_在Excel中突出显示前3个值

【分享成果&#xff0c;随喜正能量】人受到尊重&#xff0c;不是因为权钱&#xff0c;而是他骨子里透出的&#xff0c;正直与善良。。 我给VBA的定义&#xff1a;VBA是个人小型自动化处理的有效工具。利用好了&#xff0c;可以大大提高自己的工作效率&#xff0c;而且可以提高…

ChatGPT 总结数据分析的所有知识点

ChatGPT功能非常多,特别是对某个行业,某个方向,某个技术进行总结那是相当专业的。 如下图。 直接用一个指令便总结出来数据分析当中的所有知识点内容。 AIGC ChatGPT ,BI商业智能, 可视化Tableau, PowerBI, FineReport, 数据库Mysql Oracle, Office, Python ,ETL Ex…

day01-ES6新特性以及ReactJS入门

课程介绍 ES6新特性ReactJS入门学习 1、ES6 新特性 1.2、let 和 const 命令 var 之前&#xff0c;我们写js定义变量的时候&#xff0c;只有一个关键字&#xff1a; var var 有一个问题&#xff0c;变量作用域的问题&#xff0c;作用域不可控&#xff0c;就是定义的变量有时会…