大家好,我是卡颂。
都说 Hooks
是React
的将来,但 Hooks
的最佳实际是什么呢?
对于这块常识,官网文档一点儿都没提及。
所以在理论我的项目中,常会呈现相似上面的问题:
// ...
useEffect(() => {fetchData(a, b).then(// ...)
}, [a, b])
//...
useEffect
依赖了 a b
两个状态,当其中任意一个变动后会执行 fetchData
申请数据。
当利用变得复杂,要追踪 a
、b
何时变动变得越来越难。
假以时日接口调整,fetchData
还须要状态 c
作为参数。那么追踪状态变动的难度又会进一步提高。
最终会导致:
- 轻则无意义的
fetchData
屡次调用 - 重则逻辑呈现难以追究的
bug
有敌人会说:你能够封装 自定义 Hook
啊。
这只是将问题暗藏的更深了 ……
如何解决这个问题
以上问题的实质起因是:副作用 切实太多,能够被当作 副作用 的货色也切实太多。这导致 useEffect
被滥用。
所以,要解决滥用问题,就须要为不同类型 副作用 提供官网解决方案。
这样,具体问题有了具体解决方案,才不会 useEffect
一把梭。
从一个 PR 看到变动
最近 React
有个很不起眼的 PR:
大体意思是:
在之前,当你在一个曾经卸载的组件(unmounted
)中调用 setState
会触发一个 warning
,这个PR
将移除这个warning
。
举个例子,以下代码在组件 mount
时注册handleChange
:
useEffect(() => {function handleChange() {setState(store.getState())
}
store.subscribe(handleChange)
return () => store.unsubscribe(handleChange)
}, [])
如果你遗记写这行解绑代码:
return () => store.unsubscribe(handleChange)
那么组件卸载后 handleChange
也可能被调用,进而调用setState
。
这是潜在的内存透露。
在之前的 React
中,这种行为会报warning
。
那为什么要移除这种行为下的 warning
呢?
PR 的背地
一方面,这个 warning
有肯定概率误判,比方 点击按钮提交表单:
async function handleSubmit() {setPending(true)
await post('/someapi')
setPending(false)
}
点击按钮后调用 setPending
触发 loading
图标显示,接着发动 post
申请。
有可能申请返回前组件就卸载了,此时会调用:
setPending(false)
并不会有内存透露危险,然而会报warning
。
不过 warning
移除还有另一个更实质的起因:
在第一个示例中,咱们在 useEffect
中调用store.subscribe
,这种行为能够归类为:
在组件中订阅内部源
什么是 内部源 呢?
任何 变动与否不受 React 管制的源 都是 内部源。
比方:
- 各种第三方状态治理库
- 心愿
location.hash
变动触发组件更新
将来所有这类行为都会收敛到 useMutableSource
这个 Hook
中。
更多例子
再比方,对于 I/O
操作(比方 申请数据 )这种大家都会放在useEffect
中的逻辑,将来应用 resource
联合 Suspense
可能是更好的抉择:
const resource = fetchDetail();
function Page() {
return (<Suspense fallback={<h1>Loading...</h1>}>
<Details/>
</Suspense>
);
}
function Details() {const data = resource.read();
return <h1>{data.name}</h1>;
}
以上例子中,调用 fetchDetail
会发动数据申请。
Details
组件调用 resource.read
间接生产数据即可。
如果数据还未返回,视图会渲染最近的 Suspense
的fallback
(即<h1>Loading...</h1>
)。
总结
副作用 是多种多样的,以前没得选,只能用useEffect
。
随着 React18
的稳固,面对不同 副作用 场景,会有更明确的解决方案。
届时,可能才最终迎来 Hooks
真香的时代 ……