跳到主要内容

认识

2023年02月22日
柏拉文
越努力,越幸运

一、认识


函数组件创建Ref,可以用 hooks 中的 useRef 来达到同样的效果

二、语法


export default function Index(){
const currentDom = React.useRef(null)
React.useEffect(()=>{
console.log( currentDom.current ) // div
},[])
return <div ref={ currentDom } >ref对象模式获取元素或组件</div>
}

三、类型注解


3.1 元素

const divRef: RefObject<HTMLDivAreaElement> = useRef(null);

const inputRef: RefObject<HTMLInputAreaElement> = useRef(null);

3.2 对象

const objectRef: RefObject<ObjectType> = useRef(null);

四、总结沉淀


4.1 useRef 实现原理?

useRef 用于在函数组件中存储数据, 可以随意更新 ref.current.xx 的值, 并且进行同步更新, 但是 useRef 的更新不会触发组件渲染。

Mount 阶段: 调用 mountRef, 创建一个 Hook 对象, 存储在 当前处理的 fiber.memoizedState 中。Hook 对象中也有一个 memoizedState, 用于存储 { current: xx }。存储完成后, 返回 { current: xx }

Update 阶段: 从当前的 Fiber 中取出 Hook 链表, 依次循环遍历执行, 执行到 useRef 链时, 执行 updateRef, 直接返回 Hook.memoizedState 就好了。

4.2 React 中 refs 是干嘛用的?

React 中, refs 主要用于获取对 DOM 元素或 React 实例的直接引用,从而可以进行一些非声明式的操作。具体来说,refs 的用途包括:

  1. 访问 DOM 节点: 当需要直接操作底层 DOM(例如,设置焦点、测量尺寸、触发动画或滚动位置)时,可以使用 refs 获取对应的 DOM 元素引用。 与第三方库集成

  2. 访问子组件实例: ref 可以结合 forward, 子组件通过 useImperativeHandle 自定义由 ref 暴露出来的句柄, 供父组件使用。

  3. 存储不需要引起渲染的数据: 在函数组件中, 还可以用于存储任何不需要引起重新渲染的可变数据(例如,存放定时器 ID、缓存值等)。 避免不必要的渲染

4.3 useState 与 useRef 有什么区别?

useRef 存储、返回的结构为 { current: xx }, 更新是同步的, 更新 ref.current 不会触发组件重新渲染。

useSate: 存储状态值, 返回的结构为 [状态值, 更新状态函数], 返回的第二个元素为 dispatchAction, 封装了调度更新的逻辑, 里面的主要逻辑为: 确定该更新所属的优先级(即 Lane), 并生成一个 Update 对象, 其中包含了此次更新的 action(可能是新状态值或用于计算状态的函数), 基于 eagerState 策略, 通过 Object.is 比较最新结果与之前结果, 如果状态发生变化, 将该 Update 插入到对应 Hook 的更新队列 Hook.UpdateQueue 中, 调用 scheduleUpdateOnFiber,标记当前 Fiber 需要更新,并由调度器安排后续渲染任务。useState 更新是异步的, 并且会合并多次更新, React 会在合适的时候重新渲染组件。