はじめに
初めまして!
エンジニアになって数年、今まで本を読むだけでしたが、もっとプライベートで楽しみながら成長したい!自分が学んだ足跡を残していきたい!と思い記事を書きました!
最終的には自在に開発できるようになりたいと思っています。
いろいろな記事を参考にさせてもらっています。
その中でもこれってどういう意味?とかつまづいたところを念入りに書いていこうかと思います。
今回の目的
React Hookとは何か学びたかったため学べる本があったのでそちらの本の内容を自分が噛み砕いて読めるようにまとめました!より詳しい内容が参考書籍に書いてあるのでよかったらお読みください!
使用したものや事前準備
・Macbook Pro
・Visual Studio Code
主に参考にさせていただいた記事
「React Hooks 入門: フックの基礎や使い所をしっかり理解して使いこなす」
ReactHookとは
関数コンポーネントで使用できる関数です。クラスコンポーネントで複雑化した書き方を簡潔にできるようにしたものと捉えています。
useState
stateと更新関数を渡すhookです。
stateは、constでいれられる値、オブジェクト、配列、関数(アロー関数を含む)など格納できます。
初期化
const [count,setCount] = useState(0);
セット関数の場合、アロー関数で現在のStateを引数として扱える。
setCount(currentCount => currentCount + 1)
stateのレンダリングタイミング
値やオブジェクト({}で囲まれたやつ)、配列が更新された時にレンダリングされる。
但し、オブジェクトと配列については、内部の値が変更されても、参照値が変わらなければ更新されたとみなさない。
レンダリングさせたい場合は、スプレッド演算子でコピーと作成をし、更新したい値を上書きする。または、細分化してState管理する。
useEffect
依存配列はstateに限らず値や関数も入る。配列なので複数の値を設定でき、どれか一つでも変化すれば副作用が実行される。
useEffect(() => {
// 副作用を実行するコード
}, [依存配列]);
またレンダリングされるたびに実行したい場合は依存配列を記述しないことで実現できる
useEffect(() => {
// 副作用を実行するコード
});
依存配列に何も設定しなかった場合は、最初のレンダリングの時のみ副作用を実行する。
useEffect(() => {
// 副作用を実行するコード
}, []);
ポイント
副作用を利用して、検索値が変更されたときだけAPIを呼び出したり、API呼び出し中は関連する箇所を非表示にしたり、更に依存配列で更新の度に処理を動かすなど工夫できる。
クリーンアップ関数
アンマウント、副作用実行時に実行されるもので、return内に記述。APIの呼び出しやタイマーなどコンポーネントから離れた実行を制御する時に使う。
useRef
値が変更されてレンダリングしたくないものに対して使う。外部APIの参照など。
useStateで対応できる場合は無理に使用しなくていい。
React.memo / useCallback / useMemo
React.memo
propsで渡される主に値をメモ化する。
コンポーネントのpropsをメモ化するAPI。キャッシュするようなもの。
レンダーコストが高い・レンダリング頻度の多いコンポーネントに対して行うものであり、何に対しても使うものではない。
propsは参照値を比較している。同値でも再生成されていれば違うものと判定される。オブジェクトだと参照値が変わらないこともあり、memoに引っかからずレンダリングされないから注意。また、関数も参照値のため再生成されたら再レンダリングされる(関数にはuseCallbackを使用する)
下記の例ではアロー関数を引数とし、propsに変化があればレンダリングする。
const Hello = React.memo(({ name }) => { return <h1>Hello {name}</h1>; });
useCallback
関数をメモ化する。
依存している値が更新されれば、関数が再生成される。constとして定義して、呼び出し位置に配置する。
const test = useCallback(コールバック関数, [依存配列]);
関数の再生成に対して防ぐのみなので、ハンドリング関数を使ってpropsを渡している構成であれば、親コンポーネントの再レンダリングにも対応できるようにReact.memoと同時に使うのが効果的
useMemo
関数の結果をメモ化する。
依存配列で定義した関数内の値が変更されない限り再生成しない。こちらもオブジェクト内の変更に対しては検知しないので、スプレッド演算子を使って再生成するなら工夫が必要。
const [count, setCount] = useState(0);
const Count = useMemo(() => double(count), [count]);
useReducer
stateとdispatchを返すフック
useStateと似ているが、dispatchに紐づけられた関数の戻り値でセットする値が決まる。
複雑なオブジェクト(持っている情報が多いなど)を更新する場合、操作内容を集約できる。
//dispatchはreducer関数に渡すアクション値を引数にもつ
//reducerはstateとactionを引数にもつ関数
const [state, dispatch] = useReducer(reducer, { count: 0 });
Context / useContext
Context
Contextで渡した値は階層関係にあるコンポーネントでグローバルステートとして扱える。深い階層へのバケツリレー問題を解消できる。Reactは単方向データフローなため、そこは注意する。(高階層から低階層)
ポイント
直接定義するよりも、Stateをすべてのコンポーネントで連携して使用したい時など親コンポーネントでsetStateしその値をvalueに入れる方法もある。
// 定義方法
const MyContext = createContext();
<MyContext.Provider value={name}>
{/*ここで定義されたコンポーネントは使用できる*/}
<Child />
</MyContext.Provider>
// 取得
const text = useContext(MyContext);
下記のように孫コンポーネント以降も使用できる。
import React, { createContext, useContext } from 'react';
// Contextの作成
const MyContext = createContext();
function App() {
return (
<MyContext.Provider value="Hello, Context!">
<Child />
</MyContext.Provider>
);
}
function Child() {
return (
<Grandchild />
);
}
function Grandchild() {
// useContextフックを使用してContextの値にアクセス
const value = useContext(MyContext);
return <div>{value}</div>;
}
カスタムフック
useStateのような部分を独自関数で定義できる。
コンポーネント名は頭文字大文字の例外として「use」から命名する。
最後に
Hooksって言葉で難しそうで敬遠していましたが整理すると便利なものが多くいい勉強になりました!