30分でReact Hooksを包括的に理解できます

30分でReact Hooksを包括的に理解できます

概要

1. フックは関数コンポーネントでのみ使用できます。

2. フックは関数コンポーネントの機能を拡張するために使用され、関数コンポーネントはクラスコンポーネントを完全に置き換えることができます。

React Hooks はすべて React オブジェクトにアタッチされるため、React.useState() の形式で使用されます。面倒な場合は、次のように事前にインポートすることもできます。

Reactをインポートし、{useState}を"react"から取得します。

React には多くの組み込みフックがあります。ここではよく使用されるフックをいくつか紹介します。詳細については、Hooks API を参照してください。

フックを使用する関数コンポーネント名の最初の文字は大文字にする必要があります。そうでない場合、ESLintはエラーを報告します。

1. 使用状態

const [状態、setState] = useState(初期状態)

1.1 3つの概念に関する質問

useState を呼び出すと何が起こりますか?

useState は、状態変数を宣言し、関数コンポーネントに状態を導入するために使用されます。

useState に渡すパラメーターは何ですか?

useState は、宣言された状態変数を初期化するために使用される数値、文字列、オブジェクトなどの任意の値にすることができる 1 つのパラメーターのみを受け取ります。初期値を返す関数、できればレンダリング時の不要な計算を減らす関数にすることもできます。

useState は何を返しますか?

長さ 2 の読み取り/書き込み配列を返します。配列の最初の項目は定義された状態変数自体であり、2 番目の項目は状態変数を更新するために使用される関数です。規則は、set プレフィックスと状態変数名です。 setState と同様に、setState() 関数は、更新後の特定の値、または更新後の特定の値を返す関数となるパラメータを受け取ります。 setState が関数を受け取ると、古い状態値が受け取った関数にパラメータとして渡され、更新された特定の状態値が取得されます。

1.2 例

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

1.3 注記

  • useStateフックによって返されるsetStateは、オブジェクトの状態のプロパティを自動的にマージしません。
  • setState で受け取ったオブジェクト パラメータのアドレスが変更されていない場合、React はそれを変更されていないとみなすため、ビューは更新されません。

2. リデューサーを使用する

useReducer は useState のアップグレード バージョンです。 useState によって返される書き込みインターフェースでは、最終結果のみを渡すことができ、setN 内では単純な代入操作になります。
つまり、結果を得るための計算処理は関数コンポーネント内のコールバック関数に記述する必要があり、関数コンポーネントのサイズが大きくなるのは間違いありません。また、Flux の考え方(状態を生成する人がさまざまな処理を担当し、他の人が使用できるように処理インターフェイスを公開する)にも従いません。

そのため、React は useState: useReducer よりも高度な状態管理フックを提供しており、これは次のように導入されます。

2.1 使用方法

  • 初期状態値 initialState を作成する
  • すべての操作を含むreducer(state, action)関数を作成し、各操作タイプは新しい状態値を返します。
  • initialStateとreducerに基づいて、const [state, dispatch] = useReducer(reducer, initialState)を使用して読み取りおよび書き込みAPIを取得します。
  • 書き込みインターフェースを呼び出すと、渡されたパラメータはすべてアクションオブジェクトに掛けられます。

2.2 例

React をインポートし、 'react' から { useReducer } を追加します。
'react-dom' から ReactDOM をインポートします。

定数初期状態 = {
  0 です
}

const リデューサー = (状態、アクション) => {
  スイッチ(アクション.type){
    ケース 'addOne':
      戻り値 { n: 状態.n + 1 }
    ケース 'addTwo':
      戻り値 { n: 状態.n + 2 }
    ケース 'addX':
      戻り値 { n: 状態.n + アクション.x }
    デフォルト: {
      新しいエラーをスローします('不明な型')
    }
  }
}

関数App(){
  const [状態、ディスパッチ] = useReducer(リデューサー、初期状態)
  戻る (
    <div>
      私はアプリです
      {状態.n}
      <button onClick={()=>dispatch({type: 'addOne'})}>+1</button>
      <button onClick={()=>dispatch({type: 'addTwo'})}>+2</button>
      <button onClick={()=>dispatch({type: 'addX', x: 5})}>+5</button>
    </div>
  )
}


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

3. コンテキストを使用する

コンテキストとは文脈を意味します。コンテキストはローカルグローバル変数です。ローカルスコープは開発者自身が指定します。

3.1 使用方法

useContext の使用方法は、次の 3 つのステップに分かれています。

  • コンテキストを作成するには、const x = createContext(null) を使用します。通常、作成時に初期値は設定されないため、null になります。通常、コンテキスト スコープが指定されると初期化されます。
  • コンテキストのスコープを設定するには、<x.Provider value={}></x.Provider> を使用します。
  • コンテキストデータを使用するには、スコープ内でconst value = useContext(x)を使用します。

