1.对于react内对state状态修改的性能优化
对于同一时间段相同事件的重复触发,正常情况下,react会进行性能优化,比如
state={
count:0
}
for(let i=0;i<100;i++){
this.setState({
count:this.state.count + 1
}
console.log(this.state.count) //输出100次0
}
这样的话只会输出一百次0,而count的值会变为99,这就是react自身的性能优化,将短时间内多次相同的事件合并在一起处理
但是!!!,如果代码这样写的话
state={
count:0
}
for(let i=0;i<100;i++){
this.setState({
count:++this.state.count
}
console.log(this.state.count) //1,2,3,...99
}
这样的话,输出的值从0开始到99结束,每循环一次都会输出一次,这样的代码是不存在合并的
2.对于类组件更改state的同步异步的问题
state={
count:0
}
//修改state的第一种方法,在setState的第一个参数写对象,一般来说是同步
increment=()=>{
this.setState({
count:++this.state.count
}}
console.log(this.state.count)
}
//修改state的第二种方法,在setState的第一个参数写回调函数,一般来说是异步
increment=()=>{
this.setState(({count}) =>{
return {
count:++this.state.count
}
})
console.log(this.state.count)
}
上面两种方法,需要去触发increment函数,在第一种方法里,输出的值和修改后的count保持同步更新,所以一般来说是同步的,而第二种里输出的值一般是上一次的count值,会比最新的修改的count值慢一次更新,所以一般是异步的,但是在第二种方法里也是可以获取最新的count,那就需要在this.setState的第二个参数写回调函数
this.setState(({count}) =>{
return {
count:++this.state.count
}
},() =>{
//这里可以获取最新的状态
console.log(this.state.count)
})
但是!!!,如果两个修改的方法不是前置++,而是如代码所示
state={
count:0
}
//修改state的第一种方法,在setState的第一个参数写对象,是异步
increment=()=>{
this.setState({
count:this.state.count +1
}}
console.log(this.state.count)
}
//修改state的第二种方法,在setState的第一个参数写回调函数,是异步
increment=()=>{
this.setState(({count}) =>{
return {
count:this.state.count +1
}
})
console.log(this.state.count)
}
上面的输出的值,都是最新修改count值的上一次值,也就是说比最新的慢一个,当然了,在this.setState的第二个参数写回调函数还是可以获取最新的count值。
与此相同的还有就是,不是对state内的值进行简单的加减,而是直接赋值的话,如代码所示
state={
url:'aaa'
}
//修改state的第一种方法,在setState的第一个参数写对象,是异步
increment=()=>{
this.setState({
url.'bbb'
}}
console.log(this.state.url) //aaa,如果触发两次就会输出bbb
}
//修改state的第二种方法,在setState的第一个参数写回调函数,是异步
increment=()=>{
this.setState(({url}) =>{
return {
url:'bbb'
}
})
console.log(this.state.url) //aaa,如果触发两次就会输出bbb
}
上面对state内的url进行修改,然后获取的url值依旧是aaa,而不是bbb,当然,state内的url确实是修改了,但是这里还有存在异步的问题,所以只能获取上一次的url
3.在类组件中的方法都要写成箭头函数的原因
export default class Hello extends Component {
state={
name:"iron"
}
//这里的函数要写成箭头函数,才不会影响里面this.setState的使用
hender=()=>{
this.setState({
name:"superstar"
})
}
render(){
return (
<div>
<button onClick={this.hander}>点击按钮</button>
</div>
)
}
}
为什么里面的函数就一定要写成箭头函数才不会影响,其实这个和原生js面向对象语法糖里的this指向类似,都是为了写在button标签内的this.hander中的this指向,在button里的this指向的是button,就相对于在原生面向对象的函数内再写鼠标移动事件,那么这个鼠标移动事件就要写成箭头函数才行,不然就会影响事件内的this指向,所以了解这个之后,react内的函数也可以不写成箭头函数,如下代码
export default class LayOut extends React.Component {
constructor(props){
super(props)
this.state={
name:"iron"
}
//在constructor里修改this指向
this.hander4 = this.hander4.bind(this)
}
hander1=()=>{
this.setState({
name:"superstar1"
})
}
hander2(){
this.setState({
name:"superstar2"
})
}
hander3(){
this.setState({
name:"superstar3"
})
}
hander4(){
this.setState({
name:"superstar4"
})
}
render(){
return (
<div>
//使用箭头函数
<button onClick={this.hander1}>点击按钮1</button><hr/>
//只要button标签不会影响this指向
<button onClick={()=>{this.hander2()}}>点击按钮2</button><hr/>
//直接修改this指向
<button onClick={this.hander3.bind(this)}>点击按钮3</button><hr/>
//在constructor里先修改好
<button onClick={this.hander4}>点击按钮4</button><hr/><hr/>
{this.state.name}
</div>
)
}
}
对啦,对于constructor和render里是不需要使用箭头函数也不会影响this指向的,因为这两个是react生命周期初始化阶段的钩子函数,当然了,使用了箭头函数也没关系,不影响
4.react里去使用数组方法的注意事项
export default class LayOut extends React.Component {
constructor(props){
super(props)
this.state={
arr:[1,2,3]
}
}
hander1=()=>{
let num = 5
//测试一:直接去修改状态内的arr,这样是可以的
this.state.arr.push(num)
console.log(this.state.arr)//[1,2,3,5],这样可以获取最新的值
//测试二:使用解构赋值,这样是可以的
this.setState({
arr:[num,... this.state.arr]
},()=>{
console.log(this.state.arr)//[1,2,3,5]
})
console.log(this.state.arr)//[1,2,3] 异步方法,无法立刻获取修改后的值
//测试三:将修改后的值赋值与状态内的arr,有问题
this.setState({
arr:this.state.arr.push(num)
},()=>{
console.log(this.state.arr)//4
})
//测试四:针对上面的问题,再次测试
const name = this.state.arr.push(num)
console.log(this.state.arr)//[1,2,3,5]
console.log(name) //4
}
render=()=>{
return (
<div>
<button onClick={this.hander1}>点击按钮1</button><hr/>
</div>
)
}
}
有以上代码可以看出,直接去修改组件的状态是可以的,但是不能将修改后的值再赋予状态内的值,这是因为数组push的返回值是改变后的数组长度
还有其他数组的使用方法可以参考该博主的博客
https://blog.youkuaiyun.com/hahahhahahahha123456/article/details/104922711
5.在react生命周期更新阶段过程
在react生命周期的更新阶段,他有5个钩子函数,正确的说,对于属性是5个钩子函数,对于状态state的更新只有4个钩子函数,具体的可以看我写的生命周期的博客,这里要说的是两者都有的shouldComponentUpdate(nextProps,nextState){}这个钩子函数,这个钩子函数是用来判断数据是否有变化的,如果数据没有变化,那就不进行数据的渲染,而一般采用浅比较,也就是直接比较会发生变化的属性或者状态,不可以比较nextProps和this.props或者nextState和this.state,因为都是对象,对象的地址不相同的,那么两者肯定不同,这就达不到我们需要的比较效果了。
值得注意的是
- nextState 和 this.state【新值】 是一样的【值】,所以要自己去设定 一个值进行比较,要注意异步的问题
- nextProps 和 this.props【旧值】
那么如何去设定一个值用于自己在状态改变的时候进行比较,我们需要在state里添加一个状态用于保存变化的状态的前一个值,但是我们又要注意,像如下代码
constructor(props){
super(props)
this.state={
count:0,
n:0
}
}
hander=()=>{
this.setState({
n:this.state.count + 1,
count:++this.state.count
})
}
对于n的修改,前置++是可以保持同步更新的,而后置加1是无法保持同步更新的,所以这样正好可以获取我们需要的count的前一个值,我们不可以n:this.state.count,因为直接赋值也是异步,这样我们会和count相差两个次的变化,会出现错误
6.更多神坑等待更新ing
以上都是个人见解,如有错误,欢迎指出