React HooksAPIの使用を開始する

公開: 2022-03-10
簡単な要約↬このチュートリアルでは、Reactフックとは何か、使用可能な基本的なReactフック、およびReactアプリケーション用にそれらを作成する方法の例を学習して理解します。 その過程で、React 16.8に同梱されていたいくつかの追加のフックと、独自のカスタムReactフックの作成方法についても知ることができます。

React 16.8が2019年2月初旬に正式にリリースされたとき、クラスを作成せずにReactの状態やその他の機能を使用できるようにする追加のAPIが付属しています。 この追加のAPIはフックと呼ばれ、オープンソースプロジェクトから本番アプリケーションでの使用まで、Reactエコシステムで人気が高まっています。

Reactフックは完全にオプトインです。つまり、既存のコードを書き直す必要はなく、重大な変更は含まれていません。また、React16.8のリリースで使用できます。 好奇心旺盛な開発者の中には、正式にリリースされる前からHooks APIを利用している人もいますが、当時は安定しておらず、実験的な機能にすぎませんでした。 現在は安定しており、React開発者が使用することをお勧めします。

ReactやJavaScript全般については説明しません。 このチュートリアルを実行する際には、ReactJSとJavaScriptに関する十分な知識が役立ちます。

Reactフックとは何ですか?

Reactフックは、React開発者が機能コンポーネント内で状態メソッドとライフサイクルメソッドを使用できるようにする組み込み関数であり、既存のコードと連携して動作するため、コードベースに簡単に採用できます。 フックが一般に公開された方法は、開発者が機能コンポーネントで状態を使用できるようにすることでしたが、内部では、フックはそれよりもはるかに強力です。 これにより、React開発者は次のメリットを享受できます。

  • コードの再利用の改善。
  • より良いコード構成;
  • より良いデフォルト;
  • カスタムフックを使用して非ビジュアルロジックを共有する。
  • componentsツリーを上下に移動する際の柔軟性。

React Hooksを使用すると、開発者は、UIのレンダリングから、状態やロジックの処理まで、必要なほとんどすべての機能コンポーネントを使用できるようになります。これは非常に優れています。

Reactフックのリリースの背後にある動機

ReactJSの公式ドキュメントによると、Reactフックのリリースの背後にある動機は次のとおりです。

  • コンポーネント間でステートフルロジックを再利用することは困難です。
    フックを使用すると、アーキテクチャや構造を変更せずに、コンポーネント間でロジックを再利用できます。
  • 複雑なコンポーネントは理解しにくい場合があります。
    コンポーネントが大きくなり、多くの操作を実行すると、長期的には理解しにくくなります。 フックは、ライフサイクルメソッドに基づいて分割を強制するのではなく、特定の単一コンポーネントを、この分離されたコンポーネントのどの部分が関連しているか(サブスクリプションの設定やデータのフェッチなど)に基づいて、さまざまな小さな関数に分離できるようにすることでこれを解決します。
  • クラスはかなり混乱しています。
    クラスはReactを適切に学習する上での障害です。 他の言語とは異なり、JavaScriptでthisがどのように機能するかを理解する必要があります。 React Hooksは、開発者がクラスを使用せずにReactの最高の機能を使用できるようにすることで、この問題を解決します。
ジャンプした後もっと! 以下を読み続けてください↓

フックのルール

フック提案のドキュメントで概説されているReactコアチームによって述べられているように、厳密に遵守されるべき2つの主要なルールがあります。

  • ループ、条件、またはネストされた関数内でフックを使用しないようにしてください。
  • React関数内からのみフックを使用してください。

基本的なReactフック

React 16.8に同梱されていた10個の内蔵フックがありますが、基本的な(一般的に使用される)フックには次のものがあります。

  • useState()
  • useEffect()
  • useContext()
  • useReducer()

これらは、コードベースにReactフックを採用したReact開発者が一般的に使用する4つの基本的なフックです。

useState()

