意见箱
恒创运营部门将仔细参阅您的意见和建议,必要时将通过预留邮箱与您保持联络。感谢您的支持!
意见/建议
提交建议

前端-重学react_个人文章

来源:恒创科技 编辑:恒创科技编辑部
2022-10-09 09:54:23
重学 react简介

换工作后,从vuereact已经一年半了,代码写的不多,侥幸以为对react有点熟悉了。但看了「beta.reactjs.org」后依然有被震撼到,对react,自己之前的理解,原来一直都错的离谱。

今天,小编就讲讲理解react组件的心路历程,以及清空自身固有认知,尝试为未来的使用,构建一个不容易但简单的心智模型:

构建react组件的基本心智模型构建useEffect的基本心智模型自我反思
申明:本文是个人的官方文档「beta.reactjs.org」读后感,并不保证源码分析级别的严谨性,未来依然会不断调整,推荐大家有时间自己去读一遍文档。「原文档略啰嗦,但整体还是流畅易读的」。
构建react组件的基本心智模型

众所周知,react是围绕vdomdom diff设计的,更新fiber架构后,也没有改变。小编对react组件(为了简化,这里跳过已经不值一提的class component,指的都是函数式组件)的理解一直是有许多疑问的:


前端-重学react_个人文章

初见UI=f(state)简洁而优美的近乎「零」api公式,优雅,太优雅了!看起来以后一直可以这么优雅的写代码了?

image.png

如果没有类似immer等库的帮助,必须不厌其烦的手动展开ObjectArray等常见引用类型,以达到给react组件投喂不可变数据的效果,「优雅的背后果然总少不了负重前行的实现」。

再见已翻看过dan经典的博文「overreacted.io/zh-hans/algebraic-effects-for-the-rest-of-us」,读后让人感到释怀,react组件留给小编的疑惑,果然并非是不是纯函数?这么简单。

image.png

react组件是用「多次不断执行组件的关联函数」的方式,做到了以「同步代码的形式」实现「异步中断和恢复的」的效果(被称之为代数效应)。有类似async函数的功能,却没有async函数传染性的缺点,不是异步,胜似异步!

回眸文档后,认识到react组件也不仅是代数效应这么简单,而是fiber树位置fiber树diff结果紧密结合的产物。

image.png

即,react组件通过「多次执行」的方式:

实现了「零」api 抽象,每次执行都被传递到其并不优雅的内部体系中,小编目前认为,这个纯函数带上各种约束,其实是一个内置 DSL。实现了「纯」函数抽象,所以得手动保持不可变。实现了更多其他特殊能力抽象代数效应状态管理异步任务调度等实现了基于diff规则自动状态管理,要仔细考量状态是否还能保持
PS: 小编开始对用react来实现「一切皆组件的思想」产生了一丝丝怀疑,因为react组件已经是一个深度定制的系统的内置 DSL,要以一个基础单元的形式,再去支撑其他维度的抽象系统有点了,这点从react-router六大版本的变迁可以看出端倪。
构建useEffect的基本心智模型

小编对hooks的理解同样经历了几个阶段:

开始也是被优雅、简洁给惊艳,以至于对「不能在if中使用」等别扭的规则,感觉非常可以理解。这时候小编仅以为他是一个更聚合的组织代码的方式。

image.png

后来有人说hooks本质是一种reactive,深信了许久,于是小编去研究了很多reactive库,在遇见了solidjs之后感慨万千,vdom的路子跟十年前爆火的reactive思想比起来,在抽象程度、性能和包大小方面都没有什么优势,但是react已经无法走回头路了,最终小编的结论是,hooksreactive不是直接关系,不应强行关联。

image.png

react组件是通过不断重复执行以获得超能力特殊能力的。所以配合上hooks保存状态的特性,整个函数体内申明的、所有的自由变量自然而然的,都拥有了reactive的特性了。

无论是否是useState包裹的变量,还是props,甚至一句普通的const b = a + 1,也天然成为了reactive,可以解读为a + 1computed映射函数b的申明,所以不只是hooksreactive

最后,即然不是以reactive为目的设计,那么为啥useEffect要取这么一个名字呢?为啥dev阶段react非要「恶意」触发两次useEffect呢?

从新文档中小编获得了答案,useEffect本名其实应该是useImmutableReactiveAfterEveryRenderDangerEffect,解释为「用于不可变的、响应式的、危险的、react组件自身渲染后期的副作用」。小编取这样一个超级长的名字是契合官方,不鼓励多用、也防止大家滥用这个hooks

image.png

ImmutableReactive上面已经解释过了,AfterEveryRenderDangerEffect指的是组件被提交到渲染之后,可以自定义的行为,比如你想要组件一旦渲染后:

发送一个请求。上报一个日志。注册一个系统事件。

总之,只有在渲染后的这个时机内,需要一个「自动」处理「官方用词是同步」一下当前react组件和组件外部资源危险的副作用的机制的时候,才不得不使用。大部分时候,你需要的主动处理逻辑都应该放在event callback中,现在,是否觉得自己滥用了呢?

由于每个useEffect的功能、依赖的更新频率、设计目的都不相同,必须拆分大的useEffect单一功能的多个小useEffect,才能防止更多的混乱。而「恶意」触发两次useEffect,是为了凸显忘记设置cleanup返回函数的危险性。

one more thing还有一个隐藏特别深的陷阱不得不提。你是否经常遇到,因为要实现某些功能,不得不给他添加设计之初以外的依赖,否则lint 规则就又无法通过了

「lint 只会自动忽略组件外部的上下文变量、不可变的函数等,」手动忽略lint明显是一个走向失控的不负责的处理方式。那么,不打破设计意图还有哪些可控的解决办法呢?

image.png

把状态移出组件,或者移入useImmutableReactiveAfterEveryRenderDangerEffect内部。利用setState(v => ...)的方式传入函数,以去除依赖数组中的reactive变量。抽离一个non-reactive effectFn函数「最新的useEvent api正是来自于此」,由这个函数去上下文重新捕获reactive变量,也可以去除依赖数组中的reactive变量。「文档警告」non-reactive effectFn函数是useImmutableReactiveAfterEveryRenderDangerEffect独有的作用域泄漏补丁方案,也请不要滥用。只能由对应的useImmutableReactiveAfterEveryRenderDangerEffect在内部调用,也不许传递给其他的hooks!自我反思

本来还想写写re-render的心智模型,但是发现re-render的理论,其实业界聊得挺透彻,没啥新东西可说了,只是做的还不够好「共勉」。

小编发现以喷子的角色去吐槽FE的生态漏洞,收获的只有失落感,因为虽然意识到痛点和不足,却只能口嗨,无法去正确描述、正视并解决问题。这次读新文档,让人有一种解惑后的满足感,再感谢dan大佬用心写的文档,让小编重新认识了自己的无知

最后欢迎关注一波:
来源:公众号「textcraft」或者搜索「桃猿」

以上。

上一篇: 租用美国服务器:潜在的风险与应对策略。 下一篇: MongoDB 5.0 扩展开源文档数据库操作