Open Haramaki0326 opened 2 years ago
import { useEffect } from 'react'
useEffect( 実行する関数, [ 依存する値 ]);
[]
を指定するとコンポーネントを表示した初回のみ実行する
export const App = () => {
useEffect(() => {
alert();
}, [num]);
return ( {/ 省略 /} ); };
基本的にReactで再レンダリングが起きるタイミングは以下の3つ。
import { useState } from "react";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const changeText = (e) => {
setText(e.target.value);
};
return (
<>
<p>App component</p>
<input type="text" onChange={changeText} />
</>
);
}
上記のコードで空欄に文字を入力・削除してみると、処理回数に応じてconsoleに App が繰り返される。 すなわち、stateが変更されることで再レンダリングが発生している。
src/App.jsx
import { useState } from "react";
import Child from "./components/Child";
export default function App() {
const [count, setCount] = useState(0);
const countUp = () => {
setCount(count + 1);
};
return (
<>
<p>App component</p>
<button onClick={countUp}>count up</button>
<Child count={count} />
</>
);
}
src/components/Child.jsx
const Child = (props) => {
const { count } = props;
console.log("Child");
return (
<>
<p>Child component</p>
{count}
</>
);
};
export default Child;
親であるAppコンポーネントから子であるChildコンポーネントへcountというpropsを渡している。 ブラウザで実行してcount upボタンを押すと数字が1ずつ増えていき、consoleにはChildが回数分表示される。 すなわち、propsが変更されることで再レンダリングが発生している。
これは「親コンポーネントで再レンダリングが発生すると、その配下にある子コンポーネントが全て再レンダリングされてしまう」というもの。
src/App.jsx
import { useState } from "react";
import Child from "./components/Child";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const changeText = (e) => {
setText(e.target.value);
};
return (
<>
<p>App component</p>
<input type="text" onChange={changeText} />
<br />
<Child />
</>
);
}
src/components/Child.jsx
const Child = () => {
console.log("Child");
return (
<>
<p>Child component</p>
</>
);
};
export default Child;
上記のコードでは親子間でのpropsの受け渡しはないが、ブラウザ上で空欄に文字を入力・削除すると(親であるAppコンポーネントに記述されているinput要素に値を入力すると)、consoleにAppとChildが繰り返し表示されることが確認できる。 すなわち、親コンポーネントが再レンダリングされているタイミングで子コンポーネントも再レンダリングされている。 親子間で値の受け渡しが無いのにも関わらず、意図せずこのような再レンダリングが発生してしまうことで、パフォーマンスが下がってしまう。
再レンダリングを最適化する、すなわち無駄な計算や処理を抑えるために必要なReactの機能が以下の3つ。
これらの機能を用いることで、メモ化(計算結果を保持し、それを再利用すること)ができる。 同じ結果を返す処理に関しては初回のみ処理を実行しておき、2回目以降は前回の処理結果を呼び出すことで毎回同じ処理を実行しなくてよくなる。
以下のコードをブラウザで実行し、空欄に文字を入力・削除すると(親であるAppコンポーネントに記述されているinput要素に値を入力すると)、consoleにはAppのみが繰り返し表示される。(メモ化していない先ほどのコードではAppとChildが交互に繰り返されていた) Childコンポーネントはメモ化されているので、Childはconsoleに表示されない。
import { useState } from "react";
import Child from "./components/Child";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const changeText = (e) => {
setText(e.target.value);
};
return (
<>
<p>App component</p>
<input type="text" onChange={changeText} />
<br />
<Child />
</>
);
}
import { memo } from "react";
const Child = memo(() => {
console.log("Child");
return (
<>
<p>Child component</p>
</>
);
});
export default Child;
useCallbackはメモ化したコールバック関数を返すHooks API。 次に、以下のようなコードを実行してみる。
import { useState } from "react";
import Child from "./components/Child";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const changeText = (e) => {
setText(e.target.value);
};
return (
<>
<p>App component</p>
<br />
<Child changeText={changeText} />
</>
);
}
import { memo } from "react";
const Child = memo((props) => {
console.log("Child");
const { changeText } = props;
return (
<>
<input type="text" onChange={changeText} />
<p>Child component</p>
</>
);
});
export default Child;
先ほど親コンポーネント(App)で処理していたinput要素を子コンポーネント(Child)に移動させ、関数changeTextもpropsで受け渡している。 以下のコードをブラウザで実行し、空欄に文字を入力・削除すると(親であるAppコンポーネントに記述されているinput要素に値を入力すると)、再びconsoleにAppとChildが繰り返し表示される。 「Childコンポーネントをメモ化しているのになぜ?」
この原因はpropsで受け渡した関数にある。 親コンポーネントで生成した関数をpropsで子コンポーネントに渡すと、関数の内容が同じでも子コンポーネントでは「毎回新しい関数が渡されている」と判断されてしまう。 そこでuseCallbackを使う。
import { useState, useCallback } from "react";
import Child from "./components/Child";
export default function App() {
console.log("App");
const [text, setText] = useState("");
const changeText = useCallback(
(e) => {
setText(e.target.value);
},
[setText]
);
return (
<>
<p>App component</p>
<br />
<Child changeText={changeText} />
</>
);
}
以上のように関数(changeText)をuseCallbackで囲み、第2引数には配列を設定できる。(useEffectと同様) このコードをブラウザで実行し、空欄に文字を入力・削除すると(親であるAppコンポーネントに記述されているinput要素に値を入力すると)、consoleにはAppのみが繰り返し表示される。
useState
使い方
import { useState } from 'react';
const [num, SetNum] = useState();
const [num, SetNum] = useState(0);