useState()フックを使用すると、React開発者は、クラスコンポーネントに変換しなくても、機能コンポーネント内の状態を更新、処理、および操作できます。 以下のコードスニペットを使用してみましょう。これは単純なAgeカウンターコンポーネントであり、 useState()フックの機能と構文を説明するために使用します。

 function App() { const [age, setAge] = useState(19); const handleClick = () => setAge(age + 1) return <div> I am {age} Years Old <div> <button onClick={handleClick}>Increase my age! </button> </div> </div> }

お気づきの方もいらっしゃると思いますが、私たちのコンポーネントは非常にシンプルで簡潔に見え、機能的なコンポーネントになり、クラスコンポーネントのような複雑さもありません。

useState()フックは、引数として初期状態を受け取り、JavaScriptで配列の破棄を利用することにより、配列内の2つの変数にwhatという名前を付けることができます。 最初の変数は実際の状態であり、2番目の変数は新しい状態を提供することによって状態を更新することを目的とした関数です。

完成したReactアプリ(大プレビュー)

これは、Reactアプリケーションでレンダリングされたときにコンポーネントがどのように見えるかを示しています。 「年齢を増やす」ボタンをクリックすると、年齢の状態が変化し、コンポーネントは状態のあるクラスコンポーネントと同じように機能します。

useEffect()

useEffect()フックは、効果的なコードを含む関数を受け入れます。 機能コンポーネントでは、ミューテーション、サブスクリプション、タイマー、ロギング、その他の効果を機能コンポーネント内に配置することは許可されていません。配置すると、UIのレンダリング時に多くの不整合が発生し、バグが混乱するためです。

useEffect()フックを使用すると、渡された実効関数は、レンダリングが画面に表示された直後に実行されます。 エフェクトは基本的に、Reactの機能的な方法とはまったく異なるUIを構築するための必須の方法に覗き見されます。

デフォルトでは、エフェクトは主にレンダリングが完了した後に実行されますが、特定の値が変更されたときにもエフェクトを起動するオプションがあります。

useEffect()フックは、主に、ブラウザー/ DOMAPIまたは外部APIのようなデータフェッチやサブスクリプションとの相互作用に通常使用される副作用に使用されます。 また、Reactライフサイクルメソッドがどのように機能するかをすでに理解している場合は、 useEffect()フックをコンポーネントのマウント更新アンマウントとして考えることもできます。これらはすべて1つの関数にまとめられています。 これにより、機能コンポーネントでライフサイクルメソッドを複製できます。

以下のコードスニペットを使用して、 useEffect()フックを使用して実行できる最も基本的な方法を説明します。

ステップ1:アプリケーションの状態を定義する

import React, {useState} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

useState()フックを使用して機能コンポーネント内の状態を処理する方法について前のセクションで説明したように、コードスニペットでそれを使用して、フルネームをレンダリングするアプリの状態を設定しました。

ステップ2:useEffectフックを呼び出す

import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({FirstName: 'Shedrack', surname: 'Akintayo'}) }, [])//pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

これで、 useEffectフックがインポートされ、 useEffect()関数を使用して、nameプロパティとsurnameプロパティの状態が非常に簡潔に設定されました。

空の配列である2番目の引数のuseEffectフックに気づいたかもしれません。 これは、依存関係のリストを持たないsetFullNameへの呼び出しが含まれているためです。 2番目の引数を渡すと、更新の無限のチェーン( componentDidUpdate() )が防止され、 useEffect()フックがcomponentDidMountライフサイクルメソッドとして機能し、ツリー内のすべての変更で再レンダリングせずに1回レンダリングできるようになります。

Reactアプリは次のようになります。

useEffectフックを使用してアプリを反応させる(大プレビュー)

