【问题标题】:Can I assign multiple refs to the same Element/Node?我可以将多个参考分配给同一个元素/节点吗?
【发布时间】:2020-12-31 06:39:17
【问题描述】:

我有一个函数组件,它将传入的 ref 从父级转发到它正在呈现的div。我还想在组件内创建一个 ref 并将其分配给相同的div。但我不能,因为一个元素只需要一个参考。我做错了什么还是有解决此类问题的方法?

来自父级的refReact.Ref,但我需要一个React.RefObject 将其传递给第三方挂钩,例如react-use 的clickAwayhttps://github.com/streamich/react-use/blob/master/docs/useClickAway.md

这是示例组件:

import React, { useRef } from 'react';

type Props = React.PropsWithoutRef<JSX.IntrinsicElements['div']>;

function Component({ ...props }: Props, ref: React.Ref<HTMLDivElement>) {
  const wrapper = useRef<HTMLDivElement>(null);

  return (
    <div
      {...props}
      ref={ref}
      // ref={wrapper}
    />
  );
}

export default React.forwardRef(Component);

【问题讨论】:

  • 你没有为同一个 dom 节点创建两个 refs。您可以轻松地在子组件中使用转发的 ref 并像通常使用 ref 一样工作。在Component 组件中,只需使用ref.current
  • 我更新了问题,添加了我需要的原因。

标签: javascript reactjs typescript react-hooks


【解决方案1】:

我不知道你为什么要为这个 div 分配另一个 ref。 Ref 只是对 DOM 的引用。 Wrapper ref 和 props 中的 ref 是一样的。

Refs 提供了一种访问 DOM 节点或在 render 方法中创建的 React 元素的方法。

在这种情况下,如果你想访问 div 的这个 ref。

function Component({ ...props }: Props, ref: React.Ref<HTMLDivElement>) {
  const wrapper = ref;

  return (
    <div
      {...props}
      ref={ref}
      // ref={wrapper}
    />
  );
}

【讨论】:

    【解决方案2】:

    简答


    您可以使用这样的简单函数来合并参考
    const mergeRefs = (...refs) => {
      return node => {
        for (const ref of refs) {
          ref.current = node
        }
      }
    }
    

    为什么会起作用


    之所以可行,是因为在底层, ref prop 可以接受一个带有自引用节点作为参数的函数。
    import React from "react"
    
    export default () => {
      const ref1 = React.useRef(null)
      const ref2 = React.useRef(null)
      return (
        <div
          ref={node => {
            ref1.current = node
            ref2.current = node
          }}
        >
          Hello
        </div>
      )
    }
    

    示例归功于this article

    使用引用类型


    从字面上看,它看起来像这样。就个人而言,我不清楚如何阅读“RefCallback”——它看起来像是一个带有通用参数 T 的自引用函数,并且 T 以某种方式代表节点本身。开放给进一步澄清它的人。
    interface RefObject<T> {
        readonly current: T | null;
    }
    type RefCallback<T> = { bivarianceHack(instance: T | null): void }["bivarianceHack"];
    type Ref<T> = RefCallback<T> | RefObject<T> | null;
    

    打字稿答案


    如果你想添加更多的检查和平衡,你可以使用这个从 Tailwind 的 headlessui 中获取的 typescript 兼容函数。
    function useSyncRefs<TType>(
      ...refs: (
        | React.MutableRefObject<TType | null>
        | ((instance: TType) => void)
        | null
      )[]
    ) {
      let cache = React.useRef(refs);
    
      React.useEffect(() => {
        cache.current = refs;
      }, [refs]);
    
      return React.useCallback(
        (value: TType) => {
          for (let ref of cache.current) {
            if (ref == null) {
              console.log('ref is null');
              continue;
            }
            if (typeof ref === 'function') {
              console.log('ref is a function. Returning called function');
              ref(value)
            } else {
              console.log('returning the value: ', value);
              ref.current = value
            };
          }
        },
        [cache]
      );
    };
    

    您可以在 Expo Snack 中看到它的实际效果。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-08-13
      • 2013-09-29
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多