React refの使用例

React refの使用例

私はしばらく react を書いてきましたが、その 99% の時間は state、prop、useState、useEffect について書いてきました。特に ref についてはよく知りません。数日前に要件を作成し、ref を使用して親コンポーネントから子コンポーネントの状態値を実装したいと思ったのですが、失敗しました。ref に関連するコンテンツを整理したいと思います。

refとは何か

公式サイト紹介:

一般的な React データフローでは、props は親コンポーネントが子コンポーネントと対話する唯一の方法です。子コンポーネントを変更するには、新しいプロパティを使用して再レンダリングする必要があります。ただし、通常のデータ フローの範囲外でサブコンポーネントを強制的に変更する必要がある場合もあります。変更された子コンポーネントは、React コンポーネントまたは DOM 要素のインスタンスである可能性があります。どちらの場合も、React は ref を使用して dom またはコンポーネント インスタンスを取得するという解決策を提供します。

refの使い方

DOM要素に配置する

これはrefの最も直接的な使用法である

Demoクラスをエクスポートし、React.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    this.myRef = createRef()
  }
  コンポーネントマウント() {
    コンソールログ(this.myRef)
  }
  与える() {
    <div ref={this.myRef}>test</div> を返します
  }
}

印刷してrefが何であるか確認する

ref.current は DOM 要素を取得するので、入力フォーカスなど、DOM 要素自体のいくつかの機能を実装できることがわかります。

Demoクラスをエクスポートし、React.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    this.myRef = createRef()
  }

  クリック時 = () => {
    this.myRef.current.focus()
  }

  与える() {
    戻る (
      <div>
        <button onClick={this.onClick}>フォーカス</button>
        <input ref={this.myRef} />
      </div>
    )
  }
}

公式ウェブサイトでは、ref コールバックの形式も提供されています。

Demoクラスをエクスポートし、React.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    this.myRef = null
  }

  クリック時 = () => {
    this.myRef.focus()
  }

  与える() {
    戻る (
      <div>
        <button onClick={this.onClick}>フォーカス</button>
        <input ref={ele => this.myRef = ele} /> // ここでの ele は dom 要素です</div>
    )
  }
}

クラスコンポーネントに配置する

実際、コンポーネントはネイティブ DOM に似ています。コンポーネントも独自の UI といくつかの機能を持つ要素です。そのため、コンポーネントに ref を配置すると、コンポーネントの例を取得することもできます。

// 子コンポーネントクラス Child は React.Component を拡張します {
  コンストラクタ(props) {
    スーパー(小道具)
    この状態 = {
      名前: 'xx'
    }
  }
  与える() {
    <div>子要素 {this.state.name}</div> を返します。
  }
}

Demoクラスをエクスポートし、React.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    this.myRef = createRef()
  }

  コンポーネントマウント() {
    コンソールログ(this.myRef)
  }

  与える() {
    戻る (
     <子ref={this.myRef} />
    )
  }
}

子コンポーネントのインスタンスを取得できるようになったので、子コンポーネントを操作できるようになります。例えば、記事の冒頭で述べたように、親コンポーネントで子コンポーネントのステータス値をいくつか取得したいとします。

クラスChildはReact.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    この状態 = {
      カウント: 0
    }
  }
  
  クリック時 = () => {
    this.setState({count: this.state.count+1})
  }

  与える() {
    戻り値 <button onClick={this.onClick}>クリック +1: {this.state.count}</button>
  }
}

Demoクラスをエクスポートし、React.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    this.myRef = createRef()
  }

  クリック時 = () => {
    console.log(this.myRef.current.state.count) // 子コンポーネントの状態値を取得します}


  与える() {
    戻る (
      <div>
        <button onClick={this.onClick}>サブコンポーネントのクリック数を取得します</button>
        <Child ref={this.myRef} /> // ref は子コンポーネントのインスタンスを取得します</div>
    )
  }
}

値を取得できるので、関数を使用して子コンポーネントを変更することもできます。