次のように、setTitle( setTitle()関数を呼び出すことにより、 useEffect()関数内でアプリケーションのtitleプロパティを変更することもできます。

 import React, {useState, useEffect} from 'react'; function App() { //Define State const [name, setName] = useState({firstName: 'name', surname: 'surname'}); const [title, setTitle] = useState('BIO'); //Call the use effect hook useEffect(() => { setName({firstName: 'Shedrack', surname: 'Akintayo'}) setTitle({'My Full Name'}) //Set Title }, [])// pass in an empty array as a second argument return( <div> <h1>Title: {title}</h1> <h3>Name: {name.firstName}</h3> <h3>Surname: {name.surname}</h3> </div> ); }; export default App

アプリケーションが再レンダリングされた後、新しいタイトルが表示されます。

完成したプロジェクト(大プレビュー)

useContext()

useContext()フックは、コンテキストオブジェクト、つまりReact.createContextから返される値を受け入れ、そのコンテキストの現在のコンテキスト値を返します。

このフックにより、機能コンポーネントはReactアプリのコンテキストに簡単にアクセスできます。 useContextフックが導入される前は、クラスコンポーネント内のプロバイダーから渡されたグローバル状態にアクセスするために、 contextTypeまたは<Consumer>を設定する必要がありました。

基本的に、 useContextフックはReact Context APIと連携します。これは、アプリのプロップをさまざまなレベルに手動で渡す必要なしに、アプリ全体でデータを深く共有する方法です。 現在、 useContext()を使用すると、Contextの使用が少し簡単になります。

以下のコードスニペットは、Context APIがどのように機能し、 useContextがどのようにそれを改善するかを示しています。

コンテキストAPIを使用する通常の方法

import React from "react"; import ReactDOM from "react-dom"; const NumberContext = React.createContext(); function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); } function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

次に、コードスニペットを分解して、各概念を説明しましょう。

以下では、 NumberContextというコンテキストを作成しています。 これは{ Provider, Consumer } 2つの値を持つオブジェクトを返すことを目的としています。

 const NumberContext = React.createContext();

次に、作成したNumberContextから返されたProvider値を使用して、すべての子が特定の値を使用できるようにします。

 function App() { return ( <NumberContext.Provider value={45}> <div> <Display /> </div> </NumberContext.Provider> ); }

これにより、作成したNumberContextから返されたConsumer値を使用して、すべての子が利用できるようにした値を取得できます。 お気づきの方もいらっしゃると思いますが、このコンポーネントは小道具を取得していません。

 function Display() { return ( <NumberContext.Consumer> {value => <div>The answer to the question is {value}.</div>} </NumberContext.Consumer> ); } ReactDOM.render(<App />, document.querySelector("#root"));

コンテンツをNumberContext.Consumerでラップし、render propsメソッドを使用して値を取得してレンダリングすることにより、 AppコンポーネントからDisplayコンポーネントに値を取得する方法に注意してください。

すべてがうまく機能し、使用したrender propsメソッドは動的データを処理するための非常に優れたパターンですが、長い目で見れば、慣れていない場合は不要なネストと混乱が生じます。

useContextメソッドの使用

useContextメソッドを説明するために、useContextフックを使用してDisplayコンポーネントを書き直します。

 // import useContext (or we could write React.useContext) import React, { useContext } from 'react'; // old code goes here function Display() { const value = useContext(NumberContext); return <div>The answer is {value}.</div>; }

価値を表示するために必要なのはこれだけです。 かなりきちんとしていますよね? useContext()フックを呼び出して、作成したコンテキストオブジェクトを渡し、そこから値を取得します。

注: useContextフックに渡される引数は、コンテキストオブジェクト自体である必要があり、useContextを呼び出すコンポーネントは、コンテキスト値が変更されると常に再レンダリングされることを忘れないでください。

useReducer()

useReducerフックは、複雑な状態と状態の遷移を処理するために使用されます。 reducer機能と初期状態入力を取り入れます。 次に、現在の状態と、配列の破棄によって出力されたdispatch関数を返します。

以下のコードは、 useReducerフックを使用するための適切な構文です。

 const [state, dispatch] = useReducer(reducer, initialArg, init);

これは、 useStateフックの一種の代替手段です。 通常、複数のサブ値に関係する複雑な状態ロジックがある場合、または次の状態が前の状態に依存している場合は、 useStateを使用することをお勧めします。

利用可能な他のReactフック

