LoginSignup
0
0

More than 1 year has passed since last update.

React hooks useEffectについて学ぶ 1

Posted at

React hooksの1つである、useEffect について学んでいきます。

さて useEffectとは一体何者なのでしょうか?

useEffectとは

副作用 (effect) フック により、関数コンポーネント内で副作用を実行することができるようになります

参考:副作用フックの利用法

なるほど、useEffectとは 副作用を実行するためのもののようです。
...副作用ってなんだろう?

副作用とは

ある機能がプログラム上のデータを変化させ、それ以降の演算の結果に影響を与えることを指します

参考 : 副作用

Reactで言うなら、 レンダリング後、それ以降の演算の結果に影響を与えることを指します と言えそうです。
でもそれってどういうことなのでしょう。そんなこと、してもよいのでしょうか?
参考 : レンダリングとは

副作用を試す

それ以降の演算の結果に影響を与える ⇦まだよくわからないので試してみましょう。

分かりやすそうな、DOMの書き換え を行います。
レンダリング後、h1を書き換えてみます。

import { useEffect } from "react"

export const Text = () => {

    useEffect(() => {
        const elem = document.getElementById('title') as HTMLTitleElement; // 絶対h1がある!
        elem.innerText = 'こんばんわ'
    })

    return (
        <div>
            <h1 id="title">こんにちわ</h1>
            <p>使ってみよう</p>
        </div>
    )
}

レンダリング時、h1には こんにちわ というテキストが入っています。
副作用を用いて、h1のテキストを こんばんわ に変化させることができました。


続いては実験です、副作用をコメントアウトしてみましょう。
同じようにテキストを書き換えてくれるでしょうか?

// useEffect(() => {
     const elem = document.getElementById('title') as HTMLTitleElement; // 絶対h1がある!
     elem.innerText = 'こんばんわ'
// })

あれ、ページは真っ白で、エラーが起きてしまいました。

Cannot set properties of null (setting 'innerText')
// null のプロパティを設定できません(「innerText」を設定)

id="title" を見つけることができていません。
つまり、まだレンダリングが終わっていない(DOMのことわかってない) 状態で id="title" を探しに行ってしまいました。

この実験で、
それ以降の演算の結果に影響を与える というのは、レンダリングし終わった後に動き出す
ということだったのが実感できました。

useEffectが動くタイミング

レンダリングし終わった後に動き出す のはわかりました。
では、それって具体的にいつなのでしょう?

useEffectが動くタイミングが3つあります。

  1. 値の変更時
  2. 初回レンダリング時
  3. レンダリング後 // 先ほどの実験です

3は実験すみなので、1からみていきます。

useEffectが動くタイミング[値の変更時]

これはuseStateを使った実験がわかりやすそうです。
2種類のuseStateにて、countcount2 をそれぞれ用意しました。

export const Counter = () => {

    const [count, setCount] = useState<number>(0)
    const [count2, setCount2] = useState<number>(0)

    useEffect(() => {
        console.log(count)
    })

    useEffect(() => {
        console.log(count2)
    })


    const incrementCount = () => {
        setCount(c => c + 1) // *1
    }
    const incrementCount2 = () => {
        setCount2(c => c + 1) // *1
    }

    return (
        <div>
            <h1>{count}</h1>
            <button onClick={incrementCount}>1増える</button>
            <button onClick={incrementCount2}>2増える</button>
        </div>
    )
}

早速、incrementCount を押してみましょう。
*1 についてはこちらをどうぞ この時のcってなに

画面収録_2022-09-30_1_00_32_AdobeExpress.gif

1増えるボタンを押すたびに、console.logが走っているのがわかります!
値の変更時 に動いているのを確認できました。

あれ、全然関係ない console.log(count2) も動いてしまっていますね。

この場合、useEffectの第二引数に、useEffectの動作を依存させる値 を入れることができます。

   useEffect(() => {
        console.log(count)
    }, [count]) // countに反応して動く

    useEffect(() => {
        console.log(count2)
    }, [count2]) // count2に反応して動く

画面収録_2022-09-30_1_08_18_AdobeExpress.gif

それぞれ独立して反応させることができました!

useEffectが動くタイミング[初回レンダリング時]

続いて、2,初回レンダリング時 を見ていきます。
やりかたは簡単、第二引数を空配列を指定するだけです。

    useEffect(() => {
        console.log(count)
    }, []) //空っぽ

    useEffect(() => {
        console.log(count2)
    }, [])//空っぽ

画面収録_2022-09-30_1_19_13_AdobeExpress.gif

まず0が4つ出ましたね。(これについてはこちらをどうぞ)

その後何度クリックしても、console.logが出てくれません。
これは、第二引数を空配列[]にしたことで、

2,初回レンダリング時動く(それ以降動かない)

ということができるのです。

参考:マウント・アンマウント時のみuseEffectを実行する場合

useEffectの無限ループ

useEffectは無限ループにはまってしまった経験はありませんか?
どのような時に起こるのでしょうか。

無限にカウントを1足し続けるgif画像

実装は簡単です。

    useEffect(() => {
        setCount(c => c + 1) // 追加
        console.log(`----${count}----`)
    })

useEffectの中に useStateで使用するset部分 を使って関数を走らせただけです。

初回レンダリングでuseEffect走るね、その時のsetCountするね
 -> 値の変更されたからもう一度useEffect走るね、その時のsetCountするね
 -> 値の変更されたからもう一度useEffect走るね、その時のsetCountするね
:

この状態を避けるためにも、 eslint-plugin-react-hooks を設定しておくのが良いです。
画面収録_2022-10-03_1_32_27_AdobeExpress.gif

ちなみにこれを修正するには 別のstateなどに依存 するようにします。

    useEffect(() => {
        setCount(c => c + 1)
    }, [userId]) // userIdに変更があった時だけ動いてね

参考:なぜ useEffect では無限ループが起こり得るのか


いったん今回はここまでとします
次回はもう少しuseEffectのことを深く見ていきましょう、


読んでおきたい記事: useEffect完全ガイド

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