异步陷阱
function Index() {
const [count, setCount] = useState(0)
function add(){
setCount( count + 1 )
console.log(count); // 0
}
return (
<div>
<span>{count}</span>
<button @click=()=>{ add() }> + </button>
</div>
)
}
点击一次按钮,发现页面是更新了,但是console还是上一次的值
【解决方法】:
function Index() {
const [count, setCount] = useState(0)
function add(){
new Promise((resolve) => {
setCount((count) => {
resolve(count + 1)
return count + 1
})
}).then((res) => {
// 下一步操作
console.log(res)
})
}
return (
<div>
<span>{count}</span>
<button onClick={add}> ++ </button>
</div>
)
}
合并陷阱,只执行最后一个
function Index() {
const [count, setCount] = useState(0)
function add(){
setCount( count + 1 )
setCount( count + 2 )
setCount( count + 3 ) // 只执行这个
}
return (
<div>
<span>{count}</span>
<button onClick={add}> ++ </button>
</div>
)
}
此时 只执行了 最后一个 setCount , 导致数据部分逻辑未执行
如果出现这种 判断条件多次 操作 useState 怎么解决
function add(){
let num = count;
if(...) { num += 1; }
if(...) { num += 2; }
if(...) { num += 3; }
setCount( num );
}
那就不写多个setCount
再看个例子:
function Index() {
const [count, setCount] = useState(100);
function add(){
// 合并
setCount( count + 1 )
setCount( count + 1 )
console.log(1, count) // 100
// 传入函数,不会合并
setCount( count => count + 1 )
setCount( count => count + 3 )
console.log(2, count) // 100
// 点击一次后 count显示为105
}
return (
<div>
<span>{count}</span>
<button onClick={() => add() } > + </button>
</div>
)
}
过期闭包
function Index() {
const [count, setCount] = useState(0)
useEffect(()=>{
setInterval(() => { console.log(`Count: ${count}`) }, 1000)
}, [])
return (
<div>
<span>{count}</span>
<button onClick=()=>{ setCount(count+1) }> + </button>
</div>
)
}
默认就会运行 每隔1s打印0
点击按钮,count有更新,但是console一直是0
说明此时的 useEffect 中的 count ,还是取的 过期的值
react特点,每次更新都会重新执行这个函数,每次就+1, 是另外一个函数了,不是原来这个函数
但是setInterval的count永远是第一个函数里面的,形成了闭包
【解决方法】:
需要,添加依赖项 count ,
并且每次更新,添加计时器,结束改变计时器
function Index() {
const [count, setCount] = useState(0);
useEffect(()=>{
const time = setInterval(() => { console.log(`Count: ${count}`) }, 1000)
return () => { clearInterval(time) } // 关键 清除上一次的setInterval
}, [count])
return (
<div>
<span>{count}</span>
<button @click=()=>{ setCount(count+1) }> + </button>
</div>
)
}
useCallback 本来拿来优化性能,当依赖变化不用重新注册该函数
使用不当 也会出现一定的问题
获取父组件的值,不是最新
function Parent() {
let [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count+1)}> +1 </button>
// 子组件
<Child count={count} />
</div>
)
}
function Child(props){
let log = useCallback(() => { console.log(props.count) }, [])
return (
<div>
count: {props.count}
<button onClick={() => log()}> 打印 </button>
</div>
)
}
此时我们在 父组件点击 增加按钮
子组件的 count 发生改变 ,我们在点击打印按钮,发现count 一直是0
说明useCallback 依赖为【】数组,取到count 已经过期了
【解决方法】
方法1 :等于没有优化 (依赖更新,useCallback重写一次)
let log = useCallback(() => { console.log(props.count) }, [props.count])
方法2 :将获取 count 的方法 创建到父组件,子组件调用父组件方法
function Parent() {
let [count, setCount] = useState(0);
let log = useCallback(() => { console.log(count) }, [])
return (
<div>
<button onClick={() => setCount(count+1)}> +1 </button>
// 子组件
<Child count={count} log={log} />
</div>
)
}
function Child(props){
return (
<div>
count: {props.count}
<button onClick={() => props.log()}> 打印 </button>
</div>
)
}