React中this.setState({xxx:''})与this.state.xxx='' 有区别吗?

简介: React中this.setState({xxx:''})与this.state.xxx='' 有区别吗?

引言

先提个问题:React中this.setState({xxx:''})this.state.xxx='' 有区别吗?

答案:有区别的。

this.state通常是用来初始化state的,this.setstate是用来修改state值的。

如果你初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。

一、this.setState({})

  1. this.setState({})会触发render方法,重新渲染界面。而this.state.xxx=’’ 不会重新加载UI。
  2. this.setState({})是异步的。

二、this.state.xxx=''

在什么场景会使用this.state.xxx呢?

我在写了两个button,点击button更新改变state的值,然后将state作为参数请求数据,自动刷新列表UI的时候,出现了问题。

例子:

constructor(){
  this.state={
  couponStatus : 0 ,
  }
}
render() {
        <SegmentedBar
            justifyItem='fixed'
            indicatorType='customWidth'
            indicatorLineColor='#f5e220'
            indicatorWidth={90}
            animated={false}
            onChange={(index) => {
              this.setState(
                {
                  couponStatus:index;
                }
              }
            }}
        >
}
复制代码

上面这段代码是无法达到预期效果的,为什么呢?因为setState,是异步的,且有一定延迟,这就导致了有时候后面列表加载数据已经完成了,state却还没有改变,导致的直接结果就是数据错乱。于是,我们把代码略微修改一下。

this.state.couponStatus = index;
//别忘了手动刷新列表UI
this.refs.couponListView.refresh();
复制代码

这样就完美的解决了。

三、不变性

从上述例子中可以看出,和this.props类似,可以把this.state当作只读属性。应当总是使用setState方法来更新组件UI的状态,而不应直接修改this.state。当this.setState()被调用时,React会更新界面。这是最常见的情况,但也有例外,比如可以使通过生命周期函数shouldComponentUpdate()返回false,从而避免界面更新。

而标题所讲的不变性,指不去修改对象,而是直接替换这个对象。

假如现在有一个有状态组件,来显示一家航空公司的机票:

import React,{Component} from 'react';
class Test extends Component{
    constructor(){
        super(...arguments)
        this.state={
            passengers:[
                'Simmon',
                'Taylor'
            ]
        }
    }
    render(){...}
}
复制代码

现在需要将一个新乘客添加到passengers数组中。如果不小心,就会无意中直接修改组件的state对象。例如:

let newPassengers = this.state.passengers;
//在js中,对象和数组都是以引用方式传递的,意味着此行代码并未创建数组的一个副本,
//只是创建了一个新引用,而引用指向的是当前组件的state中的那个数组。
//因此在下一个代码中使用push方法是直接在修改state。
newPassengers.push('Jay');
this.setState({
    passengers: newPassengers
})
复制代码

要在js中创建一个数组的实际副本,需要使用非侵入式数组方法,也就是说,使用那些会返回一个新数组,而非直接对原数组进行修改的方法。map、filter、concat、slice都是这种形式的非侵入式数组方法。

在js中,基于原来的对象生成新的对象还有其他一些方式,例如使用Object.assign。Object.assign具有兼容性问题,不过该问题可用Babel解决,此处不详述。

下面利用Array的concat方法来实现添加的功能:

let newPassengers = this.state.passengers.concat('Jay');
this.setState({
    passengers: newPassengers
})
复制代码

四、嵌套对象(浅拷贝和深拷贝)

1、深拷贝与浅拷贝的概念

如何区分深拷贝与浅拷贝?

简单点来说,就是假设B复制了A,当修改B时,看A是否会发生变化,如果A也跟着变了,说明这是浅拷贝;如果A没变,那就是深拷贝。

1.浅拷贝: 将原对象或原数组的引用直接赋给新对象,新数组,新对象/数组只是原对象的一个引用

2.深拷贝: 创建一个新的对象和数组,将原对象的各项属性的“值”(数组的所有元素)拷贝过来,是“值”而不是“引用”

为什么要使用深拷贝?

我们希望在改变新的数组(对象)的时候,不改变原数组(对象)

深拷贝的要求程度?

我们在使用深拷贝的时候,一定要弄清楚我们对深拷贝的要求程度:是仅“深”拷贝第一层级的对象属性或数组元素还是递归拷贝所有层级的对象属性和数组元素?

2、嵌套对象

在大多数情况下,数组的非侵入式方式和Object.assign已经可以完成我们想要的操作,但是如果state中包含嵌套对象或数组,那么情况就变得棘手。因为Js的特性:对象和数组都通过引用方式传递,并且数组的非侵入式方式和Object.assign都不会做深拷贝。在实践中,这意味着在你通过数组非侵入式方法和Object.assign所创建的新对象中所包含的嵌套对象和数组,仍然指向的是原对象中的嵌套对象和数组。

网络异常,图片无法展示
|

3、React不变性助手——update

update函数应用到普通的JS对象和数组之上,可将它们包装成不可变的对象:函数不会真正修改这些对象,而总是返回一个新的可变的对象。

官网:react-addons-update - npm

安装:npm i react-addons-update

导入:import update from 'react-addons-update'

说明:update函数接收两个参数,第一个参数是想要更新的对象和数组。第二个参数是一个对象,它描述了你想要在何处进行何种修改。

