0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

React.js 学習備忘録②~再レンダリング~

Last updated at Posted at 2022-10-21

再レンダリングの条件

・stateが更新された時
・propsが変更された時
・親のコンポーネントが更新された時

inputについて

inputはvalue属性が設定されてると入力ができなくなる。流れとしては
1.inputエリアに入力
2.stateであるtextの変更を検知
3.textを更新するため、再レンダリングされる
4.useState("")が走り、初期値として空白が設定される。
そのため下記のように、onChangeイベントを設定する必要がある。

React.js App.jsx
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を指定する
・空の配列を渡すことで、最初のレンダリング時のみ処理を行うことができる

React.js App.jsx
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は再レンダリングされない

App.jsx
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 /> //通常のコンポーネント
    </>
  );
};
Child.jsx
export const Child = () => {
    console.log('通常のコンポーネント'); //上記のonClickIncrementが走る度に出力される
};
MemoChild.jsx
import { memo } from "react"

export const MemoChild = memo(() => {
    console.log('メモ化したコンポーネント'); //上記のonClickIncrementが走っても出力されない
});

useCallback

・関数をメモ化する
・第1引数にメモ化する関数を、第2引数に再計算の対象となるstateを指定する
・関数をpropsとして渡してるコンポーネント自身が再レンダリングされた際に、渡されたコンポーネントが再レンダリングされるのを防ぐ

App.jsx
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} />
    </>
  );
};

Child.jsx
import { memo } from "react";

export const Child = memo((props) => {
    props.notMemoFunction() //コンポーネントがメモ化されていても、再レンダリング時関数が再計算される=propsの変更があったと見なされ再レンダリングされる
});
MemoChild.jsx
import { memo } from "react"

export const MemoChild = memo((props) => {
    props.memoFunction() //propsとして渡される関数がメモ化されているため、再レンダリングされない
});
HogeChild.jsx
import { memo } from "react"

export const HogeChild = memo((props) => {
    props.hogeFunction()//propsとして渡される関数がhogeを対象として再計算されているため、上記onClickHogeでのみ再レンダリングされる
});

useMemo

・計算結果をメモ化する
・第1引数にメモ化する関数を、第2引数に再計算の対象となるstateを指定する
・useCallbackと違い、コンポーネント自身の関数の再計算を防ぐ

App.jsx
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'}
    </>
  );
};

何かミスやアドバイス等ありましたら、コメント頂けると幸いです。

前回:基本事項について
次回:CSSについて

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?