3.2 例

'react' から React、{useState、createContext、useContext } をインポートします。
'react-dom' から ReactDOM をインポートします。

const コンテキスト = createContext(null)

関数App(){
  定数[n, setN] = useState(0)
  戻る (
    <Context.Provider 値 = {{n, setN}}>
      <div>
        <ババ />
        <おじさん />
      </div>
    </コンテキスト.プロバイダー>
  )
}

関数ババ(){
  戻る (
    <div>
      私は父親です<子供 />
    </div>
  )
}

関数Uncle(){
  const {n, setN} = useContext(コンテキスト)
  戻る (
    <div>
      私は叔父です。私が取得したコンテキストデータは{n}です
    </div>
  )
}

関数Child(){
  const {n, setN} = useContext(コンテキスト)
  戻る (
    <div>
      私は息子です。私が取得したコンテキストデータは{n}です
      <ボタンのクリック時={() => setN(n+5)}>
        クリックしてコンテキスト データを変更します</button>
    </div>
  )
}


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

4. 使用効果

効果とは副作用を意味し、環境の変化は副作用です。副作用は関数型プログラミングの概念のようです。よく理解していないので、ここでは詳しく説明しません。
React では、useEffect は各レンダリング後に実行される操作であり、afterRender に相当します。受け取る最初のパラメータはコールバック関数、2 番目のパラメータはコールバックのタイミングです。関数コンポーネントのライフサイクルをシミュレートするために使用できます。

複数の useEffects が同時に出現した場合、出現順に実行されます。

4.1 コンポーネントDidMountをシミュレートする

使用効果(()=>{
  console.log('最初のレンダリング後にのみ実行されます')
},[])

4.2 componentDidMount + componentDidUpdate をシミュレートする

使用効果(()=>{
   console.log('最初のレンダリングを含む各レンダリング後に実行')
})

4.3 依存関係の追加

使用効果(()=>{
    console.log('x が変更された後のみ実行されます。x が undefined から initialValue に最初に変更された場合も含みます')
},[x])
//依存関係が2つある場合は、どちらかの依存関係が変更されたときに実行されます

4.4 コンポーネントWillUnmountをシミュレートする

使用効果(()=>{
  console.log('最初のレンダリングを含む各レンダリング後に実行')
  戻り値 () =>{
    console.log('コンポーネントが破棄されようとしています')
  }
})
//コンポーネントが破棄される前に実行される関数を返すだけです

5.レイアウト効果を使用する

useEffect は、常にブラウザがビューをレンダリングした後に実行されます。useEffect のコールバック関数が DOM ビューに対して動作する場合、最初にビューが初期化され、その後 useEffect のコールバックが実行され、ビューの一部がすぐに変更され、ちらつく状態になります。
このちらつきを回避するには、ブラウザがビューをレンダリングする前に、副作用のコールバック関数を実行します。エフェクト内の DOM を操作するコールバック関数を、DOM がページにマウントされて表示される前に実行すると、ブラウザがページをレンダリングした後にちらつきは発生しません。

layout はビューを意味し、useLayoutEffect はビューが表示される前に実行される副作用です。

useEffect と useLayoutEffect の違いは実行時間です。useLayoutEffect はブラウザーがレンダリングされる前に実行されますが、useEffect はブラウザーがレンダリングされた後に実行されます。ただし、どちらもレンダリング関数の実行中に実行されます。useEffect はレンダリングが完了した後に実行され、useLayoutEffect はレンダリングが完了する前 (ビューがブラウザー ページにレンダリングされていない) に実行されます。

したがって、useLayoutEffect は常に useEffect の前に実行されます。

一般的に、エフェクト内のコールバック関数が DOM ビューの変更を伴う場合は、useLayoutEffect を使用する必要があります。そうでない場合は、useEffect を使用します。

6. 参照

useRef フックは、コンポーネントが継続的にレンダリングされるときに変更されない変数を定義するために使用されます。
コンポーネントがレンダリングされるたびに仮想 DOM が返され、コンポーネント内の対応する変数はその瞬間の仮想 DOM にのみ属します。
useRef フックは、このコンポーネントに対してローカルであり、仮想 DOM の更新履歴全体にわたって保持されるグローバル変数を作成する方法を提供します。
各レンダリング後にuseRefを使用して取得した変数が以前と同じ変数であることを保証するためには、参照を使用することしかできません。したがって、useRefは、このローカルグローバル変数の値を、プロパティ名currentを持つオブジェクトに格納します。

useRefは現在の変更時に自動的にレンダリングされません

