【React hooks】关于useCallback带来的闭包问题实践方案
作者:互联网
问题描述
// 举个栗子,我用hooks 写了这么一个组件
let Test = () => {
/** Search base infos */
const [searchID, setSearchID] = useState(0)
/** Search info action */
const onSearchInfos = useCallback(() => {
let fetchUrl = '/api/getSearchInfos'
let fetchParams = { searchID }
fetch(fetchUrl, {
method: 'POST',
body: JSON.stringify(fetchParams)
}).then(res => res.json()
).then(res => {
console.log(res)
})
}, [])
return (
<>
<button onClick={() => {setSearchID(searchID + 1)}} >button1</button>
<button onClick={() => {onSearchInfos()}}>button2</button>
</>
)
}
export default Test
上述写了一个很简单的伪代码功能,大致就是,点击button1按钮,searchID的值加1,点击button2发送一个请求。
开始描述问题:当我们点击了四次button1,把searchID的值更改到了4,然后点击button2,会发现,发送出去的请求,searhID的值是0。
问题分析
为什么会产生这种问题呢?因为我们使用useCallback将请求数据的回调方法onSearchInfos包裹了一层,并且第二参数我们传递了一个[],表示只在组件第一次创建的时候,这个回调函数被创建,从而去提升性能!
回顾下, 我上面说到了什么?
只在第一次组件创建的时候onSearchInfos被创建!第一次!
也就是说searchID拿到的值是第一次被创建的时候,传入的值,形成了一个闭包。
解决方案1
interface IRef {
current: any
}
let Test = () => {
/** Search base infos */
const [searchID, setSearchID] = useState(0)
/** 解决闭包问题 */
const fetchRef: IRef = useRef() // hooks为我们提供的一个通用容器,里面有一个current属性
fetchRef.current = { // 为current这个属性添加一个searchID,每当searchID状态变更的时候,Test都会进行重新渲染,从而current能拿到最新的值
searchID
}
/** Search info action */
const onSearchInfos = useCallback(() => {
let fetchUrl = '/api/getSearchInfos'
let fetchParams = { ...fetchRef.current } // 解构参数,这里拿到的是外层fetchRef的引用
fetch(fetchUrl, {
method: 'POST',
body: JSON.stringify(fetchParams)
}).then(res => res.json()
).then(res => {
console.log(res)
})
}, [])
return (
<>
<button onClick={() => {setSearchID(searchID + 1)}} >button1</button>
<button onClick={() => {onSearchInfos()}}>button2</button>
</>
)
}
export default Test
解决方案2
解决方案3
据我所知,目前至少还有两种解决方案,刚和隔壁大佬讨论完,还没来得及研究,周末研究一下,后续完善!
标签:闭包,searchID,hooks,onSearchInfos,useCallback,current,let,res,Test 来源: https://www.cnblogs.com/fe-linjin/p/11402288.html