クラスChildはReact.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    この状態 = {
      名前: 'xx'
    }
  }
  名前の変更 = () => {
    this.setState({name: 'ww'})
  }
  与える() {
    <div>子要素 {this.state.name}</div> を返します。
  }
}

Demoクラスをエクスポートし、React.Componentを拡張します。
  コンストラクタ(props) {
    スーパー(小道具)
    this.myRef = createRef()
  }

  クリック時 = () => {
    this.myRef.current.changeName() // 親コンポーネントが子コンポーネントに到達します}

  与える() {
    戻る (
      <div>
        <button onClick={this.onClick}>子コンポーネントの状態を変更する</button>
        <子ref={this.myRef} />
      </div>
    )
  }
}

もちろん、この例は適切ではありません。親コンポーネントが子コンポーネントの状態を変更する場合は、状態を親コンポーネントに昇格させてから、それを子コンポーネントのプロパティとして渡す必要があります。
主に、ref は props をバイパスして親子コンポーネントの通信を実現する方法を提供します。

関数コンポーネントに配置する

これは、記事の冒頭で要件を記述したときに私が犯した間違いです。関数コンポーネントにはインスタンスがないため、Ref を関数コンポーネントに配置できません。

定数子 = () => {
  <div>子コンポーネント</div>を返します。
}

