如何在基于类的组件中使用React.forwardRef?

Han*_*rus 86 javascript reactjs

我正在尝试使用React.forwardRef,但是如何让它在基于类的组件(而不是HOC)中工作.

docs示例使用元素和功能组件,甚至在高阶组件的函数中包装类.

所以,从他们的ref.js文件中的这样的东西开始:

const TextInput = React.forwardRef(
    (props, ref) => (<input type="text" placeholder="Hello World" ref={ref} />)
);
Run Code Online (Sandbox Code Playgroud)

而是将其定义为:

class TextInput extends React.Component {
  render() {
    let { props, ref } = React.forwardRef((props, ref) => ({ props, ref }));
    return <input type="text" placeholder="Hello World" ref={ref} />;
  }
}
Run Code Online (Sandbox Code Playgroud)

要么

class TextInput extends React.Component {
  render() { 
    return (
      React.forwardRef((props, ref) => (<input type="text" placeholder="Hello World" ref={ref} />))
    );
  }
}
Run Code Online (Sandbox Code Playgroud)

只有工作:/

另外,我知道我知道,参考不是​​反应方式.我正在尝试使用第三方画布库,并希望在单独的组件中添加一些工具,因此我需要事件监听器,因此我需要生命周期方法.以后它可能会走另一条路,但我想尝试一下.

文档说这是可能的!

Ref转发不仅限于DOM组件.您也可以将refs转发给类组件实例.

来自本节说明.

但后来他们继续使用HOC而不仅仅是课程.

Mr *_* Br 79

通过使用ref帮助程序代理类导出,可以实现始终使用相同prop的想法.

class ElemComponent extends Component {
  render() {
    return (
      <div ref={this.props.innerRef}>
        Div has ref
      </div>
    )
  }
}

export default React.forwardRef((props, ref) => <ElemComponent 
  innerRef={ref} {...props}
/>);
Run Code Online (Sandbox Code Playgroud)

所以基本上,是的,我们被迫有一个不同的道具来转发参考,但它可以在集线器下完成.重要的是公众将其作为正常参考使用.

  • 如果将组件封装在像React-Redux的connect和marterial-ui的withStyles这样的HOC中,该怎么办? (2认同)
  • 我得到:不变违规:对象作为 React 子对象无效(发现:对象带有键 {$$typeof, render})。如果您打算渲染一组子项,请改用数组。 (2认同)

Łuk*_*ski 7

基本上,这只是一个HOC函数。如果您想在课堂上使用它,可以自己做,并使用常规道具。

class TextInput extends React.Component {
    render() {
        <input ref={this.props.forwardRef} />
    }
}

const ref = React.createRef();
<TextInput forwardRef={ref} />
Run Code Online (Sandbox Code Playgroud)

例如在中使用此模式,styled-components并在其中调用innerRef它。

  • 使用像`innerRef`这样的不同名字的道具完全没有意义。目标是完全透明:我应该能够将`&lt;FancyButton&gt;`视为常规DOM元素,但是使用样式化组件方法时,我需要记住,该组件使用了任意命名的ref代替只是`ref`。 (3认同)
  • 无论如何,styled-components都打算[删除对`innerRef`的支持](https://github.com/styled-components/styled-components/issues/1694)以便使用`React将ref传递给孩子。 .forwardRef`,这是OP试图完成的任务。 (2认同)

Seb*_*ber 7

class BeautifulInput extends React.Component {
  const { innerRef, ...props } = this.props;
  render() (
    return (
      <div style={{backgroundColor: "blue"}}>
        <input ref={innerRef} {...props} />
      </div>
    )
  )
}

const BeautifulInputForwardingRef = React.forwardRef((props, ref) => (
  <BeautifulInput {...props} innerRef={ref}/>
));

const App = () => (
  <BeautifulInputForwardingRef ref={ref => ref && ref.focus()} />
)
Run Code Online (Sandbox Code Playgroud)

您需要使用其他属性名称来将引用转发到类。innerRef在许多库中常用。


ore*_*por 5

如果您需要在许多不同的组件中重用此功能,您可以将此功能导出为类似的东西withForwardingRef

const withForwardingRef = <Props extends {[_: string]: any}>(BaseComponent: React.ReactType<Props>) =>
    React.forwardRef((props, ref) => <BaseComponent {...props} forwardedRef={ref} />);

export default withForwardingRef;
Run Code Online (Sandbox Code Playgroud)

用法:

const Comp = ({forwardedRef}) => (
 <input ref={forwardedRef} />
)
const EnhanceComponent = withForwardingRef<Props>(Comp);  // Now Comp has a prop called forwardedRef
Run Code Online (Sandbox Code Playgroud)


rpe*_*rce 5

如果您愿意,可以使用更高阶的组件来实现:

import React, { forwardRef } from 'react'

const withForwardedRef = Comp => {
  const handle = (props, ref) =>
    <Comp {...props} forwardedRef={ref} />

  const name = Comp.displayName || Comp.name
  handle.displayName = `withForwardedRef(${name})`

  return forwardRef(handle)
}

export default withForwardedRef
Run Code Online (Sandbox Code Playgroud)

然后在您的组件文件中:

class Boop extends React.Component {
  render() {
    const { forwardedRef } = this.props

    return (
      <div ref={forwardedRef} />
    )
  }
}

export default withForwardedRef(Boop)
Run Code Online (Sandbox Code Playgroud)

我通过测试进行了前期工作,并为此发布了一个程序包react-with-forwarded-refhttps : //www.npmjs.com/package/react-with-forwarded-ref