useRef は、ref 属性を通じて、作成された Refs オブジェクトを DOM ノードまたは React インスタンスに参照できます。この効果は、React の ref 属性で導入されました。

コンポーネントのローカル グローバル変数としても使用できます。次の例では、ページがレンダリングされた回数を記録します。

関数App(){
  const [状態、ディスパッチ] = useReducer(リデューサー、初期状態)
  定数カウント = useRef(0)
  使用効果(()=>{
    count.current++;
    console.log(`これはページがレンダリングされた ${count.current} 回目です`)
  })
  戻る (
    <div>
      私はアプリです
      {状態.n}
      <button onClick={()=>dispatch({type: 'addOne'})}>+1</button>
      <button onClick={()=>dispatch({type: 'addTwo'})}>+2</button>
      <button onClick={()=>dispatch({type: 'addX', x: 5})}>+5</button>
    </div>
  )
}

7. forwardRef (フックではない)

forwardRefは主に、ref属性をサポートしていないネイティブ関数コンポーネントをラップしてref属性を受け取れるようにするために使用されます。具体的な使用方法については、React—ref属性を参照してください。

forwardRefは関数コンポーネントを受け取り、ref属性を受け取ることができる関数コンポーネントを返します。

8. useMemo && useCallback

React フレームワークは、連続レンダリングによって異なる仮想 DOM を取得し、DOM Diff を実行してページ DOM を選択的に更新します。そのため、レンダリングのたびに、短時間、新しい仮想 DOM と古い仮想 DOM が 2 つ存在することになります。

コンポーネントに子コンポーネントが含まれている場合、親コンポーネントがレンダリングをトリガーすると、子コンポーネントが依存するプロパティが変更されていなくても、親コンポーネントの再レンダリングにより子コンポーネントが再度レンダリングされます。これにより、不要なレンダリングが発生します。

不要なレンダリングを解決するために、React はサブコンポーネントをカプセル化する React.memo() インターフェースを提供します。次のように:

関数App(){
  定数[n, setN] = useState(0)
  定数[m, setM] = useState(0)
  戻る (
    <div>
      私は親コンポーネントnです: {n}
      <button onClick={()=>setN(n+1)}>n+1</button>
      <button onClick={()=>setM(m+1)}>m+1</button>
      <Child value={m}/> // この方法では、子コンポーネントが依存するm値が変更されない場合、子コンポーネントは再レンダリングされません。
    </div>
  )
}

const 子 = React.memo((props)=>{
  使用効果(()=>{
    console.log('サブコンポーネントがレンダリングされました')
  })
  戻る (
  <div>私は子コンポーネントであり、親コンポーネントから受け取る値は m {props.value} です。</div>
  )
})

しかし、上記の方法にはバグがあります。React.memo は、子コンポーネントの依存関係のプロパティが変更されたかどうかを確認するために、前の値と次の値のみを比較します。子コンポーネントが親コンポーネントから受け取った依存関係がオブジェクトの場合、比較はオブジェクトのアドレスになり、オブジェクト内のコンテンツではありません。そのため、親コンポーネントが再レンダリングされるたびに、異なるアドレスのオブジェクトが取得されます。オブジェクト内の値は更新されていませんが、子コンポーネントはアドレスが変更されたことを検出すると再レンダリングします。

この問題を解決するために、useMemo() フックが導入されました。useMemo は、古いコンポーネントと新しいコンポーネントを切り替えるときに関数またはオブジェクトをキャッシュして再利用し、依存関係が再度変更された場合にのみ再生成するために使用されます。

useMemo フックは、引数のない関数 (またはオブジェクト) を返す関数を受け取ります。また、useMemo には、いつ再計算するかを指示する依存関係が必要です。これは、Vue の計算プロパティの原理に多少似ています。次のように:

関数App(){
  定数[n, setN] = useState(0)
  定数[m, setM] = useState(0)
  定数 onClickChild = useMemo(()=>{
    戻り値 () => {
      コンソール.log(m)
    }
  },[m])  
  戻る (
    <div>
      私は親コンポーネントnです: {n}
      <button onClick={()=>setN(n+1)}>n+1</button>
      <button onClick={()=>setM(m+1)}>m+1</button>
      <子の値={m} onClick = {onClickChild}/>
    </div>
  )
}

const 子 = React.memo((props)=>{
  使用効果(()=>{
    console.log('サブコンポーネントがレンダリングされました')
  })
  戻る (
    <div>
      私は子コンポーネントであり、親コンポーネントから次のように値を受け取ります: m {props.value}
      <br/>
      <button onClick={props.onClick}>クリック</button>
    </div>
  )
})

useCallback() は useMemo の構文糖です。useMemo はパラメータなしで関数 (またはオブジェクト) を返す関数を受け取るので、少し奇妙になります。そのため、関数またはオブジェクトを直接受け取るために useCallback が提供されています。