エクスポートconstデモ = () => {
  const myRef = useRef() // 関数コンポーネント内でrefを作成できます

  使用効果(() => {
    コンソールログ(myRef)
  }, [])

  return <Child ref={myRef} /> // ただし、関数コンポーネントに配置すると無効になります}

関数コンポーネントは ref を使用できないのですか? もちろんそんなことはありません、ハハ。関数コンポーネントを forwardRef でラップできます。

const Child = (props, ref) => { // パッケージ化後、元の props に加えて、ref も返されます <div ref={ref}>child component</div> // まだ dom にマウントする必要があります}

const ProChild = React.forwardRef(Child) // 重要なポイントはここです export const Demo = () => {
  定数 myRef = useRef()

  使用効果(() => {
    コンソールログ(myRef)
  }, [])

  <ProChild ref={myRef} /> を返します。
}

公式サイトからのヒントは次のとおりです。

関数コンポーネントでも ref を使用できるため、関数コンポーネントを使用して親コンポーネントを実装し、子コンポーネントのデータを取得します。ただし、forwardRef でラップした後でも、ref を dom またはクラス コンポーネントにマウントする必要があることがわかります。データのみをマウントする場合は、useImperativeHandle も使用する必要があります。

const 子 = (props, ref) => {
  定数[count, setCount] = useState(0)

  命令型ハンドルを使用します(
    参照、
    () => ({ // これは外部参照に公開されるデータです getVal: ()=> count
    })、
    [カウント]、
  )

  定数onClick = () => {
    setCount(pre => pre+1)
  }
  戻り値 <button onClick={onClick}>クリック +1: {count}</button>
}

const ProChild = React.forwardRef(Child)

エクスポートconstデモ = () => {
  定数 myRef = useRef()

  定数onClick = () => {
    console.log(myRef.current.getVal()) // 子コンポーネントの値を取得します}

  return <><button onClick={onClick}>子コンポーネントのクリック数を取得します</button><ProChild ref={myRef} /></>
}

これまでのところ、要求を行う際に残っていた問題は解決されました✅

要約する

最後に、親コンポーネントが子コンポーネントの状態を取得するシナリオでは、一般的に状態昇格+コールバックで通信し、要求は最終的にこのように実装されることを強調する必要があります。 最初にrefを使用したかった理由は、状態が昇格した後、子コンポーネントの変更により親コンポーネントが再レンダリングされると考えましたが、レンダリングを起こさずにデータを取得したかっただけです。
要件を書く際に考えたことを師匠に伝えたところ、師匠の意見は以下のとおりです。

  • ステータスの改善を優先する
  • パフォーマンスの問題がある場合は、状態の改善+メモを検討してください
  • 複数のコンポーネントにメモを追加したくない場合は、redux/mobxの導入を検討する必要があります。
  • redux/mobx の導入にコストがかかるなら、ref は不可能ではないですね、ハハハハ

以上がReact refの使い方の詳しい説明の内容です。React refの使い方についてさらに詳しく知りたい方は、123WORDPRESS.COM内の他の関連記事もぜひご覧ください!

以下もご興味があるかもしれません:
  • React forwardRefの使い方と注意点
  • Vue3 の組み合わせ API における setup、ref、reactive の完全な使用方法
  • Reactのref属性を深く理解する方法
  • React の 3 つの主要属性における Ref の使用に関する詳細な説明
  • ReactにおけるuseRefの具体的な使い方
  • ReactでRefを使用する方法の詳細な説明
  • react-refetchの使い方の詳しい説明
  • Reactのrefのデモ例を2つ学ぶ
  • React で refs を使用するチュートリアル
  • Reactコンポーネントrefsの使用に関する詳細な説明
  • React Native での RefreshContorl プルダウン リフレッシュの使用
  • ReactにおけるRefの相互利用の詳細な説明

<<:  MySQL における KEY、PRIMARY KEY、UNIQUE KEY、INDEX の違い

>>:  Raspberry PiにDockerをインストールする方法

推薦する

NFS サーバーの原理と、その構築、構成、展開の手順を簡単に分析します。

目次NFS サービスの概要NFS とは何ですか? NFS マウントの原則NFS サーバーはデータ転送...

Win10 MySQLでCSVをエクスポートする2つの方法

Win10 で csv をエクスポートする方法は 2 つあります。1 つ目はツールを使用することです...

CentOS 起動時にカーネルモジュール overlayfs 操作を自動的にロードする

CentOS でカーネル モジュールを自動的にロードするには、/etc/sysconfig/modu...

jQueryは検証コード送信のコントロールボタンを無効にする機能を実装します

必要な効果: 確認コードを送信するためにクリックした後、ボタンは無効になり、5 秒後に無効解除されま...

vue2 vue3 での Echarts の詳細な使用方法

目次1. インストール2. vue2でEchartsを使用するmain.jsファイル内コンテナが与え...

ViteでReactプロジェクトを構築する方法

目次序文Viteプロジェクトを作成する改修プロジェクトディレクトリの規則その他の構成序文毎日鳩、火ば...

select @@session.tx_read_only が DB に大量に出現するのはなぜですか?

問題を見つける上位の SQL ステートメントを取得すると、DB が大量のselect @@sessi...

Dockerのヘルス検出メカニズム

コンテナの場合、最も単純なヘルスチェックはプロセス レベルのヘルスチェックであり、プロセスが稼働して...

CentOS7 から CentOS8 にアップグレードする方法 (詳細な手順)

この記事では、具体的な例を使用して、CentOS 7 から CentOS 8 にアップグレードする方...

jQuery キャンバスは QR コード付きのポスターを生成します

この記事では、jQuery キャンバスを使用して QR コード付きのポスターを生成するための具体的な...

Ubuntu 20.04 Firefox でビデオを再生できない (Flash プラグインがない) 場合の解決策

1. Flashプラグインパッケージのダウンロードアドレス: https://get.adobe.c...

MySQL LOAD_FILE() 関数メソッドの概要

MySQL では、LOAD_FILE() 関数はファイルを読み取り、その内容を文字列として返します。...

MySQL 8.0 バージョンで getTables がすべてのデータベース テーブルを返す問題の簡単な分析

序文この記事では、主にライブラリ内のすべてのテーブルを返すMysql8.0ドライバgetTables...

時間のかかるDockerエラーのトラブルシューティングプロセス記録

目次起源環境情報トラブルシューティングのプロセス要約する起源顧客は CentOS をベースにしたカス...

Linux カーネル デバイス ドライバー proc ファイル システム ノート

/***************** * proc ファイルシステム***************...