useCallback このフックは、メモ化され、依存関係ツリーの1つの依存関係が変更された場合にのみ変更されるコールバック関数を返します。
useMemo このフックはメモ化された値を返します。「作成」関数と依存関係の配列を渡すことができます。 返される値は、依存関係ツリーの依存関係の1つが変更された場合にのみ、メモ化された値を再度使用します。
useRef このフックは、 .currentプロパティが渡された引数( initialValue )に初期化された可変refオブジェクトを返します。 返されたオブジェクトは、コンポーネントの存続期間中ずっと利用できます。
useImperativeHandle このフックは、Reactで参照を使用するときに親コンポーネントで使用できるようになるインスタンス値をカスタマイズするために使用されます。
useLayoutEffect このフックはuseEffectフックに似ていますが、すべてのDOMミューテーションの後に同期的に起動します。 また、 componentDidUpdateおよびcomponentDidMountと同じ方法でレンダリングされます。
useDebugValue このフックは、React DevToolsでカスタムフックのラベルを表示するために使用できます。 これは、React DevToolsを使用したデバッグに非常に役立ちます。

カスタムReactフック

「カスタムフック」は、名前の前に「 use 」という単語が付いたJavaScript関数であり、他のフックを呼び出すために使用できます。 また、コンポーネントロジックを再利用可能な関数に抽出することもできます。 これらは、内部の他のフックを利用できる通常のJavaScript関数であり、複数のコンポーネント内で利用できる共通のステートフルロジックも含まれています。

以下のコードスニペットは、無限スクロールを実装するためのカスタムReactフックの例を示しています(Paulo Levyによる)。

 import { useState } from "react"; export const useInfiniteScroll = (start = 30, pace = 10) => { const [limit, setLimit] = useState(start); window.onscroll = () => { if ( window.innerHeight + document.documentElement.scrollTop === document.documentElement.offsetHeight ) { setLimit(limit + pace); } }; return limit; };

このカスタムフックは、 startpaceの2つの引数を受け入れます。 start引数はレンダリングされる要素の開始数であり、pace引数はレンダリングされる後続の要素数です。 デフォルトでは、 start引数とpace引数はそれぞれ3010に設定されています。つまり、引数なしで実際にフックを呼び出すことができ、代わりにこれらのデフォルト値が使用されます。

したがって、Reactアプリ内でこのフックを使用するには、「偽の」データを返すオンラインAPIで使用します。

 import React, { useState, useEffect } from "react"; import { useInfiniteScroll } from "./useInfiniteScroll"; const App = () => { let infiniteScroll = useInfiniteScroll(); const [tableContent, setTableContent] = useState([]); useEffect(() => { fetch("https://jsonplaceholder.typicode.com/todos/") .then(response => response.json()) .then(json => setTableContent(json)); }, []); return ( <div style={{ textAlign: "center" }}> <table> <thead> <tr> <th>User ID</th> <th>Title</th> </tr> </thead> <tbody> {tableContent.slice(0, infiniteScroll).map(content => { return ( <tr key={content.id}> <td style={{ paddingTop: "10px" }}>{content.userId}</td> <td style={{ paddingTop: "10px" }}>{content.title}</td> </tr> ); })} </tbody> </table> </div> ); }; export default App;

上記のコードは、無限スクロールフックを使用して画面にデータの初期数を表示する偽のデータ( userIDtitle )のリストをレンダリングします。

結論

このチュートリアルを楽しんでいただけたでしょうか。 以下のリファレンスから、Reactフックの詳細をいつでも読むことができます。

ご不明な点がございましたら、コメント欄にご記入ください。喜んでお答えいたします。

この記事のサポートリポジトリはGithubで入手できます。

リソースと参考資料

  • 「フックAPIリファレンス」、React.jsドキュメント
  • 「Reactフックとは何ですか?」Robin Wieruch
  • useContextフックのしくみ」、Dave Ceddia
  • 「Reactフック: useEffect()の使用方法」、Hossein Ahmadi、Medium
  • 「独自のカスタムReactフックを作成する」、Aayush Jaiswal、Medium
  • 「Reactフックのレシピを理解しやすい」、Gabe Ragland、useHooks()