经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » JS/JS库/框架 » React » 查看文章
React自定义Hook-useForkRef的具体使用
来源:jb51  时间:2022/3/7 11:12:58  对本文有异议

开篇

使用过 React 技术栈的同学相信都使用过 ref 传递给 render 中的元素,而在使用 React 封装组件时,会有这样一个场景:

组件将 props.children 作为 render 内容;组件内部会创建 ref 绑定到 props.children 上。

我们知道,元素上只能绑定一个 ref 属性引用,但对于上面这个场景,props.children 上可能已经存在一个 ref 属性,而组件内部定义的 ref 也会绑定到 props.children 上。
我们要想一种方式,将两者的 ref 都可以生效于元素上。

思路

首先我们回顾一下 React 创建 ref 的方式:

  • React.createRef():React 16.3 版本提供的 class 创建 ref 方式;
  • React.useRef():React Hooks 提供的 函数组件 创建 ref 方式;
  • 回调 Refs:传递一个函数作为元素的 ref 属性,此函数接收 React 组件实例或 HTML DOM 元素作为参数。

综合考虑,既然 回调 Refs 允许我们传递一个函数,并且接收元素实例作为这个函数的参数,那我们就可以定义一个这样的函数,在函数内编写我们的逻辑来处理 多个 ref 绑定元素实例的场景。(函数的灵活性)

实现

  • 编写一个函数(闭包函数),接收 props.children.ref 和 组件内 ref 作为参数;
  • 函数(闭包函数)需要 return 返回一个函数,这个函数将作为 回调 Refs 去作用于元素;
  • 在 return 的这个函数中,将函数参数(元素引用)绑定到 props.children.ref 和 组件内 ref 上。

上代码:

  1. function forkRef(refA, refB) {
  2. ? return refValue => {
  3. ? ? setRef(refA, refValue);
  4. ? ? setRef(refB, refValue);
  5. ? };
  6. }
  7.  
  8. function setRef(ref, value) {
  9. ? if (typeof ref === 'function') {
  10. ? ? ref(value);
  11. ? } else if (ref) {
  12. ? ? ref.current = value;
  13. ? }
  14. }

在 setRef 中会针对创建 ref 的方式做不同处理,比如:React.createRef 和 React.useRef 创建的 ref 是一个具有 current 属性的对象。

使用:

  1. const nodeRef = React.useRef(null); // 组件内部的 ref
  2.  
  3. const handleRef = forkRef(props.children.ref, nodeRef);
  4.  
  5. const childrenProps = { ref: handleRef };
  6.  
  7. return React.cloneElement(children, childrenProps);

自定义 Hook - useForkRef

在 Hook 函数组件中,我们可以借助于 React.memo() 优化一下 forkRef() 的逻辑,避免每次组件更新时都创建一个新的闭包函数。
下面我们使用 TS 编写一个 useForkRef:

  1. import * as React from 'react';
  2.  
  3. interface MutableRefObject<T> {
  4. ? current: T;
  5. }
  6.  
  7. type Ref<T> = ((instance: T | null) => void) | MutableRefObject<T> | null;
  8.  
  9. export function setRef(ref: Ref<unknown>, value: unknown) {
  10. ? if (typeof ref === 'function') {
  11. ? ? ref(value);
  12. ? } else if (ref) {
  13. ? ? ref.current = value;
  14. ? }
  15. }
  16.  
  17. export default function useForkRef(refA: Ref<unknown>, refB: Ref<unknown>) {
  18. ? return React.useMemo(() => {
  19. ? ? if (refA == null && refB == null) {
  20. ? ? ? return null;
  21. ? ? }
  22. ? ? return (refValue: unknown) => {
  23. ? ? ? setRef(refA, refValue);
  24. ? ? ? setRef(refB, refValue);
  25. ? ? };
  26. ? }, [refA, refB]);
  27. }

使用:

  1. const nodeRef = React.useRef<HTMLElement>(null); // 组件内部的 ref
  2. const handleRef = useForkRef(children.ref, nodeRef);
  3.  
  4. const childrenProps: any = { ref: handleRef };
  5. React.cloneElement(children, childrenProps)

到此这篇关于React自定义Hook-useForkRef的具体使用的文章就介绍到这了,更多相关React Hook-useForkRe内容请搜索w3xue以前的文章或继续浏览下面的相关文章希望大家以后多多支持w3xue!

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号