クラスベースのコンポーネントでReact.forwardRefを使用する方法


111

React.forwardRefを使用しようとしていますが、それをクラスベースのコンポーネント(HOCではない)で機能させる方法につまずきました。

ドキュメントの例では、要素と機能コンポーネントを使用し、さらに高次コンポーネントのクラスを関数でラップしています。

以下のようなものから始まるので、この自分でref.jsファイル:

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

代わりに、次のように定義します。

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

または

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

のみ動作します:/

また、私は知っていることを知っている、refは反応する方法ではない。私はサードパーティのキャンバスライブラリを使用しようとしています。それらのツールのいくつかを個別のコンポーネントに追加したいので、イベントリスナーが必要なので、ライフサイクルメソッドが必要です。後で別のルートに進むかもしれませんが、これを試してみたいと思います。

ドキュメントはそれが可能であると言います!

参照転送はDOMコンポーネントに限定されません。refをクラスコンポーネントインスタンスに転送することもできます。

このセクションメモから

しかし、クラスだけでなくHOCを使用し続けます。

回答:


107

常に同じプロップを使用するという考えrefは、ヘルパーを使用してクラスエクスポートをプロキシすることで実現できます。

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}
/>);

したがって、基本的には、そうです、refを転送するための別のプロップを用意する必要がありますが、ハブの下で実行できます。一般の人がそれを通常の参照として使用することが重要です。


4
コンポーネントをReact-Redux connectやmarterial-uiなどのHOCでラップしている場合はどうしますwithStylesか?
J.ヘスターズ

connectまたはの問題は何withStylesですか?すべてのHOCをラップしforwardRef、内部で「安全な」プロップを使用して、チェーン内の最も低いコンポーネントに参照を渡す必要があります。
Br氏

あなたがsetStateを使用しているときに酵素でこれをテストする方法についての洞察はありますか?
zero_cool 2018年

もう少し詳しく教えてください。正確に何が問題なのかわからない。
Mr Br

2
取得中:不変の違反:オブジェクトはReactの子として有効ではありません(キー:{$$ typeof、render}のオブジェクト)。子のコレクションをレンダリングする場合は、代わりに配列を使用してください。
Brian Loughnane

9
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()} />
)

refをクラスに転送するには、別のプロップ名を使用する必要があります。innerRef多くのライブラリで一般的に使用されています。


コード内でbeautifulInputElementは、React Elementではなく関数です。これは次のようになりますconst beautifulInputElement = <BeautifulInputForwardingRef ref={ref => ref && ref.focus()} />
OlivierBoisséOct

8

基本的に、これはHOC関数です。クラスで使用したい場合は、自分でこれを行い、通常の小道具を使用できます。

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

const ref = React.createRef();
<TextInput forwardRef={ref} />

このパターンは、たとえばで使用され、そこでstyled-components呼び出されinnerRefます。


3
のような別の名前の小道具を使用するとinnerRef、ポイントが完全に失われます。目標は完全な透過性です。<FancyButton>通常のDOM要素のように扱うことができるはずですが、スタイル付きコンポーネントアプローチを使用する場合、このコンポーネントはrefの代わりに任意の名前のプロップを使用することを覚えておく必要がありますref
user128216

2
いずれにせよ、styled-componentsは、を使用してrefを子に渡すことを支持してinnerRefサポートを終了する予定ですReact.forwardRef。これは、OPが達成しようとしていることです。
user128216 2018

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

そして、あなたのコンポーネントファイルで:

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

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

export default withForwardedRef(Boop)

私はテストで事前に作業を行い、このためのパッケージを公開しましたreact-with-forwarded-refhttps : //www.npmjs.com/package/react-with-forwarded-ref


3

これを多くの異なるコンポーネントで再利用する必要がある場合は、この機能を次のようなものにエクスポートできます。 withForwardingRef

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

export default withForwardingRef;

使用法:

const Comp = ({forwardedRef}) => (
 <input ref={forwardedRef} />
)
const EnhanceComponent = withForwardingRef<Props>(Comp);  // Now Comp has a prop called forwardedRef
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.