こんにちは、カツヒロです。
普段はバックエンドのエンジニアとして仕事をしています。
React 16.8から正式に追加された新機能’React Hooks‘。
フック (hook) は React 16.8 で追加された新機能です。state などの React の機能を、クラスを書かずに使えるようになります。 – フックの導入
Reactエンジニアにはすでに馴染みの機能のようですが、バックエンドを主戦場にしていたぼくにとっては少し倦厭していた技術でした。しかし、ひとたび勉強して使用すると、便利さに驚愕しました。
今回はそんなReact Hooksについて、以下の通りまとめていきます。
- Hooksのメリット
- 基本の使い方
React Hooksの基本は、この記事を読めば理解できると思います。
React Hooksのメリット
従来のコンポーネントの問題点
簡単に説明すると、React Hooksは「Reactの関数型コンポーネントで’state’を使用できる機能」です。
従来のReactコンポーネントで状態管理を使用する際のベストプラクティスは、クラス型コンポーネントを使用することでした。しかし、従来のコンポーネントはReact Hooks開発の動機にも書かれているように、いくつかの問題を抱えていました。
- ステートフルなロジックをコンポーネント間で再利用するのは難しい
- 複雑なコンポーネントは理解しづらくなる
- クラスは人間と機械の両方を混乱させる
つまりは
- 関数型のコンポーネントに’state’を導入するためのコストが高い
- コンポーネント内にネストが多すぎて、理解ができない
という問題点が、開発者やコードの中で散見されたということです。
(上記の諸問題は、リンクにて詳しく説明されています。)
解決策としてのReact Hooks
そこで、上記の問題を解決するために開発されたのが’React Hooks‘です。
導入することで、下記のようなメリットが享受できます。
- クラスコンポーネントを減らせる
- props、stateの管理を減らせる
- 関数型コンポーネントのリファクタリングがしやすくなる
クラスコンポーネントを減らせる
上記でも何度か書かれていますが、Reactのコンポーネントでは、2種類の記法が存在します。
- クラス型コンポーネント
- 関数型コンポーネント
クラス型コンポーネント
クラス型コンポーネントは、オブジェクト志向のクラスから作成されたコンポーネントです。 従来のReactでは、状態管理やライフサイクルを使用する際には、クラス型コンポーネントの使用を指定されていました。
下記は、クラス型コンポーネントの例です。
import React, {Component} from 'react'; export default class App extends Component { render() { return ( <div>hoge</div> ) } }
関数型コンポーネント
関数型コンポーネントは、「状態を持たず、レンダリングするだけのコンポーネント」に使用されていました。コードを記述する量は、クラス型コンポーネントと比べると圧倒的に少ないですが、stateを持つことができませんでした。
下記は、関数型コンポーネントの例です。
import React from 'react'; const App = () => { return ( <div>hoge</div> ) } export default App
従来では、「状態を持たずpropsで与えられたものを出力する」といった場合のみに使われるのが関数型コンポーネントでした。
React Hooksが与えた影響
React Hooksが登場したことで、関数型コンポーネントでもstate(状態管理)を使用可能になりました。
もともと、関数型コンポーネントの方が記述量として少ないので、大幅にコードを少なくできるようになりました。個人的にも、状態管理が必要なコンポーネントは冗長なクラス型で書いていたこともあり、簡潔に書くことができるReact Hooksの恩恵をとても感じています(体感的にではありますが、コンポーネントの記述量は2/3くらいになるのではないでしょうか。。)
props、stateの管理を減らせる
Hooksが開発される以前のコンポーネントでは、Reduxを使用していたとしても、propsを使用してのバケツリレーになることが多々ありました。 stateを一括管理できるStoreを使用していたとしても、結局はHigh-Order Componentなどの手法を使用する必要がありました。 しばしば、このような手法は開発者の理解を妨げていました。
しかし、Hooksを使用することで、Reduxの使用もより効率的になりました。「stateをStoreでの一元管理」というReduxの基本概念がより活かせるようになります。
関数型コンポーネントのリファクタリングがしやすくなる
従来は、関数型コンポーネントのリファクタリングの際に非常に手間がかかっていました。
つまり、関数型をステートフルなコンポーネントに修正する際には、必ずクラス型にリファクタリングしなくてはなりませんでした。これは、1度組んだコンポーネントを組み替え、ほとんど新しいコンポーネントを作成することと同じでした。 しかし、Hooksを使用すると、かんたんにステートフルな関数型コンポーネントにリファクタリングが可能です。既存の階層を変更することなくリファクタリングができ、Reactの実用性を犠牲にしません。
React Hooksの基本の使い方
基本的なHooksのルール
便利そうに見えるHooksですが、もちろん最低限のルールは存在します。
- フックを呼び出すのはトップレベルのみ
- フックを呼び出すのは React の関数内のみ
フックを呼び出すのはトップレベルのみ
ループや条件分岐やネストした関数の中でフックを呼び出さないでください。
フックを呼び出すのは React の関数内のみ
通常のJavaScript 関数内ではReact Hookを使用しないでください。Hooks は関数型コンポーネント内でのみ利用できます。
上記の2つだけ抑えていれば、基本的には問題ありません。
基本的なフックとその使い方
- クラス無しでstateを使えるuseState
- クラス無しでライフサイクルを使えるuseEffect
1. クラス無しでstateを使えるuseState
useState
はもっとも基本的なフックです。
import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [ count, setCount ] = useState(0); return ( <div> <p>You clicked { count } times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
上記の例では、関数コンポーネントの中でローカルな state を使うために呼び出しています。buttonタグがクリックされた回数をstateとして保存し、更新もできます。
import React, { useState } from 'react'; function Example() { // Declare a new state variable, which we'll call "count" const [ count, setCount ] = useState(0); const increment = () => { // もちろんメソッドでも機能を実装できる setCount(previousCount => previousCount + 1); } return ( <div> <p>You clicked { count } times</p> <button onClick={ increment }> Click me </button> </div> ); }
上記のように、メソッドを設定しての宣言も可能です。その際、引数に以前の情報(ここではpreviousCount)をとることができ、複雑な処理も行うことが可能です。
2. クラス無しでライフサイクルを使えるuseEffect
クラスコンポーネントにおける componentDidMount
, componentDidUpdate
および componentWillUnmount
と同じようなライフサイクルメソッドが使用できるフックがuseEffect
です。
import React, { useState, useEffect } from 'react'; function Example() { const [ count, setCount ] = useState(0); // Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${ count } times`; }); return ( <div> <p>You clicked { count } times</p> <button onClick={() => setCount(count + 1)}> Click me </button> </div> ); }
上記のコンポーネントは React が DOM を更新した後で、HTML ドキュメントのタイトルを設定するコンポーネントです。useEffect
は、DOM への更新を反映した後に定義した「副作用関数」を実行するように React に指示します。
上記のコードでは、componentDidMount
, componentDidUpdate
の副作用が機能してしまいますが、もちろん別個に設定することも可能です。
componentDidMount
のみ使用したい場合
// Similar to componentDidMount: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${ count } times`; }, []);
useEffectの第二引数に空の配列を取ると、componentDidMount
と同様の動きをします。
componentDidUpdate
のみ使用したい場合
// Similar to componentDidMount and componentDidUpdate: useEffect(() => { // Update the document title using the browser API document.title = `You clicked ${ count } times`; }, [ count ]);
useEffectの第二引数を取るまでは上記と同じです。第二引数に特定のstateを入れる(上記では[ count ])と、指定したstateに変化があった場合のみ再描画されます。
まとめ
React Hooksのメリット、並びにHooksの基本の使い方についてまとめました。
Hooksを使用することで、コードの量が格段に減り、可読性やメンテナンスの効率も上がります。基本的には、HooksでReactの機能をかんたんに実装できるようになったので、すすんでReact Hooksを使用してみてははいかがでしょうか。
今後も、ReactやJavaScriptについては記事を書いていきますので、どうぞご贔屓にお願いします!
コメントを残す