React Hooks场景下能否直接调用组件函数?存在哪些潜在风险?
结论先行
在使用了Hooks的React场景下,直接调用组件函数的写法是官方不允许的,会触发多种不可预期的错误和逻辑异常。两种写法的底层逻辑完全不同:使用<Counter/>时React会为组件创建独立的fiber节点,分配专属的Hooks存储队列,和父组件完全隔离;而直接执行Counter()相当于把Counter的代码平铺到父组件的渲染上下文执行,所有Hooks都会挂载到父组件的Hooks队列上,会引发以下问题:
具体问题(聚焦Hooks场景)
直接违反Hooks调用规则,容易触发运行时报错
React明确要求Hooks只能在函数组件顶层、或者自定义Hook中调用,且调用顺序必须固定。如果Counter()被条件渲染逻辑包裹(比如{ show && Counter() }),相当于Counter内部的Hooks是有条件执行的,会直接破坏父组件Hooks的调用顺序,轻则出现状态错位(比如A组件的状态跑到B组件上),重则直接抛出「Rendered more hooks than during the previous render」的运行时错误,整个组件树渲染失败。完全失去组件状态和生命周期的隔离性
标准写法下多个<Counter/>的状态完全独立,各自的state修改只会触发自身重渲染。但直接调用Counter()时,Counter内部的所有状态都会挂载到父组件上:渲染多个Counter()会出现状态共享、相互覆盖的问题;Counter内部调用setCount会触发整个父组件重渲染,而非仅更新Counter对应的视图。无法使用React组件生态的相关能力
直接调用的组件无法接收ref、无法用React.memo做渲染优化、无法被Context Provider做局部作用域隔离,同时React DevTools中不会展示该组件的节点,状态调试难度会大幅提升。
注:如果组件本身没有使用任何Hooks、是纯无状态的展示组件,直接调用不会触发运行时错误,但依然不符合React规范,不建议使用,避免后续组件迭代增加Hooks后出现不可预期的问题。
内容的提问来源于stack exchange,提问作者gmoniava

