React HooksAPIの使用を開始する
公開: 2022-03-10React 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アプリケーションでレンダリングされたときにコンポーネントがどのように見えるかを示しています。 「年齢を増やす」ボタンをクリックすると、年齢の状態が変化し、コンポーネントは状態のあるクラスコンポーネントと同じように機能します。
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アプリは次のようになります。
次のように、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; };
このカスタムフックは、 start
とpace
の2つの引数を受け入れます。 start引数はレンダリングされる要素の開始数であり、pace引数はレンダリングされる後続の要素数です。 デフォルトでは、 start
引数とpace
引数はそれぞれ30
と10
に設定されています。つまり、引数なしで実際にフックを呼び出すことができ、代わりにこれらのデフォルト値が使用されます。
したがって、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;
上記のコードは、無限スクロールフックを使用して画面にデータの初期数を表示する偽のデータ( userID
とtitle
)のリストをレンダリングします。
結論
このチュートリアルを楽しんでいただけたでしょうか。 以下のリファレンスから、Reactフックの詳細をいつでも読むことができます。
ご不明な点がございましたら、コメント欄にご記入ください。喜んでお答えいたします。
この記事のサポートリポジトリはGithubで入手できます。
リソースと参考資料
- 「フックAPIリファレンス」、React.jsドキュメント
- 「Reactフックとは何ですか?」Robin Wieruch
- 「
useContext
フックのしくみ」、Dave Ceddia - 「Reactフック:
useEffect()
の使用方法」、Hossein Ahmadi、Medium - 「独自のカスタムReactフックを作成する」、Aayush Jaiswal、Medium
- 「Reactフックのレシピを理解しやすい」、Gabe Ragland、useHooks()