Reactフックの仕組み

Reactフックの仕組み

1. React フックと純粋関数

簡単に言うと、React Hook は React V18.6 で追加されたいくつかの新しい API です。API の本質は、特定の関数に関数インターフェースを提供することです。したがって、React Hooks は関数ですが、React Hooks は純粋な関数ではありません。

純粋関数とは何ですか?つまり、この関数は入力値が同じ場合に同じ出力を生成する必要があり、この関数は外部データに影響を与えることはできません。
簡単に言うと、外部で定義された変数は関数内では使用できません。外部で定義された変数を使用すると、外部変数が変更されると関数内の計算に影響し、関数も外部変数に影響を与えるからです。

React Hooks によって提供される関数 API は純粋な関数ではありません。
useState ステートメント const [count, setCount] = useState(0) を見てみましょう。useState 関数を使用した結果は常に同じではありません。useState(0) の結果が毎回同じであれば、カウント値は変更されず、カウントが配置されているページも変更されないため、表示される結果とは異なります。このことから、React Hooks は純粋な関数ではないことがわかります。つまり、Hooks は関数の外部で変数を使用します。

では、React Hooks が純粋関数ではないのはなぜでしょうか?実際には、React フレームワークと関数コンポーネント自体によって決定されます。 React ページ レンダリングの原則は、レンダリングするたびに新しい仮想 DOM を取得し、DOM Diff を実行してページをレンダリングすることであることがわかっています。 React の機能コンポーネントは、関数全体を実行して仮想 DOM を取得します。したがって、ページがレンダリングされるたびに、関数コンポーネント内のすべてのステートメントが再実行されます。関数コンポーネント内で使用される React フックが純粋な関数である場合、レンダリングごとに異なる仮想 DOM は取得されません。

React では、すべての React コンポーネントは純粋な関数である必要があり、独自のプロパティを変更することは禁止されていると規定されています。

そのため、React V16.8 より前、React Hooks がまだリリースされていなかった頃は、関数コンポーネントは純粋な関数であったため、固定の仮想 DOM しか返せず、状態を含めることができず、ライフサイクル メソッドをサポートしていませんでした。そのため、当時は関数コンポーネントのみがサポートされていました。しかし、関数コンポーネントはクラスコンポーネントに比べて制限が多すぎました。関数コンポーネントはクラスコンポーネントを置き換えることはできず、クラスコンポーネントほど使いやすいわけでもありませんでした。

React は、コンポーネントが複雑ではなくシンプルであることを望んでいます。React は、コンポーネントを記述する最良の方法はクラスではなく関数であるべきだと考えています。そのため、React は React Hooks を追加しました。Hook はフックを意味し、React によって関数コンポーネントに提供され、必要なときに外部関数とデータの状態を「フック」することで、関数コンポーネントが改善され、クラスコンポーネントを完全に置き換えることができるようになります。

React の関数コンポーネントは純粋な関数にしかできないため、イベントが発生するたびに関数コンポーネントを再レンダリングするときに異なる仮想 DOM を取得するタスクは、完全に React Hooks に任されています。では、React Hooks はそれをどのように行うのでしょうか。次に、useState を手動で実装します。useState の具体的な詳細は確かに異なりますが、原則と考え方は同じです。

2. シンプルなmyUseState

React.useState の最初の実行では、_state に初期値が割り当てられ、その後の再レンダリングごとに _state の値が読み取られます。 [state, setState] の setState は、_state の値を変更してページを再レンダリングします。
この原則に従って、myUseState 関数は次のように実装されます。

'react' から React をインポートします。
'react-dom' から ReactDOM をインポートします。

_state を記述する

関数 myUseState(初期値){
  if(_state === 未定義){
    _state = 初期値
  }
  const setState = (新しい値)=>{
    _state = 新しい値
    与える()
  }
  [_state, setState] を返す
}

関数レンダリング(){
  ReactDOM.render(<App/>,document.getElementById('root'));
}

関数App(){
  定数[n, setN] = myUseState(0)
  戻る (
    <div>
      番号: {n}
      <button onClick={() => setN(n+1)}>+1</button>
    </div>
  )
}

ReactDOM.render(<App/>,document.getElementById('root'));

3. myUseStateを改善する

上記で実装した myUseState にはバグがあります。関数コンポーネント内で myUseState を 2 回使用すると問題が発生します。2 つが同じ _state を共有するため、混乱が生じます。
そのため、上記の実装は改善する必要があります。改善の考え方は、_state をデータまたはオブジェクトとして定義することです。関数を使用するときに数値を渡すだけなので、キーの値を判別できず、データのみを使用できます。改善点は次のとおりです。

'react' から React をインポートします。
'react-dom' から ReactDOM をインポートします。

_state = [] とします
インデックスを0にする

関数 myUseState(初期値){
  const currentIndex = インデックス
  if(_state[currentIndex] === 未定義){
    _state[現在のインデックス] = 初期値
  }
  const setState = (新しい値)=>{
    _state[現在のインデックス] = 新しい値
    与える()
  }
  インデックス++
  [_state[currentIndex], setState]を返す
}

関数レンダリング(){
  インデックス = 0
  ReactDOM.render(<App/>,document.getElementById('root'));
}

