buto > /dev/null

だいたい急に挑戦してゴールにたどり着かずに飽きる日々です

react useEffectでライフサイクル入門

今日はuseEffectフックを使って関数を実行するタイミングを操作します

useEffectフック

useEffect(() => {実行したい処理}, [state変数]);

このように書くとstate変数が変更されたタイミングで実行したい処理が実行されます

第2引数([state変数]のところ)を変えることでstate変数の変更タイミング以外でも処理を実行することができます

レンダリングごとに実行(Updating)

初期表示+再描画の度に実行したい場合は「useEffectの第2引数を省略」します

サンプルコードではWelcome.tsxで名前を入力、Enterボタンを押下するとメッセージと現在日時が表示されます

useEffectには現在日時を取得してセットする処理を書いています

components/Welcome.tsx

import {useState,useEffect} from 'react';
import {useName} from '../logic/useName';

function Welcome() {

  const {disp, changeName} = useName();
  const [show, setShow] = useState(false);
  const [date, setDate] = useState('');

  // useEffectの第2引数を省略すると描画ごとに実行される
  useEffect(() => {
    const now: string = new Date().toLocaleString();
    setDate(now);
  });

  return (
    <div>
      <p>名前を入力してください</p>
      <input type="text" onBlur={e => changeName(e.target.value)}/>
      <button onClick={() => setShow(true)}>Enter</button>
      {show &&
        <div>
          <p>ようこそ!! {disp}</p>
          <p>{date}</p>
        </div>
      }
    </div>
  );
}

export default Welcome;

App.tsx

import Welcome from './components/Welcome';

function App() {

  return (
    <div>
      <Welcome/>
    </div>
  );
}

export default App;

logic/useName.tsx 入力された名前のsetter/getter

import {useState,useEffect} from 'react';

export const useName = () => {

  const [name, setName] = useState<string>('risa');
  const [disp, setDisp] = useState<string>(name);

  useEffect(() => {
    setDisp(name + 'さん');
  }, [name]);

  const changeName = (input:string) => {
    setName(input);
  };

  return {disp, changeName};
}

再描画のタイミング「名前を変更してテキストボックスからフォーカスアウトした時」に現在日時も変わっています f:id:butorisa:20210919171613g:plain

初期表示のみ実行(Mounting)

初期表示のみ実行したい場合は「useEffectの第2引数を[]」にします

components/Welcome.tsx

import {useState,useEffect} from 'react';
import {useName} from '../logic/useName';

function Welcome() {

  const {disp, changeName} = useName();
  const [show, setShow] = useState(false);
  const [date, setDate] = useState('');

  // useEffectの第2引数を[](空配列)すると初期表示のみ実行される
  useEffect(() => {
    const now: string = new Date().toLocaleString();
    setDate(now);
  }, []);

  return (
    <div>
      <p>名前を入力してください</p>
      <input type="text" onBlur={e => changeName(e.target.value)}/>
      <button onClick={() => setShow(true)}>Enter</button>
      {show &&
        <div>
          <p>ようこそ!! {disp}</p>
          <p>{date}</p>
        </div>
      }
    </div>
  );
}

export default Welcome;

今度は名前を変更しても現在日時は変わっていません f:id:butorisa:20210919172551g:plain

コンポーネント破棄で実行(Unmounting)

コンポーネントが非表示になったタイミングで実行したい場合は「useEffectの第1引数に実行したい処理を記述」します

import {useState,useEffect} from 'react';
import {useName} from '../logic/useName';

function Welcome() {

  const {disp, changeName} = useName();
  const [show, setShow] = useState(false);
  const [date, setDate] = useState('');

  // useEffectの第1引数return句に記述した処理はコンポーネント破棄時に実行される
  useEffect(() => {
    const now: string = new Date().toLocaleString();
    setDate(now);

    return () => console.log('コンポーネントが破棄されました');
  });

  return (
    <div>
      <p>名前を入力してください</p>
      <input type="text" onBlur={e => changeName(e.target.value)}/>
      <button onClick={() => setShow(true)}>Enter</button>
      {show &&
        <div>
          <p>ようこそ!! {disp}</p>
          <p>{date}</p>
        </div>
      }
    </div>
  );
}

export default Welcome;

コードを修正後ホットリロード時にコンソールに「コンポーネントが破棄されました」と出力されました f:id:butorisa:20210919180412p:plain

第2引数を[]にするとマウント時とアンマウント時に実行されるようになるようです

コンポーネント破棄タイミングってブラウザ閉じた、別サイトへ移動って感じなのかな??

(非表示で破棄になるかと思って画像のbyeボタンを作ったが非表示では破棄されなかった)

参考

useEffectフックのしくみ

Reactの基礎 【ライフサイクル】

【ReactNative】現在の日付、時間表示をする方法