写了两个react hook,大家帮忙品品
详情
事情是这样的,某天我在参与一个react-native项目开发时,碰到了一个问题:useState更新状态后获取不到最新的状态值,useMemo同样也有这个问题。我赶紧上网搜索答案,折腾了很久,最后终于在官方文档中找到了这么一段描述:

翻译过来,就是说想要使用新状态的话,可以提前用一个变量去保存新状态。这样useState的问题就解决了,但是useMemo呢,useMemo要怎么搞?在经过一阵头脑风暴后,我有了那么一点点思路,我决定自己再封装两个hook来解决这个问题。说干就干,经过一段时间地不停试错和调试后,终于还是被我搞出来了,我欣喜若狂,马上拿给同事看,于是有了下面的对话:
同事:你自己试了吗? 我:试了几次。 同事:感觉怎么样? 我:我修改了一部分用法,但是又保留了一部分,我觉得保留一部分写法习惯,你才知道你在用的是什么hook。 同事:你是有意把它保留的吗? 我:是我在写的过程中, 留下了一部分。 同事:是故意的还是不小心的? 我:是故意的。
于是同事试了一下
import { useEffect } from 'react'
import { useSyncState, useSyncMemo } from 'react-sync-state-hook'
export default MyComponent = () => {
const [ state, setState ] = useSyncState(0)
const [ state2, setState2 ] = useSyncState(() => 100)
const memo = useSyncMemo(() => {
return state.current + state2.current
}, [state, state2])
useEffect(() =>{
setState(1)
console.log(state.state) // 0
console.log(state.current) // 1
console.log(memo.state) // 100
console.log(memo.current) // 101
}, [])
return (
<>
<div>{ state.state }</div>
<div>{ memo.state }</div>
</>
)
}
我赶紧解释道:现在确实要比原先多写一个.state去调用状态,但这其实是不得已而为之的,主要是为了让useSyncMemo()能更方便地执行监听依赖和同步计算而做出的让步。现在即使是在复杂的循环和递归中,只需调用一次setState(),就能让current自动更新成最新的状态,memo也会随着依赖项的current更新而更新,像这样:
import { useEffect } from 'react'
import { useSyncState, useSyncMemo } from 'react-sync-state-hook'
export default MyComponent = () => {
const [ state, setState ] = useSyncState(0)
const memo = useSyncMemo(() => {
return state.current + 1
}, [state])
useEffect(() =>{
for(let i = 0; i < 5; i++){
setState(i)
console.log(state.state) // 0 0 0 0 0
console.log(state.current) // 0 1 2 3 4
console.log(memo.state) // 0 0 0 0 0
console.log(memo.current) // 1 2 3 4 5
}
}, [])
return (
<>
<div>{ state.state }</div>
<div>{ memo.state }</div>
</>
)
}
我:我们也可以只对current做修改,最后再调用setState()修改状态的值,来避免因频繁修改状态值而增加重新渲染的次数,这样可以带来一点性能上的提升,像这样:
import { useEffect } from 'react'
import { useSyncState, useSyncMemo } from 'react-sync-state-hook'
export default MyComponent = () => {
const [ state1, setState1 ] = useSyncState(0)
const [ state2, setState2 ] = useSyncState(0)
let request1 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
state1.current = 1
resolve()
}, 500)
})
}
let request2 = () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
state2.current = 2
resolve()
}, 1000)
})
}
useEffect(() =>{
Promise.all([request1(), request2()]).then(res => {
setState1(state1.current)
setState2(state2.current)
// 这里虽然setState了两次,但是react会合并所有setState,只发起一次重新渲染。
// 如果是在request中直接setState则会重新渲染两次
})
}, [])
return (
<>
<div>{ state1.state }</div>
<div>{ state2.state }</div>
</>
)
}
我:useSyncState()和setState()的参数形式也和原来的一样,可以传值也可以传一个函数,用法与原来的hook几乎是一样的,可以自己试试。
最终在我苦口婆心地劝说下,同事终于妥协了。
总结
useSyncState()和useSyncMemo()维持了与原来hook一样的写法,但在用法上略有不同,是通过state.state调用状态以及state.current调用当前状态值,有需要的小伙伴可以试试看react-sync-state-hook。
转载自:https://juejin.cn/post/7209504489010921530