再レンダリングの条件
・stateが更新された時
・propsが変更された時
・親のコンポーネントが更新された時
inputについて
inputはvalue属性が設定されてると入力ができなくなる。流れとしては
1.inputエリアに入力
2.stateであるtextの変更を検知
3.textを更新するため、再レンダリングされる
4.useState("")が走り、初期値として空白が設定される。
そのため下記のように、onChangeイベントを設定する必要がある。
import { useState } from "react";
//動かない
export const App = () => {
const [text, setText] = useState("");
return(
<>
<input value="text" />
</>
);
};
//動く
export const App = () => {
const [text, setText] = useState("");
const onChangeText = (e) => {
setText(e.target.value)
}
return(
<>
<input value="text" onChange={onChangeText} />
</>
);
};
useEffect
・特定のstateが更新された時のみ処理を行う
・第1引数に行いたい処理、第2引数に配列形式で対象となるstateを指定する
・空の配列を渡すことで、最初のレンダリング時のみ処理を行うことができる
import './App.css';
import { useEffect, useState } from 'react';
export const App = () => {
const [hoge, setHoge] = useState(true);
const [fuga, setFuga] = useState(true);
const onClickHoge = () => {
setHoge(!hoge);
}
const onClickFuga = () => {
setFuga(!fuga);
}
useEffect(() => {
console.log('最初のレンダリングの時のみ')
},[])
useEffect(() => {
console.log('hogeが変更された時のみ')
},[hoge])
console.log('stateが変わるたび');
return (
<>
<button onClick={onClickHoge}>hoge</button>
<div>{hoge || 'hoge'}</div>
<button onClick={onClickFuga}>fuga</button>
<div>{fuga || 'fuga'}</div>
</>
);
};
メモ化
・コンポーネントや値を再利用できるように保持すること
・再レンダリングを防ぐことができる
memo
・コンポーネントをメモ化する
・下記であればChildコンポーネントは親コンポーネントがレンダリングされる度に再レンダリングされるが、MemoChildは再レンダリングされない
import { useState } from 'react';
import { Child } from './componentes/Child';
import { MemoChild } from './componentes/MemoChild';
export const App = () => {
const [num, setNum] = useState(0);
const onClickIncrement = () => {
setNum(num + 1);
};
return (
<>
<button onClick={onClickIncrement}>stateを更新</button> //クリックされる度にstateが更新されるため、再レンダリング
{num}
// 親が再レンダリングされると、通常子コンポーネントは再レンダリングされるが、MemoChildの方は再レンダリングされない
<MemoChild /> //メモ化されたコンポーネント
<Child /> //通常のコンポーネント
</>
);
};
export const Child = () => {
console.log('通常のコンポーネント'); //上記のonClickIncrementが走る度に出力される
};
import { memo } from "react"
export const MemoChild = memo(() => {
console.log('メモ化したコンポーネント'); //上記のonClickIncrementが走っても出力されない
});
useCallback
・関数をメモ化する
・第1引数にメモ化する関数を、第2引数に再計算の対象となるstateを指定する
・関数をpropsとして渡してるコンポーネント自身が再レンダリングされた際に、渡されたコンポーネントが再レンダリングされるのを防ぐ
import { useCallback, useState } from 'react';
import { Child } from './componentes/Child';
import { HogeChild } from './componentes/HogeChild';
import { MemoChild } from './componentes/MemoChild';
export const App = () => {
const [hoge, setHoge] = useState(true);
const onClickHoge = () => {
setHoge(!hoge);
};
const [fuga, setFuga] = useState(true);
const onClickFuga = () => {
setFuga(!fuga);
};
const notMemoFunction = () => console.log('メモ化されていない関数'); //アロー関数はレンダリングの度に新たな関数として再計算されるため、propsの変更と見なされる
const memoFunction = useCallback(() => console.log('メモ化されている関数'),[]); //メモ化されてるためレンダリングされても再計算されない
const hogeFunction = useCallback(() => console.log('hogeに対してのみメモ化されていない関数'),[hoge]); //hogeが更新された時のみ再計算される
return (
<>
<button onClick={onClickHoge}>hoge</button>
{hoge || 'hoge'}
<button onClick={onClickFuga}>fuga</button>
{fuga || 'fuga'}
<MemoChild memoFunction={memoFunction}/>
<Child notMemoFunction={notMemoFunction}/>
<HogeChild hogeFunction={hogeFunction} />
</>
);
};
import { memo } from "react";
export const Child = memo((props) => {
props.notMemoFunction() //コンポーネントがメモ化されていても、再レンダリング時関数が再計算される=propsの変更があったと見なされ再レンダリングされる
});
import { memo } from "react"
export const MemoChild = memo((props) => {
props.memoFunction() //propsとして渡される関数がメモ化されているため、再レンダリングされない
});
import { memo } from "react"
export const HogeChild = memo((props) => {
props.hogeFunction()//propsとして渡される関数がhogeを対象として再計算されているため、上記onClickHogeでのみ再レンダリングされる
});
useMemo
・計算結果をメモ化する
・第1引数にメモ化する関数を、第2引数に再計算の対象となるstateを指定する
・useCallbackと違い、コンポーネント自身の関数の再計算を防ぐ
import { useState, useMemo } from 'react';
export const App = () => {
const [hoge, setHoge] = useState(true);
const onClickHoge = () => {
setHoge(!hoge);
};
const [fuga, setFuga] = useState(true);
const onClickFuga = () => {
setFuga(!fuga);
};
console.log('メモ化されていない')
useMemo(() => console.log('メモ化されている'),[]);
useMemo(() => console.log('hogeに対してはメモ化されていない'),[hoge]);
return (
<>
<button onClick={onClickHoge}>hoge</button>
{hoge || 'hoge'}
<button onClick={onClickFuga}>fuga</button>
{fuga || 'fuga'}
</>
);
};
何かミスやアドバイス等ありましたら、コメント頂けると幸いです。