举例:

let student = {name:'Jonn',grades:['A','B','C']}
//要创建这个对象的一个修改grades后的副本,update函数的用法如下:
let newStudent = update(student,{grades:{$push:['A']}})
复制代码

对象{grades:{$push:['A']}}从左到右表明了update函数应当:

  • 定位到grades属性(修改应该应用在“何处”)
  • 将一个新值添加到数组中(应该应用到“何处”修改“)

如果想要完全修改整个数组,可使用命令set来替代set来替代setpush:

let newStudent = update(student,{grades:{$set:['A','A','B']}})
复制代码

对于对象中可以有多少层嵌套,并没有任何限制。适当时候可使用数组索引:

a={
    code:[
        {company:'GL',No:'9'},
        {company:'TM',No:'3'}
    ]
}
b=update(a,{
    code:{
        0:{$set:{company:'AZ',No:'5'}}
    }
})
复制代码

4、update的命令

命令 描述
$push 类似与Array的push函数,它向一个数组的尾部添加一个或多个元素。
$unshift 类似于Array的unshift函数,它在一个数组的头部添加一个或多个元素。
$splice 类似于Array的splice函数,它通过从数组中移除元素且/或向数组中添加元素,来修改一个数组的内容。和Array.splice主要的语法区别是你需要提供一个元素为数组的数组来作为参数,作为参数的数组中的每一个数组包含了要对数组进行splice操作的参数。
$set 完整地替换掉整个目标。
$merge 将给定对象的键合并到目标对象中。
$apply 将当前的值传给一个函数,在函数中对传入的值进行修改,然后使用函数的返回值作为结果。

代码举例:

let a = [1,2,3]
let b = update(a,{$push:[4]})
// => [1,2,3,4]
let a = [1,2,3]
let b = update(a,{$unshift:[0]})
// => [0,1,2,3]
let a = [1,2,'a']
let b = update(a,{$splice:[[2,1,3,4]]})
// => [1,2,3,4]
let ob = {a:5,b:3}
let newOb = update(ob,{$merge:{b:6,c:7}})
// => {a:5,b:6,c:7}
let ob = {a:5,b:3}
let newOb = update(ob,{b:{$apply:(value)=>value*2}});
// => {a:5,b:6}
复制代码

参考链接:

1.react native中this.setState({xxx:''})与this.state.xxx='' 有区别吗?

2.一篇文章彻底搞懂浅拷贝和深拷贝

3.书籍《React开发实战》——Cssio de Sousa Antonio著  杜伟、柴晓伟、涂曙光译



相关文章
|
5月前
|
XML JavaScript 前端开发
Vue和React有什么区别
【8月更文挑战第28天】Vue和React有什么区别
696 0
|
2月前
|
JavaScript 前端开发 开发者
React和Vue有什么区别?
React 和 Vue 都有各自的优势和特点,开发者可以根据项目的需求、团队的技术背景以及个人的喜好来选择使用。无论是 React 还是 Vue,它们都在不断发展和完善,为前端开发提供了强大的支持。
115 2
|
2月前
|
JavaScript 前端开发 算法
React 框架和 Vue 框架的区别是什么?
React框架和Vue框架都是目前非常流行的前端JavaScript框架,它们在很多方面存在区别
|
2月前
|
JavaScript 前端开发 算法
在性能上,React和Vue有什么区别
【10月更文挑战第23天】在性能上,React和Vue有什么区别
22 1
|
3月前
|
前端开发 JavaScript UED
react-router 里的 Link 标签和 a 标签有什么区别
`react-router` 中的 `Link` 标签与 HTML 中的 `a` 标签的主要区别在于:`Link` 是专门为 React 应用设计的,用于实现客户端路由导航,不会触发页面的重新加载,而 `a` 标签则会刷新整个页面。使用 `Link` 可以提升应用的性能和用户体验。
|
3月前
|
前端开发 开发者 UED
React 18 与之前版本的主要区别
【10月更文挑战第12天】 总的来说,React 18 的这些区别体现了 React 团队对于提升应用性能、用户体验和开发效率的持续努力。开发者需要适应这些变化,充分利用新特性来构建更出色的应用。同时,随着技术的不断发展,React 也将继续演进,为开发者带来更多的创新和便利。
|
2月前
|
开发框架 JavaScript 前端开发
React和Vue之间的区别是什么
【10月更文挑战第23天】React和Vue之间的区别是什么
18 0
|
2月前
|
JavaScript 前端开发 Android开发
React和Vue之间的区别是什么
【10月更文挑战第23天】React和Vue之间的区别是什么
32 0
|
4月前
|
前端开发 JavaScript 开发者
React 和 Vue.js 框架的区别是什么?
React 和 Vue.js 框架的区别是什么?
|
3月前
|
存储 前端开发 JavaScript
React useState 和 useRef 的区别
本文介绍了 React 中 `useState` 和 `useRef` 这两个重要 Hook 的区别和使用场景。`useState` 用于管理状态并在状态变化时重新渲染组件,适用于表单输入、显示/隐藏组件、动态样式等场景。`useRef` 则用于在渲染之间保持可变值而不触发重新渲染,适用于访问 DOM 元素、存储定时器 ID 等场景。文章还提供了具体的代码示例,帮助读者更好地理解和应用这两个 Hook。
63 0