4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Reactにおいて再レンダリングが発生する条件と対策

4
Last updated at Posted at 2025-12-13

この記事は、ラクスパートナーズ AdventCalendar 2025の17日目の記事です。
(個人で25日連続投稿にチャレンジ中のカレンダーになります)


Reactにおいて再レンダリングが発生する条件と、不要な再レンダリングを防止する方法をまとめてみました。

再レンダリングが起きる条件

stateが変更された時

コンポーネントでstateが変更されると、そのコンポーネントは再レンダリングします。

import { useState } from 'react'
const Profile = () => {
    // nameの値が変わるとProfileコンポーネントも更新される
    const [name, setName] = useState('')

    return (
        // 省略
    )
}

親コンポーネントが再レンダリングされた時

親コンポーネントが再レンダリングされると、子コンポーネントも再レンダリングされます。

import { useState } from 'react'
const Parent = () => {
    // titleの値が変わるとParentコンポーネントが再レンダリングされる
    const [title, setTitle] = useState('')

    return (
        // titleの値が変わるとChildコンポーネントも再レンダリングされる
        <Child />
    )
}

※ 「propsが変更された時、子コンポーネントも再レンダリングされる」という話を聞いたのですが、厳密にはpropsは関係ないそうですね。あくまで親コンポーネントが再レンダリングされるから、それに伴って子コンポーネントも再レンダリングされる、ということでした。
(この後触れる、Reactのmemoという機能を使うと話は別です)

対策

Reactのmemoでメモ化する

memoを使うと、親コンポーネントで再レンダリングが起きても、propsに変更がなければ子コンポーネントが再レンダリングされなくなります。
これをメモ化と言います。

親コンポーネント
import { useState } from 'react'
const Parent = () => {
    // titleの値が変わるとParentコンポーネントが再レンダリングされる(Childコンポーネントは再レンダリングされない)
    const [title, setTitle] = useState('')

    // textの値が変わるとChildコンポーネントも再レンダリングされる
    const [text, setText] = useState('')

    return (
        <>
            <div>{ title }</div>
            <Child text={text} />
        </>
    )
}
子コンポーネント
import { memo } from 'react'
const Child = memo((props) => {
    const { text } = props;

    return (
        // 省略
    )
})

肥大化していきそうなコンポーネントには、memoを使って積極的にメモ化してあげると良さそうですね。

useCallbackを使用する

子コンポーネントに親コンポーネントで定義したアロー関数を渡すと、
「毎回新しい関数を生成している」
という判断をされてしまうそうです。
その結果、親コンポーネントで再レンダリングが発生する度に、子コンポーネントも再レンダリングされてしまいます。
(そのため、memoを使ってメモ化していても防げない)

親コンポーネント
const Parent = () => {
    // titleの値が変わるとParentコンポーネントが再レンダリングされる(Childコンポーネントは再レンダリングされない)
    const [title, setTitle] = useState('')

    // textの値が変わるとChildコンポーネントも再レンダリングされる
    const [text, setText] = useState('')

    const [isShow, setIsShow] = useState('')

    // 毎回新しいアロー関数が渡されてしまう
    const onClickClose = () => setIsShow(false)

    return (
        <>
            <div>{ title }</div>
            <Child text={text} isShow={isShow} onClickClose={onClickClose} />
        </>
    )
}
子コンポーネント
const Child = memo((props) => {
    const { text, isShow, onClickClose } = props;

    return (
        {isShow ? (
             {/* isShowをfalseにするボタン */}
            <button onClick={onClickClose}></button>
            // 省略()
        ) : null}
    )
})

これを防ぐのに役立つのがuseCallbackです。
useCallbackを使うことで、指定した関数の再生成を制御して、不要なレンダリングを防ぐことができます。

親コンポーネント
import { useState, useCallback } from 'react'
const Parent = () => {
    // titleの値が変わるとParentコンポーネントが再レンダリングされる(Childコンポーネントは再レンダリングされない)
    const [title, setTitle] = useState('')

    // textの値が変わるとChildコンポーネントも再レンダリングされる
    const [text, setText] = useState('')

    const [isShow, setIsShow] = useState('')

    const onClickClose = () => useCallback(setIsShow(false), [])

    return (
        <>
            <div>{ title }</div>
             {/* 子コンポーネントに関数渡すと */}
            <Child text={text} isShow={isShow} onClickClose={onClickClose} />
        </>
    )
}

useCallback(関数, 監視する変数)のような形式で使うことができます。監視対象の値が変わると、第一引数の関数を再生成します。

useEffect()と同じように、第二引数部分に空の配列を指定することができて、空の配列を指定すると関数の再生成を防ぐことができます。
これにより、子コンポーネントの不要な再レンダリングも防止できるようです。

「ダイアログのコンポーネントを呼び出して、ダイアログ側で表示フラグをfalseにして閉じる」みたいなことをすると再レンダリングさせてしまいそうですね。気をつけねば。

参考

参考にさせていただいた記事です。
ありがとうございました。
https://qiita.com/yokoto/items/ee3ed0b3ca905b9016d3

4
6
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
4
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?