反应-转发多个引用

EJ *_*gan 10 reactjs

我有一个SideNav组件,其中包含动态创建的链接,这些链接需要滚动到相邻html表(InfoTable)中的相应标题。我尝试了多种不同的方法来完成此操作,但没有成功。

export default class Parent extends Component {
  state = {
    categories: [],
  }

  scrollToHeader = (tableRefString) => {
    // Function to pass to SideNav to access refs in InfoTable
    this[tableRefString].scrollIntoView({ block: 'start' });
  }

  render() {
    return (
      <div>
        <SideNav
          categories={this.state.categories}
          scrollToHeader={this.scrollToHeader} />
        <InfoTable
          categories={this.state.categories} />
      </div>
    );
  }
}

export default class InfoTable extends Component {
  render() {
    return (
      <div>
        <table>
          <tbody>
            {this.props.categories.map(category => (
              <>
                // Forward the ref through InfoTableHeader to be set on the parent DOM node of each InfoTableHeader
                <InfoTableHeader />
                {category.inputs.map(input => <InfoTableRow />)}
              </>
            ))}
          </tbody>
        </table>
      </div>
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

为了单击SideNav上的链接并滚动到InfoTable上的相应标题,我相信我需要转发基于我的类别数组中的名称在Parent上动态创建的引用,并将这些引用设置为DOM中每个标题的DOM节点。信息表。从那里,我会将一个函数传递给SideNav,该函数可以访问Parent中的引用以滚动到标题。

  • 如何将多个引用一次转发到InfoTable组件?
  • 有没有更干净的方法来完成我要完成的工作?我已经研究了React.findDOMNode(),但引用似乎是更好的选择。

Sam*_*rad 42

我知道有一个已经被接受的答案,虽然我发现@nicholas-haley 的解决方案是可以接受的。我认为更好的方法是使用内置useImperativeHandle钩子。

重要提示:React Hooks Api 可用

  • react@16.8.0 及更高版本
  • react-native@0.59.0 及更高版本

React hooks API Docs状态:

useImperativeHandle自定义使用 ref 时暴露给父组件的实例值。与往常一样,在大多数情况下应该避免使用 refs 的命令式代码。useImperativeHandle 应该与 `forwardRef 一起使用

此注释后跟以下示例:

function FancyInput(props, ref) {
  const inputRef = useRef();
  useImperativeHandle(ref, () => ({
    focus: () => {
      inputRef.current.focus();
    }
  }));
  return <input ref={inputRef} ... />;
}
FancyInput = forwardRef(FancyInput);
Run Code Online (Sandbox Code Playgroud)

因此,在我看来,一个更简洁的解决方案是通过useImperativeHandle钩子委托所需的引用。

这样就不需要特殊的 ref 语法,组件可以简单地返回一个特定类型的 FatherRef;例子:

// LabelInput.js
function LabelInput(props, ref) {
    const labelRef = useRef();
    const inputRef = useRef();

    useImperativeHandle(ref, () => ({
      focus: () => {
       inputRef.current.focus();
      },
      get input() {
          return inputRef.current;
      },
      get label() {
          return labelRef.current;
      },
      // ... whatever else one may need
    }));
    return (
      <div>
        <label ref={labelRef} ... />
        <input ref={inputRef} ... />;
      </div>
    )
}
LabelInput = forwardRef(LabelInput);

function MyScreen() {
   const labelInputRef = useRef();

   const onClick = useCallback(
    () => {
//       labelInputRef.current.focus(); // works
//       labelInputRef.current.input.focus(); // works
// ... etc
    },
    []
   );

   return (
     ...
      <LabelInput ref={labelInputRef} ... />
     ....
   )
}
Run Code Online (Sandbox Code Playgroud)


Nic*_*ley 9

我遇到过类似的情况,我需要将多个引用转发给我的Parent组件的孩子。

我仍然没有找到一个优雅的解决方案,但是您可以尝试将ref作为对象传递,并在forwardRef回调中进行分解:

// Parent
ref={{
    ref1: this.ref1,
    ref2: this.ref2
}}
Run Code Online (Sandbox Code Playgroud)
// Child
export default React.forwardRef((props, ref) => {
  const { ref1, ref2 } = ref;

  return (
    <Child1
      {...props}
      ref={ref1}
    />
    <Child2
      {...props}
      ref={ref2}
    />
  );
});
Run Code Online (Sandbox Code Playgroud)

我不是此处命名的忠实拥护者(我更喜欢ref称呼refs),但这可以在您遇到紧急情况时起作用。

  • 我搜索了互联网,最终也找不到一个优雅的解决方案。似乎没有任何既定的模式来实现这一点(也许是有原因的?)。我最终只是将 refs 传递到一个对象中并将它们直接附加到对象之外,而不是使用 React.forwardRef。这样做一切正常,不使用 React.forwardRef 有什么我遗漏的吗? (7认同)