引言
先提个问题:React中
this.setState({xxx:''})
与
this.state.xxx=''
有区别吗?
答案:有区别的。
this.state通常是用来
初始化state
的,this.setstate是用来
修改state
值的。
如果你初始化了state之后再使用this.state,之前的state会被覆盖掉,如果使用this.setState,只会替换掉相应的state值。
一、this.setState({})
-
this.setState({})会触发render方法,重新渲染界面。而this.state.xxx=’’ 不会重新加载UI。
-
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来替代set来替代push:
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著 杜伟、柴晓伟、涂曙光译