React Hooks中设置state的同函数内访问最新state返回默认值问题
问题原因
这个问题是典型的React 闭包捕获 问题:
useCallback的作用是缓存函数实例,只有当它的依赖数组里的变量发生变化时才会生成新的函数实例。你当前的代码没有给useCallback传入依赖数组,所以函数只会在组件首次渲染时生成一次,捕获到的selectedRows永远是首次渲染时的初始空数组,后续state更新也不会刷新该函数内的state引用。- 除此之外你的代码还有两处错误:
includes是数组方法,调用需要用圆括号()而非方括号[];给setSelected传值时额外包裹了一层数组,会导致最终state变成二维数组;如果你的需求是多选,原来的else分支逻辑也会清空之前的选中项。
解决方案
推荐两种可行方案,第二种性能更优:
方案1:补全useCallback的依赖数组
把selectedRows加入useCallback的依赖项,每次selectedRows变化时自动生成新的函数实例,就能拿到最新的state值,同时修正代码里的其他错误:
const [selectedRows, setSelected] = useState([]) const handleRowClick = useCallback((id) => { if(selectedRows.includes(id)) { const arr = selectedRows.filter((item) => item !== id) setSelected(arr) } else { // 多选保留之前选中项,单选直接写setSelected([id])即可 setSelected([...selectedRows, id]) } // 补全依赖 }, [selectedRows])
方案2:使用setState的函数式更新(更推荐)
setSelected支持传入函数作为参数,函数的第一个参数就是最新的state值,所有逻辑可以直接在这个回调内完成,不需要依赖外部的selectedRows,也不需要给useCallback加依赖,避免不必要的函数刷新和组件重渲染:
const [selectedRows, setSelected] = useState([]) const handleRowClick = useCallback((id) => { setSelected(prevSelectedRows => { if(prevSelectedRows.includes(id)) { return prevSelectedRows.filter(item => item !== id) } else { // 多选保留之前选中项,单选直接返回 [id] 即可 return [...prevSelectedRows, id] } }) // 不需要加selectedRows依赖 }, [])
内容的提问来源于stack exchange,提问作者Sai Krishna
相关产品推荐
相关产品推荐

