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をインストールする方法

推薦する

MySQLクエリのパフォーマンスに影響を与える大きなオフセットの理由と最適化の詳細な説明

序文MySQL クエリは select コマンドを使用し、limit および offset パラメー...

マインスイーパゲームを実装するための jQuery プラグイン (2)

この記事では、jQueryプラグインを使用してマインスイーパゲームを実装する2番目の記事を参考までに...

Dockerを使用してDjango+MySQL8開発環境をデプロイする方法の詳細な説明

しばらく前にシステムを再インストールしましたが、バックアップを取っていなかったので、コンピューター上...

誤って削除されたデータを復元するための mysqlbinlog コマンドを使用した mysql の実装

実験環境: MYSQL 5.7.22バイナリログを有効にするログ形式 MIXED実験プロセス: 1....

図を使ってWeb2.0とは何かを説明する

最近はWeb2.0という言葉をよく耳にしますが、Web2.0とは何でしょうか? Web 1.0 とど...

vue の webpack -v エラー解決の概要

XiaobaiはVueについて学び、次にwebpackについて学び、そしてさまざまなものをインストー...

Tomcat ディレクトリ構造の詳細な紹介

tomcat の解凍されたディレクトリを開くと、次のディレクトリ構造が表示されます。 1.Tomca...

Navicat の MySQL へのリモート接続の実装手順の分析

序文皆さんはリモート サーバーで開発を行っており、MySQL の使用率はかなり高いはずです。コマンド...

CentOS7.5 MySQLのインストールチュートリアル

1. まずシステムにmysqlがインストールされているかどうかを確認します rpm -qa | gr...

MySQL InnoDBエンジンのインデックスとストレージ構造の詳細な説明

序文Oracle や SQL Server などのデータベースには、ストレージ エンジンが 1 つだ...

GET POSTの違い

1. Get はサーバーからデータを取得するために使用され、Post はサーバーにデータを渡すために...

選択にスタイルを追加するための純粋な CSS (スクリプトなし) 実装

通常は ul、li を介して選択のデフォルト スタイルを変更して、実現をシミュレートします。このよう...

実用的なクイックスタートReactルーティング開発

インストールインストールするには、次のコマンドを入力します。 // ネプ npm で react-r...

小さなプログラムが天井に張り付いてしまう問題を完璧に解決するためにposition:stickyを使用する方法

最近、あるプロジェクトのクライアントが、上部に 2 つのタブ メニューを配置することを要求しました。...

MySQLテーブルパーティショニングプログラムを変更する方法

MySQLテーブルパーティショニングプログラムを変更する方法1. サブテーブルの実装の原則は次のとお...