これはなに?
React初学者の私がフロントエンドになるための第一弾!
この記事では、ReactのhooksであるuseCallbackについて学んできました!
とりあえず、useCallbackってなんなん?
useCallbackってなんなんということですが...
👉結論: パフォーマンス向上のためのhooksです!
ありがとうございました!!
と、いきたいところなのですが、詳細書いていきたいと思います。
useCallbackとは、関数をメモ化することができます。
メモ化とは、いわばキャッシュです。(多分)
Reactでは、親コンポーネントの再描画によって、
変更のない子コンポーネントまで再描画されてしまうことがしばしばあります。
そんな時に使うのが、useCallbackです。
では、関数をメモ化するとはいったいどういうことなのでしょう。
関数をメモ化するとは?
まず、サンプルとして以下のコードを見てみましょう。
const updateCountA1 = () => {
setCountA((prev) => prev + 1);
};
const updateCountA2 = () => {
setCountA((prev) => prev + 1);
};
Object.is(updateCountA1, updateCountA2)
上記の場合、Object.is()の返り値は何になるでしょう。
一見、updateCountA1とupdateCountA2は、
まったく同一の処理を行なっているため、trueが返ってくるように思えます。
が、実際の返り値はfalseとなり、異なるオブジェクトとして判定されます。
これでは、コンポーネントが描画される度に関数が定義されてしまい、パフォーマンスの悪化に繋がります。
そこで活躍するのが、今回のuseCallbackとなるわけです。
では、早速useCallbackの書き方を見ていきましょう。
useCallbackの書き方
ここでは、onClickなどで使う関数を想定してみます。
import { useCallback } from 'react'
~~~
const handleClick = useCallback(() => {
doSomething(a, b);
},[a, b]);
useCallbackはhooksなのでreactからimportが必要です。
では関数の構成を見ていきましょう。
const handleClick = useCallback(() => {
//第一引数 コールバック関数
doSomething(a, b);
},
//第二引数 依存配列
[a, b]);
useCallbackは以下のような構成になっています。
第一引数 コールバック関数
第一引数には実行したい関数を記述します。
今回の例でいえばonClickで実行する関数にあたります。
doSomething(a, b)の関数が実行されます。
第二引数 依存配列
第二引数には依存配列を記述します。
依存配列が空にする場合
依存配列は[]のように空にすることも可能です。
const Parent = () => {
const [countA, setCountA] = useState(0);
const updateCountA = useCallback(() => {
setCountA(countA + 1);
}, []);
return (
<div>
<button onClick={updateCountA}>countup A</button>
<p>A: {countA}></p>
</div>
);
};
依存配列を空にした場合は、初回実行時に関数が定義されます。
この場合、updateCountA内のcountAの値は初回実行時の1の値でメモ化されるため、
何度updateCountAの関数を実行しても、countAの値は1のままとなります。
依存配列に値を入れる場合
const Parent = () => {
const [countA, setCountA] = useState(0);
const updateCountA = useCallback(() => {
setCountA(countA + 1);
}, [countA]);
return (
<div>
<button onClick={updateCountA}>countup A</button>
<p>A: {countA}></p>
</div>
);
};
依存配列に格納されている値が変化した場合のみ、関数が再定義されます。
この場合、依存配列にcountAが格納されているため、countAの値が更新されるたびに、
updateCountAの関数は再定義されます。
そのため、countAの値はカウンターの役目を果たすことができます。
実際に使ってみるZE★
useCallbackを使わない場合
import React, { useCallback, useState } from "react";
import Child from "./Child";
const Parent = () => {
console.log("親コンポーネントrendar");
const [countA, setCountA] = useState(0);
const [countB, setCountB] = useState(0);
const updateCountA = () => {
setCountA((prev) => prev + 1);
};
const updateCountB = () => {
setCountB(countB + 1);
};
return (
<div>
<button onClick={updateCountA}>countup A</button>
<Child onClick={updateCountB} />
<p>A: {countA}</p>
<p>B: {countB}</p>
</div>
);
};
import React, { useCallback, useState } from "react";
import Child from "./Child";
const Parent = () => {
import React from "react";
const Child = React.memo(({ onClick }) => {
console.log("子コンポーネントrendar");
return (
<div className="childComponent">
<button onClick={onClick}>countup B</button>
</div>
);
});
この場合、setCountAが実行された場合でも、
子コンポーネントであるChild.jsが再描画されてしまいます。
useCallbackを使う場合
import React, { useCallback, useState } from "react";
import Child from "./Child";
const Parent = () => {
console.log("親コンポーネントrendar");
const [countA, setCountA] = useState(0);
const [countB, setCountB] = useState(0);
const updateCountA = () => {
setCountA((prev) => prev + 1);
};
// 先ほどのコードから変更はuseCallbackのみ
const updateCountB = useCallback(() => {
setCountB(countB + 1);
}, [countB]);
return (
<div>
<button onClick={updateCountA}>countup A</button>
<Child onClick={updateCountB} />
<p>A: {countA}</p>
<p>B: {countB}</p>
</div>
);
};
import React, { useCallback, useState } from "react";
import Child from "./Child";
const Parent = () => {
import React from "react";
const Child = React.memo(({ onClick }) => {
console.log("子コンポーネントrendar");
return (
<div className="childComponent">
<button onClick={onClick}>countup B</button>
</div>
);
});
useCallbackを使うことで、setCountAが実行された場合でも、
子コンポーネントであるChild.jsは再描画されなくなります。
まとめ
useCallbackとは...?のまとめ
- 関数をメモ化することができる
- メモ化することで不要なレンダリングを防ぐことができる
- パフォーマンスを向上させることができる
useCallbackの使い方のまとめ
- 第一引数にはコールバック関数を記述する
- 第二引数には依存配列を記載する
- 依存配列は
[]でもOK- ただし関数が定義されるのは初回実行時のみ
- 依存配列に値を格納することができる
- 格納された値が更新される度に関数が再定義される
- 依存配列は
では、良きReactライフを!!