定数 onClickChild = useMemo(() => {
      コンソール.log(m)
  },[m])

9. 使用インペラティブハンドル

useInperativeHandel は ref に関連するフックです。

ref 属性は、渡された Ref オブジェクトの現在のプロパティに現在のコンポーネント インスタンスまたはネイティブ DOM を直接割り当て、関数コンポーネントにはインスタンスがないため、関数コンポーネントは ref 属性を受け取ることができないことがわかっています。しかし、関数コンポーネントが React.forwardRef() によってカプセル化された後に ref を受け取ることができる場合、通常、この ref は関数コンポーネントによって転送された後にネイティブ DOM にアクセスします。しかし、外部 ref が関数コンポーネント内のネイティブ DOM 以外を指すようにしたい場合はどうすればよいでしょうか。関数コンポーネントの ref に、インスタンスを指すクラス コンポーネントの ref のように、より制御可能な操作を持たせることは可能ですか? React は、関数コンポーネントが返された ref によって指されるオブジェクトをカプセル化する方法、つまり useInteractiveHandle フックを提供します。

9.1 例

関数App(){
  定数 myRef = useRef(null)
  使用効果(()=>{
    コンソールログ(myRef.current.real)
    コンソールログ(myRef.current.getParent())
  }, [])
  戻る (
    <div>
      私は親コンポーネントです <Child ref={myRef}/>
    </div>
  )
}

const 子 = forwardRef((props, ref)=>{
  定数childRef = useRef(null)
  命令型ハンドルを使用します(ref, ()=>{
    戻る {
      実数: childRef.current、
      getParent(){
        childRef.current.parentNode を返す
      }
    }
  })
  戻る (
    <div>
      私は子コンポーネントであり、子DOMを持っています
      <button ref={childRef}>ボタン</button>
    </div>
  )
})

10. カスタムフック

カスタム フックはカスタム関数です。この関数は use で始まる必要があり、関数内ではネイティブ Ract フックを使用する必要があります。戻り値は通常、フックの読み取りおよび書き込みインターフェースを公開するために使用される配列またはオブジェクトです。

カスタム フックは通常、関数コンポーネントで複数回使用されるフックを統合します。関数コンポーネントで複数のフック操作を行わないようにしてください。

以上がReact Hooksを完全に理解するための30分の詳細内容です。React Hooksを完全に理解するための詳細については、123WORDPRESS.COMの他の関連記事に注目してください。

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

<<:  MacBook 向け Python 3.7 インストール チュートリアル

>>:  MySQL並列レプリケーションの簡単な説明

推薦する

Linux で ffmpeg をインストールするための詳細なチュートリアル

1. CentOS Linuxにffmpegをインストールする1.ダウンロードして解凍する http...

MySQL SQL ステートメント分析とクエリ最適化の詳細な説明

パフォーマンスの問題のあるSQL文を取得する方法1. ユーザーからのフィードバックを通じてパフォーマ...

MySQL InnoDBストレージエンジンについて簡単に説明します

序文:ストレージ エンジンはデータベースの中核です。MySQL の場合、ストレージ エンジンはプラグ...

VUEはFlappy Birdゲームのサンプルコードを実装します

Flappy Bird は、誰もがアプリでプレイしたことがある非常にシンプルな小さなゲームです。ここ...

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

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

データベースのインデックス作成に関する知識ポイントのまとめ。必要な情報はすべてここにあります。

データベースインデックスについては皆さんもよくご存知だと思います。 インデックスは、データベース テ...

ランダムな文字を生成する Java サンプルコード

サンプルコード: java.util.Random をインポートします。 java.util.UUI...

Linux サーバーが処理できる接続数をご存知ですか?

序文まず、TCP 接続を識別する方法を見てみましょう。システムは、(src_ip、src_port、...

静的ウェブサイトをRSSに変換するツール

<br /> この記事は allwebdesignresources.com から Ra...

HTML タグでの this の使用法の紹介

例えば:コードをコピーコードは次のとおりです。 <html> <ヘッド> &...

Winにmysqlをインストールする詳細な手順

この記事では、参考までにWinにmysqlをインストールする詳細な手順を紹介します。具体的な内容は次...

Docker データボリュームの一般的な操作コードの例

開発者が Dockerfile を使用してイメージをビルドする場合は、イメージをビルドするときにデー...

MySQL データベースのインストールと Navicat for MySQL の使用に関するチュートリアル

MySQL は、スウェーデンの会社 MySQL AB によって開発され、現在は Oracle が所有...

擬似静的およびクライアント適応型 Nginx の設定方法

バックエンドは thinkphp3.2.3 フレームワークを使用します。他の言語を使用している場合は...