• 首页
  • 归档
    • 时间线
    • 文章分类
    • 文章标签
  • 留言
  • 关于
  • 首页
    归档
    时间线
    文章分类
    文章标签
    留言
    关于
    VenDream’s Blog
    VenDream’s Blog
    智性孤独
  • 首页
  • 归档
    • 时间线
    • 文章分类
    • 文章标签
  • 留言
  • 关于
  • 首页
    归档
    时间线
    文章分类
    文章标签
    留言
    关于
    前端(3)
    音乐(2)
    react(2)
    notion(1)
    windows(1)
    字体(1)
    StableDiffusion(1)
    WebSocket(1)
    SSE(1)
    AI(1)
    RSC(1)
    Avicii(1)
    心情随想(1)音乐分享(2)技术分享(1)生命在于折腾(1)阅读笔记(4)
    © 2021-2025 VenDream.

    Powered by NotionNext 4.7.0

    React Escape Hatches 阅读笔记
    React Escape Hatches 阅读笔记
    阅读笔记|2024-2-21|最后更新: 2024-3-28
    前端
    react
    type
    status
    date
    Feb 21, 2024 03:27 AM
    slug
    summary
    tags
    category
    icon
    password
    原文:https://react.dev/learn/escape-hatches

    总结

    在技术文档中,"Escape Hatches"(逃生舱口)通常指的是在某个系统、框架或编程语言中提供的一种机制,允许开发者绕过或者规遍系统的某些限制、规定或者标准。这个术语强调了提供一种应对特殊情况或者解决问题的手段,即使这种手段可能破坏了原本的规则或者设计。
     
    Referencing values with refs
    当在组件中想“记住”一些信息,但不想这些信息触发组件的re-render时,可以使用ref
    常用于存储:
    • 定时器 ID
    • DOM元素
    • 其他不影响组件渲染结果的对象
     
    💡
    You can access the current value of that ref through the ref.current property. This value is intentionally mutable, meaning you can both read and write to it. It’s like a secret pocket of your component that React doesn’t track.
    notion image
     
    ref可以指向任意类型的值,改变ref的值不会触发组件re-render。
     
    ref与state的区别
    refs
    state
    定义:useRef(initialValue) 返回:{ current: initialValue }
    定义:useState(initialValue) 返回:[value, setValue]
    值改变时不触发组件重渲染
    值改变时触发组件重渲染
    Mutable值可变,可直接修改
    Immutable值不可变,需要通过setter修改值
    渲染过程中不要读写current值,不可控
    随时可读,但只是某一轮渲染的快照值
     
    Manipulating the DOM with refs
    使用ref指向一个DOM节点以进行交互操作
     
    针对动态生成的复数DOM维护其ref,使用ref callback
     
    函数组件暴露内部的DOM,使用forwardRef包裹
     
    如果想自定义暴露特定方法或属性,使用useImperativeHandle
     
    React在commit phase设置ref.current的值;更新DOM之前,ref.current设置为null,更新DOM后,会立刻设置为对应的DOM引用。
    一般而言,只会在事件处理逻辑中访问ref。
     
    如果希望state更新后马上刷新DOM,使用flushSync包裹
     
    使用ref操作DOM的最佳实践
    • 脱离React进行独立的逻辑控制,如:聚焦/失焦、滚动、几何信息测量或调用浏览器API等
    • 避免操作由React管理的DOM,二者会发生冲突
     
    Synchronizing with Effects
    React组件中包含两种类型的逻辑
    • Rendering Code渲染逻辑,纯函数计算,返回JSX
    • Event handlers事件处理逻辑,处理用户交互,会产生副作用
     
    💡
    Effects let you specify side effects that are caused by rendering itself, rather than by a particular event. Effects run at the end of a commit after the screen updates. Effects are typically used to “step out” of your React code and synchronize with some external system.
     
    实现一个Effect应该包含3个步骤
    • 创建副作用声明useEffect
    • 确认副作用依赖dependencies
      • React使用Object.is进行依赖比较
      • 依赖无法自主选择,由副作用内的代码决定,按lint提示进行补充
      • 具备稳定一致性stable identity的值不需要添加为依赖,如:ref
    • 按需添加副作用cleanup
     
    ⚠️
    在Strice Mode启用的开发环境中,所有组件都会重新挂载一次,目的是帮助发现副作用中未处理的cleanup逻辑。
     
    当useEffect在开发环境执行两次时,不同场景的不同处理
    场景
    添加cleanup
    具体处理
    非React组件、控件
    是
    调用对应的API进行清理操作
    事件订阅
    是
    取消订阅
    动效触发
    是
    重置样式
    数据获取
    是
    中断请求
    数据上报
    否
    不处理,开发环境不上报
    应用初始化
    否
    只执行一次,移到组件外
    购买请求
    否
    不属于副作用,移到event handler中
     
    💡
    Each render has its own Effects. You can think of useEffect as “attaching” a piece of behavior to the render output.
     
    每次副作用执行时,获取到的state和props都是那一轮render的快照值,并非实时值。
     
    You Might Not Need an Effect
    副作用不可滥用,要根据实际情况合理使用,一般来说有两种反模式:
    • 副作用不用于进行数据转换,数据转换应该在组件顶层进行,在副作用中进行会产生不必要的冗余计算
    • 副作用不用于处理用户交互,副作用执行时,无法追踪事件触发源信息
     
    具体的场景及最佳实践见原文,注意与event handler的区别。
     
    Lifecycle of Reactive Effects
    每一个Effect都代表着一个独立的与外部系统同步的过程,不要把所有副作用逻辑都写在同一个Effect里,应互相独立维护。
     
    💡
    All values inside the component (including props, state, and variables in your component’s body) are reactive. Any reactive value can change on a re-render, so you need to include reactive values as Effect’s dependencies.
     
    总结
    • 组件会经历挂载、更新和卸载三个阶段
    • 每个副作用的的生命周期与其所在上下文有关,与组件生命周期无关
    • 每个副作用描述了一个可以开始与结束的同步过程
    • 状态值reactive values应该触发副作用重新执行
    • 副作用依赖由其内部代码决定,并有linter提示,不用尝试忽略或禁用提示,而应该重新思考副作用的实现是否存在问题
     
    Separating Events from Effects
    认清Effect与Event handlers的区别
    • Event handlers run in response to specific interactions
    • Logic inside event handlers is not reactive
     
    • Effects run whenever synchronization is needed
    • Logic inside Effects is reactive
     
    要把non-reactive的逻辑从副作用中抽离出来。
    对于抽离出来的non-reactive逻辑,可以放到Effect Events中,效果类似之前rfc的useEvent。
    现阶段可以使用ahooks的useMemoizedFn作为workaround。
     
    Removing Effect Dependencies
    如果要移除副作用依赖,只需要确保依赖为non-reactive value即可。
    不要尝试欺骗react以规避linter错误提示,会存在潜在的且难以发现的bug。
     
    可以思考以下几个问题以确定是否可以移除对应的副作用依赖
    • 是否可以处理为event handler ?
    • 是否可以拆分为多个独立的副作用 ?
    • 是否读取了state以计算下个state ?
    • 是否包含了non-reactive的逻辑(参考上节)?
     
    总结
    • 副作用依赖应该与其代码实现符合(不多也不少)
    • 发现副作用依赖不太正常时,应该检查的是副作用的实现
    • 不要忽略副作用依赖的linter提示
    • 移除副作用依赖时,确保它是non-reactive的
    • 如果副作用内的部分逻辑只响应用户交互,应该移到event handler中
    • 副作用的粒度应该尽量小,每个副作用只处理一项同步外部系统的逻辑
    • 如果要根据state计算nextState,使用updater function
    • 如果想要读取state的最新值且不想被其触发副作用重新执行,把它放到Effect Event中
    • 相同的对象和函数字面量实际上并不相等,作为依赖时仍会触发副作用重新执行
    • 对象和函数不应该作为副作用依赖,考虑移到组件外部或副作用内部
     
    Reusing Logic with Custom Hooks
    总结
    • 自定义hooks可以在组件间共享逻辑
    • 自定义hooks的命名应该满足useXxx的形式
    • 自定义hooks共享的是状态化的逻辑,而非状态值本身(每个hooks运行时都拥有独立的状态值)
    • 自定义hooks间可以传递reactive的参数
    • 组件重新渲染时,副作用都会重新执行
    • 自定义hooks的代码应该pure
    • 自定义hooks的event handlers参数应该使用Effect Events包裹
    • 没必要创造类似useMount的自定义hooks,正常使用useEffect实现即可
    • 如何划定自定义hooks的范围和边界非常灵活,根据实际情况自行决定即可
    How Stable Diffusion works 阅读笔记windows 字体美化
    Loading...