関数App(){
  定数[n, setN] = myUseState(0)
  定数[m, setM] = myUseState(0)
  戻る (
    <div>
      番号: {n}
      <button onClick={() => setN(n+1)}>+1</button>
      <br/>
      メートル: {メートル}
      <button onClick={() => setM(m+1)}>+1</button>
    </div>
  )
}

ReactDOM.render(<App/>,document.getElementById('root'));

4. 実装原則によってトリガーされるフックルール

上記で実装した myUseState は、React.useState の具体的な実装コードではありませんが、実装原理は同じです。 myUseState 関数は、関数コンポーネント内のデータ状態をカプセル化し、状態を管理して、関数コンポーネントが使用する関連する操作インターフェイスを公開します。
このようにして、関数コンポーネントはデータ状態から分離されます。関数コンポーネントは仮想 DOM 自体を返すことのみを担当し、データ状態の管理は、それが「フック」されている React.useState フックに完全に引き渡されます。

上記の実装のアイデアから、React Hooks の実装は実際にはグローバル変数とクロージャ原則に基づいた特別な関数であることがわかります。

ただし、この実装方法だからこそ、React Hooks の使用はトップレベルでの Hooks の呼び出しのみに制限されており、ループ、条件、またはネストされた関数内で Hooks を呼び出さないようにする必要があります。if 条件文内で Hooks を使用すると、コンポーネントがレンダリングされるたびに React.useState 文の実行回数が不正確になり、インデックス カウントが乱れてデータ保守エラーが発生します。

上記の実装原則はインデックスの正しいカウントに依存しているため、React はフックが呼び出される順序に依存します。

上記はReact Hooksの仕組みの詳しい説明です。React Hooksの詳細については、123WORDPRESS.COMの他の関連記事にも注目してください。

以下もご興味があるかもしれません:
  • React Hooksコンポーネント間で値を渡す方法の詳細な説明(tsを使用)
  • ReactHooks バッチ更新状態とルートパラメータの取得例の分析
  • React Hooksの詳細な説明
  • React Hooksを使用する際のよくある落とし穴
  • 30分でReact Hooksを包括的に理解できます
  • Reactにおけるフックの一般的な使用法
  • React の 10 個のフックの紹介

<<:  Windows 7 で Python 3.4 を使って MySQL データベースを使用する

>>:  Django は Pillow を使用して検証コード機能を簡単に設定します (Python)

推薦する

ハイパーリンクのWebデザイン原則

<br />関連記事: Web コンテンツ ページ作成のための 9 つの実用的なヒント、...

CentOS7 で jar アプリケーションの起動を設定する方法

プロジェクトの展開中に遭遇した落とし穴Zhihudemo を展開する際、Jenkins などの自動展...

この記事ではJavaScriptのガベージコレクションの仕組みを説明します

目次1. 概要2. メモリ管理3. ガベージコレクション4. GCアルゴリズムの紹介5. 参照カウン...

Nexus を使用して Docker リポジトリを作成する方法

公式の Docker レジストリを使用して作成されたウェアハウスでは、イメージを削除してもデフォルト...

VUE+Canvasはデスクトップピンボールブロック破壊ゲームのサンプルコードを実装します

誰もがピンボールやレンガ崩しのゲームをプレイしたことがあるでしょう。左と右のキーを使用して、下にある...

純粋な CSS でマークダウンの自動番号付けを実装するサンプル コード

問題の起源私がタイトルの番号付けの問題に初めて注目したのは、学部の論文を書いていた頃まで遡ります。当...

Vue シングルファイルコンポーネントの実装

最近、vue について読みました。これまで基本的に見落としていた単一ファイル コンポーネントを見つけ...

Reactでwindow.print()を使用した際にページが応答しなくなる問題の解決記録について

目次1. 問題の背景: 2. 問題の原因: 3. 問題解決:要約: 1. 問題の背景: window...

DockerはElasticsearch7.6クラスタをインストールし、パスワードを設定します

Elasticsearch 6.8 以降、無料ユーザーは X-Pack のセキュリティ機能を使用でき...

HTML と JavaScript を使用してローカル メディア (ビデオとオーディオ) ファイルを再生する方法

まず、セキュリティ上の理由から、JavaScript はローカル リソース ファイルに直接アクセスで...

Vueはシンプルな虫眼鏡効果を実装します

この記事では、参考までに、簡単な虫眼鏡効果を実現するためのVueの具体的なコードを紹介します。具体的...

KVM 仮想マシンのオンライン ホット マイグレーションを実装する方法 (画像とテキスト)

1. KVM仮想マシンの移行方法と注意すべき点KVM 仮想マシンを移行する方法は 2 つあります。...

Nginx における accept lock の仕組みと実装の詳細な説明

序文nginx はマルチプロセス モデルを使用します。リクエストが届くと、システムはプロセスをロック...

MySQLの起動と接続方法の例分析

目次mysqldの起動方法方法 1: mysqld方法 2: mysqld_safe方法3: mys...

MySQL での limit の使用方法は何ですか (推奨)

SELECT * FROM テーブル名制限m,n; SELECT * FROM テーブル LIMI...