React Hook中useState更新延迟
方法一:去掉useEffect的第二个参数
例如以下代码 错误实例
const[zoom, setZoom] = useState(0); useEffect(() = >{ document.getElementById('workspace-content').addEventListener('mousewheel', scrollFunc); },[]); function scrollFunc(e) { setZoom(zoom + 5) }
会出现zoom永远等于 0+5, 而不是所谓的5, 10 ,15 为什么会这样呢? 因为useEffect执行时,会创建一个闭包,在每次监听到mousewheel运行时 闭包内部保存了zoom的初始化值 每次调用的时候都是取的初始化值0 所有会一直为0+5
怎么解决呢?
解决方案: 去掉useEffect中的空数组即可
const[zoom, setZoom] = useState(0); useEffect(() = >{ document.getElementById('workspace-content').addEventListener('mousewheel', scrollFunc); return () = >document.getElementById('workspace-content').removeEventListener("mousewheel", scrollFunc); // 记得解绑事件 }); function scrollFunc(e) { setZoom(zoom + 5) }
方法二:将改变函数移入useEffect并将第二个参数设置为state
依旧用上面的例子
解决方法:正确示例
useEffect(() = >{ document.getElementById('workspace-content').addEventListener('mousewheel', scrollFunc); return () = >document.getElementById('workspace-content').removeEventListener("mousewheel", scrollFunc); function scrollFunc(e) { setZoom(zoom + 5) e.preventDefault() } },[zoom]);
方法三:使用Ref, 在useEffect内监听此ref, 并实时跟useState同步
例如下面的代码 错误示例
const [currentIndex, setCurrentIndex] = useState(0) const handleLeft = () => { setCurrentIndex(currentIndex+ 1) console.log(currentIndex) }
初始化currentIndex为0 每次执行handleLeft函 数是让currentIndex加1, 之后立即获取currentIndex的值发现 第一次执行currentIndex = 0
第二次执行currentIndex = 1 每次都跟实际情况差一个 查阅资料发现useState必须要执行完react整个生命周期才会获取最新值
解决方案:用useRef中转,并实时同步给useState
const [currentIndex, setCurrentIndex] = useState(0) const currentIndexRef = useRef(0); const handleLeft = () => { currentIndexRef.current += 1 console.log(currentIndexRef.current) } useEffect(()=>{ setCurrentIndex(currentIndexRef.current) },[currentIndexRef.current])
React Hook useState连续更新对象问题
react hook 的useState更新是异步的,所以在连续更新出发useState时会出现问题
eg:
import React, {useState} from 'react'; export default () => { const [obj, setObj] = useState({ a: 1, b: 2 }) const changeObj = () => { // 连续触发2次setObj(实际项目不会这样写,我这样写只是为了模拟连续触发2次setObj带来的问题) setObj({...obj, a: 2}) setObj({...obj, b: 3}) } return (// 此时页面上显示的值为 {a: 1, b: 3}, 出现该问题的原因是因为useState是异步的,在第二次触发setObj时,obj还是没更新a之前的obj,所以出现该结果 {JSON.stringify(obj)}) }
解决此情况的方式,就是在第二次触发时使用setObj((data) => ({...data, b: 3})) 这样的方式
import React, {useState} from 'react'; export default () => { const [obj, setObj] = useState({ a: 1, b: 2 }) const changeObj = () => { // 连续触发2次setObj(实际项目不会这样写,为了模拟情况) setObj({...obj, a: 2}) // data标识存储的是更新a后的对象,用这样的方式可以解决连续触发2次带来的问题 setObj((data) => ({...data, b: 3})) } return (// 此时页面上显示的值为 {a: 2, b: 3} {JSON.stringify(obj)}) }
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。