2
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 HookのuseEffect()を使ったのでまとめてみた

Posted at

そもそものReactの特徴

stateを使わずに関数を書いた場合、コンポーネント内の関数が複数回実行されても、再レンダリングは起きない。

JS
const Example = () => {
    console.log('再レンダリング')
    return (
        <intput
        onchange = {(e) => console.log(e.target.value);}
        >
    )
}

例えばこちらにinputフォームで、文字を入力したとします。1文字入力するごとにeventが発生し、console.log(e.target.value)が実行されます。しかし、 console.log('再レンダリング')は文字入力とは連動せず、Exampleコンポーネントが最初に呼び出された時のみ実行されます。
 
 
 

stateを使うとどうなる

stateの値が変更されるたびに、コンポーネントが呼び出される。

JS
const Example = () => {
    console.log('再レンダリング')
    const [text, setText] = useState('');

    return (
        <intput
        onchange = {(e) =>
        setText(e.target.value);
        console.log(e.target.value);}
        >
    )
}

文字入力が起きると、onChangenのeventが発生し、setText(e.target.value);によってtextの値が書き換えられる。つまり、1文字入力されるたびに、stateの値が変更される。stateの値が変更されるたびにconsole.log('再レンダリング')が実行される。このようにレンダリングされると、副産物的に関数が実行されてしまい、これを副作用と呼んだりする。
 
 
 

useEffect()を使うとどうなる

結論:起こしたい副作用を指定したり、副作用が起きないように制御できる。
 
1秒ずつ表示される数字が1ずつ増えるタイマーを例にレンダリングで副作用が起きないようにしてみよう。
まずはuseEffect()を使わないと...

JS
const Timer = () => {
    console.log('再レンダリング')
    const [time, setTime] = useState(0);
    
    window.setInterval(() => {setTime(prev => prev + 1)}, 1000);

    return (
        <>{time}</>
    )
}

これはまずTimerコンポーネントが呼ばれると、console.log('再レンダリング')が実行される。そして1秒ごとにsetTime(prev => prev + 1)が実行される。ここで注意すべきは、stateが変わると再レンダリングが起きるということ。つまり、setTime(prev => prev + 1)によってstateの値が1秒ごとに変わると再レンダリングが起きてtimeの値がおかしくなる。
 
どうすればいいかというと、stateの値が変わっても、再レンダリングが起きないようにすればいい。言い換えると、コンポーネントが呼ばれたときに、関数が実行されるのは1度だけになるようにすればいい。

JS
const Timer = () => {
    console.log('再レンダリング')
    const [time, setTime] = useState(0);
    
    useEffect(() => {
         console.log('useEffectが呼ばれたぜ')
         window.setInterval(() => {setTime(prev => prev + 1)}, 1000)
    },[])
   
    return (
        <>{time}</>
    )
}

window.setIntervalをuseEffect()の中に入れることで、Timerコンポーネントが呼ばれた時に一度だけ実行されるようになる。
 
 
 

useEffect()の第二引数の配列について

第二引数には配列が入る。この配列にstateを含めると、そのstateが変更された時にuseEffect()の第一引数にあるコールバック関数が実行される。

JS
    useEffect(callback関数, [state1, state2,....]);

Timerの例のように、コンポーネントが呼ばれたら1度だけ関数を実行すれば良い場合は、配列は空にする。
 
 
 

まとめ

useEffect()はstateの更新時のレンダリングによって実行される副産物的な関数実行(副作用)を制御する役割がある。2回目以降のレンダリングで副作用を起こしたくないときは、useEffect()の第2引数に空配列[]を渡せば良い。

2
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
2
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?