見出し画像

React Stateを理解する

この記事はReactのHooksの一部であるuseStateを理解するためのものです。
ハマったところで備忘録を書いています。

コンソール上で確認するとStateが更新されていない

こんなことに遭遇した方はおおいのではないでしょうか。
ReactのuseStateは非常に便利で、コンポーネント単位での制作が簡単であり、影響範囲も把握しやすいです。しかし、Stateが更新されるタイミングが分からずに混乱することがあります。この記事では、その理解を深めるために、useStateを使用した簡単なソースコードを用意しました。
今回はボタンを押下すると判定がtrue/falseになるというもの。

判定画面

App.js

import React, { useState } from 'react';

function SampleState() {
  const [isEnt, setIsEnt] = useState(false);

  const handleTrueButtonClick = () => {
    setIsEnt(true);
    console.log(isEnt);
  };

  const handleFalseButtonClick = () => {
    setIsEnt(false);
    console.log(isEnt);
  };

  const RenderClick = () => {
    console.log(isEnt);
  };

  
  return (
    <div>
      <h1>Stateの練習</h1>
      <h2>ボタン直後の判定: {isEnt.toString()}</h2>
      <button onClick={handleTrueButtonClick}>ClickMe True</button>
      <br/>
      <button onClick={handleFalseButtonClick}>ClickMe False</button>
      <br/>
      <button onClick={RenderClick}>ClickMe Rendarling</button>
      
    </div>

);
}

export default SampleState;

 


console.log(isEnt);で内容をコンソール上に判定を表示するようにします。

  const handleTrueButtonClick = () => {
    setIsEnt(true);
    console.log(isEnt);
  };

始めはfalseでスタートします。
画面にはfalseで表示されています。

判定画面

Click Me trueを押下。

Trueボタンを押してもコンソール上ではfalseのまま


コンソール上ではfalseで表示されており、「あれ?表示されない」とソースを見返したが、stateの更新はsetIsEntで(true)としているし、「これは何だろう?」という疑問が残ったので調査をしてみると表示をするまでの理解が存在していた。

公式ではこう表現されている

コンポーネントのメモリとしての state は、関数が終了したら消えてしまう通常の変数とは異なります。state は実際には React 自体の中で「生存」しています。まるで棚に保管しているかのように、関数の外部で存在し続けます。React がコンポーネントを呼び出すとき、React はその特定のレンダーに対する state のスナップショットを提供します。あなたのコンポーネントは、props やイベントハンドラの新たな一式を揃えた JSX という形で UI のスナップショットを返し、それらはすべてその特定のレンダー時の state の値を使って計算されます!



書き換えを行うまで変数(isEnt)は更新されないままで、HTMLが差分を検出して表示をする。isEntに格納された値の更新は予約されている状態となる。
つまり、console.log(isEnt);はまだレンダリング確定しておらず、stateの値は変わっていない。


ここでレンダークリック関数を押下してみる。

  const RenderClick = () => {
    console.log(isEnt);
  };


変更が適用された

レンダーが適用されたのが分かる。
つまり次の変化まで変数の更新がお手の状態になっているのだ。
HTMLのみ表示が優先されて非同期で動いている状態。
この結果を条件にもって、即座に値の判定を行いたい場合はどのようにするか。console.log上では値の確認をするかぎり変数の更新つまりレンダーを行ってくれるタイミングでしかない。

これは変化したstateの状態をかったさらう動き、たとえば
登録ボタンを押す、次のページに行くタイミングの実装などだ。

いったんはconsole.logの動きを確認したいならでは変更されたタイミングを追うにはどのようにしたらよいか?

UseEffectを使用する

非同期で行われる関数を終えた後に関数処理をuseEffectで行う。

第二引数に更新の監視を行う関数を入れておく。
そうすると、変化があった関数が一度だけuseEffect関数の処理が行われる。

  useEffect(() => {  
  // 更新後の値が表示される
    console.log(isEnt); 
  }, [isEnt]);

9行目と、27行目で判定の状態が違うのがお分かりだろうか。

更新後の値が表示されている


変化が分かるように記載する

import React, { useEffect, useState } from 'react';

function SampleState() {
  const [isEnt, setIsEnt] = useState(false);

  const handleTrueButtonClick = () => {

    setIsEnt(true);
    console.log(isEnt);
  };

  const handleFalseButtonClick = () => {
    setIsEnt(false);
    console.log(isEnt);
  };

  const RenderClick = () => {
    console.log(isEnt);
  };


  useEffect(() => {
    console.log(isEnt); // 更新後の値が表示されます
  }, []);
  
  
  return (
    <div>
      <h1>Stateの練習</h1>
      <h2>ボタン直後の判定: {isEnt.toString()}</h2>
      <button onClick={handleTrueButtonClick}>ClickMe True</button>
      <br/>
      <button onClick={handleFalseButtonClick}>ClickMe False</button>
      <br/>
      <button onClick={RenderClick}>ClickMe Rendarling</button>
      
    </div>

);
}

export default SampleState;


これで、更新後の値確認が可能になる。


余談だが値の更新には更新関数を記載すると変数内で、返却値が返ってくるので、こちらでも確認はできる。

function SampleState() {
  const [isEnt, setIsEnt] = useState(0);

  const handleTrueButtonClick = () => {

    setIsEnt(n => n + 1);
    console.log(isEnt);
  };


カウントアップがコンソール上で確認できる


Reactは非同期で行われる更新を値のゲッター、セッターにしてくれていると思いとどめ、組み込みを行っていくことが肝要である。

ご覧いただきありがとうございました。 サポートしていただいたお金は開発費にかけさせていただきます。