从一个PR窥探React未来开发方式

开发 前端
都说Hooks是React的未来,但Hooks的最佳实践是什么呢?关于这块知识,官方文档一点儿都没提及。本篇就带给大家相关知识。

[[419828]]

大家好,我是卡颂。

都说Hooks是React的未来,但Hooks的最佳实践是什么呢?

关于这块知识,官方文档一点儿都没提及。

所以在实际项目中,常会出现类似下面的问题:

// ... 
useEffect(() => { 
  fetchData(a, b).then
    // ... 
  ) 
}, [a, b]) 
//... 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.

useEffect依赖了a b两个状态,当其中任意一个变化后会执行fetchData请求数据。

当应用变得复杂,要追踪a、b何时变化变得越来越难。

假以时日接口调整,fetchData还需要状态c作为参数。那么追踪状态变化的难度又会进一步提高。

最终会导致:

  • 轻则无意义的fetchData多次调用
  • 重则逻辑出现难以追查的bug

有朋友会说:你可以封装自定义Hook啊。

这只是将问题隐藏的更深了......

如何解决这个问题

以上问题的本质原因是:「副作用」实在太多,可以被当作「副作用」的东西也实在太多。这导致useEffect被滥用。

所以,要解决滥用问题,就需要为不同类型「副作用」提供官方解决方案。

这样,具体问题有了具体解决方案,才不会useEffect一把梭。

从一个PR看到变化

最近React有个很不起眼的PR[1]:

大体意思是:

在之前,当你在一个已经卸载的组件(unmounted)中调用setState会触发一个warning,这个PR将移除这个warning。

举个例子,以下代码在组件mount时注册handleChange:

useEffect(() => { 
  function handleChange() { 
     setState(store.getState()) 
  } 
  store.subscribe(handleChange) 
   
  return () => store.unsubscribe(handleChange) 
}, []) 
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.

如果你忘记写这行解绑代码:

return () => store.unsubscribe(handleChange) 
  • 1.

那么组件卸载后handleChange也可能被调用,进而调用setState。

这是潜在的内存泄漏。

在之前的React中,这种行为会报warning。

那为什么要移除这种行为下的warning呢?

PR的背后

一方面,这个warning有一定概率误判,比如「点击按钮提交表单」:

async function handleSubmit() { 
  setPending(true
  await post('/someapi'
  setPending(false

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.

点击按钮后调用setPending触发loading图标显示,接着发起post请求。

有可能请求返回前组件就卸载了,此时会调用:

setPending(false
  • 1.

并不会有内存泄漏风险,但是会报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>; 

  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.

 以上例子中,调用fetchDetail会发起数据请求。

Details组件调用resource.read直接消费数据即可。

如果数据还未返回,视图会渲染最近的Suspense的fallback(即<h1>Loading...</h1>)。

总结

「副作用」是多种多样的,以前没得选,只能用useEffect。

随着React18的稳定,面对不同「副作用」场景,会有更明确的解决方案。

届时,可能才最终迎来Hooks真香的时代......

 

责任编辑:姜华 来源: 魔术师卡颂
相关推荐

2021-10-12 08:34:23

React组件前端

2013-03-06 09:58:39

开发方式软件开发程序员

2015-09-22 09:30:28

2023-03-07 15:08:57

2009-11-23 09:27:00

PayPal支付接口

2014-03-14 14:04:29

AlloyDesign前端开发

2022-08-02 07:57:54

RAC故障运维

2010-12-01 09:04:59

PHP开发

2018-03-14 19:39:31

数据库Oracle临时表

2024-06-05 08:40:53

2021-06-24 09:53:05

前端架构开源

2015-08-06 17:15:28

2015-11-12 13:47:53

Firefox OSAPPFirefox

2010-02-06 14:52:15

ibmdw敏捷测试

2021-04-19 10:47:11

NettyDemoI

2020-10-20 14:01:16

HTTP

2025-02-19 18:00:00

神经网络模型AI

2023-06-07 08:25:41

2023-07-14 07:23:21

ReactuseEffect

2021-04-26 14:02:37

AMD串流硬件
点赞
收藏

51CTO技术栈公众号