博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
react之setState解析
阅读量:4290 次
发布时间:2019-05-27

本文共 3694 字,大约阅读时间需要 12 分钟。

在react开发过程中,state是组件一个重要的属性,对state的管理也尤为重要,这里记录一下踩坑经历

修改state正确方式

对于修改组件state正确的方式如下:

// 错误this.state.title = 'React';// 正确this.setState({title: 'React'});

有两个比较重要的点,一是对state的修改是异步,二是对多个相邻的state的修改可能会合并到一起一次执行。代码举例:

异步执行

class Clock extends React.Component {
constructor(props) { super(props); this.state = { num: 1 }; } handleClick() { this.setState((prevState, props) => ({ num: prevState.num + 1 })); console.info(this.state.num); } render() { return (

Hello, world!

It is {
this.state.num}.

); }}ReactDOM.render(
, document.getElementById("root"));

结果在ui显示每一次加1之后的结果,而console打印的总是上一次ui的值,也就可以确定state并没有立即执行,而是异步去执行的。我们可以通过添加一个回调函数到第二个参数,让state更新完成之后来执行该回调,代码如下:

handleClick() {    this.setState({      num : this.state.num + 1    });  }

此时ui上显示的数值与console打印的会是一致。另一种情况,如果对state的修改依赖state和prop,那么由于异步的原因就会产生很多异常情况,我们可以可以传入包含两个参数的函数到第一个参数来解决,代码如下:

handleClick() {    this.setState((prevState, props) => ({      num: prevState.num + 1    }),() => console.info(this.state.num));  }

第一个参数prevState表示前一次的state,后一个参数表示当前状态组件的prop值,显示的让该操作同步执行

批量单次执行

对于多次相邻的state修改操作的执行会被合并在一起执行,代码如下:

handleClick() {    this.setState({      num : this.state.num + 1    },() => console.info(this.state.num));    this.setState({      num : this.state.num + 1    },() => console.info(this.state.num));    this.setState({      num : this.state.num + 1    },() => console.info(this.state.num));  }

最终数值每次只会加1,我们可以看作是以下代码的执行:

Object.assign(  previousState,  {
num : this.state.num + 1}, {
num : this.state.num + 1})

因此,被合并之后最终只会保留一个更新。解决方法和上述解决异步的方式类似:

handleClick() {    this.setState((prevState,props) => ({      num : prevState.num + 1    }),() => console.info(this.state.num));    this.setState((prevState,props) => ({      num : prevState.num + 1    }),() => console.info(this.state.num));    this.setState((prevState,props) => ({      num : prevState.num + 1    }),() => console.info(this.state.num));  }

结果是我们期望的每次加3,但是需要注意的是,console打印的只会是每次加3之后的数值,并不会是每次加1的结果

State与Immutable

React官方建议把State当作是不可变对象,一方面是如果直接修改this.state,组件并不会重新render;另一方面State中包含的所有状态都应该是不可变对象。当State中的某个状态发生变化,我们应该重新创建这个状态对象,而不是直接修改原来的状态。那么,当状态发生变化时,如何创建新的状态呢?根据状态的类型,可以分成三种情况:

  1. 状态的类型是不可变类型(数字,字符串,布尔值,null, undefined)

    这种情况最简单,因为状态是不可变类型,直接给要修改的状态赋一个新值即可。如要修改count(数字类型)、title(字符串类型)、success(布尔类型)三个状态:

    this.setState({count: 1,title: 'Redux',success: true})
  2. 状态的类型是数组

    如有一个数组类型的状态books,当向books中增加一本书时,使用数组的concat方法或ES6的数组扩展语法(spread syntax):

    // 方法一:将state先赋值给另外的变量,然后使用concat创建新数组var books = this.state.books; this.setState({books: books.concat(['React Guide']);})// 方法二:使用preState、concat创建新数组this.setState(preState => ({books: preState.books.concat(['React Guide']);}))// 方法三:ES6 spread syntaxthis.setState(preState => ({books: [...preState.books, 'React Guide'];}))

    当从books中截取部分元素作为新状态时,使用数组的slice方法:

    // 方法一:将state先赋值给另外的变量,然后使用slice创建新数组var books = this.state.books; this.setState({books: books.slice(1,3);})// 方法二:使用preState、slice创建新数组this.setState(preState => ({books: preState.books.slice(1,3);}))

    注意不要使用push、pop、shift、unshift、splice等方法修改数组类型的状态,因为这些方法都是在原数组的基础上修改,而concat、slice、filter会返回一个新的数组。

  3. 状态的类型是普通对象(不包含字符串、数组)

    3.1 使用ES6 的Object.assgin方法

    // 方法一:将state先赋值给另外的变量,然后使用Object.assign创建新对象var owner = this.state.owner;this.setState({owner: Object.assign({}, owner, {name: 'Jason'});})// 方法二:使用preState、Object.assign创建新对象this.setState(preState => ({owner: Object.assign({}, preState.owner, {name: 'Jason'});}))

    3.2 使用对象扩展语法

    // 方法一:将state先赋值给另外的变量,然后使用对象扩展语法创建新对象var owner = this.state.owner;this.setState({owner: {...owner, name: 'Jason'};})// 方法二:使用preState、对象扩展语法创建新对象this.setState(preState => ({owner: {...preState.owner, name: 'Jason'};}))

参考:

转载地址:http://vergi.baihongyu.com/

你可能感兴趣的文章
菜鸟带你Hook技术实战
查看>>
BAT面试题集锦——Java基础(一)
查看>>
BAT面试题集锦——Java基础(二)
查看>>
Retrofit原理解析最简洁的思路
查看>>
Okhttp的源码解读
查看>>
【Android P】 JobScheduler服务源码解析(二) ——框架解析
查看>>
【Android P】 JobScheduler服务源码解析(三)—— 使用Job需要注意的点
查看>>
string和wstring相互转换
查看>>
c++读取utf8等不同编码文件
查看>>
STL中的vector
查看>>
C++中的map
查看>>
Python小时钟
查看>>
C语言清空getchar缓冲区
查看>>
python中的全局变量
查看>>
python的decode和encode
查看>>
c++词法分析器
查看>>
python中的is、==和cmp()
查看>>
python Tkinter的image不能显示的问题
查看>>
python 中的相互import问题
查看>>
linux 使用锐捷认证上网
查看>>