react常见错误 a year ago
setState数据不同步
现在我们有这样一个demo,当点击button时,我们期望count以4递增
可是当我们点击按钮后:
count
并没有像我们预期的那样增加
这是因为所有的count
还是上一次的count
当点击点1次时,count
初始化为0,上面的add相当于:
setCount(0 + 1)
setCount(0 + 1)
setCount(0 + 1)
setCount(0 + 1)
当点击点2次时,上一次的count
变成了1,上面的add相当于:
setCount(1 + 1)
setCount(1 + 1)
setCount(1 + 1)
setCount(1 + 1)
那么如何解决state不同步的问题呢?
答案是用回调函数, 用上一次的state更新下一次的state
我们更新add方法再来尝试一下:
setCount(previous => previous + 1)
setCount(previous => previous + 1)
setCount(previous => previous + 1)
setCount(previous => previous + 1)
setState: 普通值vs object
来看一个demo:
import { useState } from 'react'
type User = {
name: string;
age: number;
sex: string;
}
function App() {
console.log("component is rendering...")
const [num, setNum] = useState<number>(0)
const [user, setUser] = useState<User>({
name: 'scott',
age: 18,
sex: ''
})
const changeNum = () => {
setNum(0)
}
const changeUser = () => {
setUser({
name: 'scott',
age: 18,
sex: ''
})
}
console.log("user", user)
return (
<>
<button onClick={changeUser}>change user</button>
<button onClick={changeNum}>change num</button>
<div>number:{num}</div>
<div>
<ul>
<li>name:{user.name}</li>
<li>email:{user.age}</li>
<li>address: {user.sex}</li>
</ul>
</div>
</>
)
}
export default App
我们来分别点击 change num
和 change user
按钮:
分析:
num
值不变:当我们点击change num
时,由于set的value值没有改变,所以组件就没有重新渲染。user
set的值和初始值一样,按理说应该没变,但是奇怪的是每次都重新渲染了
到底是什么原因呢?
这就是js传值:普通值和对象的区别
来看看下面的演示 你就明白了
传递普通值是value值的比较,传递arry object的时候,是地址的比较
所以在setvalue的时候如果值是object那么组件会一直重新render
useEffect的依赖也是如此,将依赖转化为普通值可以大大提高性能
useEffect(()=>{
//do sth
},[user.age])
setState更新object的正确姿势
当state为object时,更新value的正确方式是先copy再赋值,原因是地址变了, 之前的值无法保留
来看看下面的demo:
import React, { useState } from 'react'
type User = {
name: string;
age: number;
sex: string;
}
function App() {
console.log("component is rendering...")
const [user, setUser] = useState<User>({
name: 'scott',
age: 18,
sex: ''
})
const nameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser({
...user,
name: e.target.value,
})
}
console.log("user", user)
return (
<>
<input type="text" onChange={nameChange} value={user.name} />
<div>
<ul>
<li>name:{user.name}</li>
<li>email:{user.age}</li>
<li>address: {user.sex}</li>
</ul>
</div>
</>
)
}
export default App
当然我们可以进一步优化,写成下面这种方式更完美 😋
const nameChange = (e: React.ChangeEvent<HTMLInputElement>) => {
setUser(prev => ({
...prev,
name: e.target.value,
}))
}
清理Event Listener
1, 如果不清理
import { useEffect, useState } from 'react'
function App() {
const [count, setCount] = useState<number>(0)
useEffect(() => {
setInterval(() => {
console.log("interval function is running...")
setCount(count + 1)
}, 1000)
}, [count])
return (
<>
{count}
</>
)
}
export default App
刷新浏览器,我们来看看输出:
可以看到前几秒输出还正常 越往后页面刷新都感觉有点吃力了 为什么呢?看下控制台的输出 - 异常夸张,它并不是1s打印一次,而是1s 几千次甚至后面数万次
所以清理Event Listener非常有必要
2, 来看看清理后
import { useEffect, useState } from 'react'
function App() {
const [count, setCount] = useState<number>(0)
useEffect(() => {
const i = setInterval(() => {
console.log("interval function is running...")
setCount(count + 1)
}, 1000)
return () => {
//清理工作
clearInterval(i)
}
}, [count])
return (
<>
{count}
</>
)
}
export default App
刷新浏览器,我们来看看输出:
可以看到console的次数和页面显示的此时是一致的
- 上一篇: react技巧总结之表单form处理
- 下一篇: react icon 推荐