LoginSignup
15
19

More than 3 years have passed since last update.

React HooksのTips(と便利な汎用カスタムフック)

Last updated at Posted at 2019-05-19

はじめに

React Hooksを使っていてハマったところをカスタムフックで解決したときの記録です。
TypeScriptで書いてます。

useEffectの中で非同期処理をawaitで実行する

useEffectをラップしたカスタムフックを作ればいい。
useEffectで初期データをawaitを使って取得したい場合などに使える。

import { useEffect, DependencyList } from "react";

export default function useEffectAsync(
  effect: () => any,
  deps?: DependencyList
) {
  useEffect(() => {
    effect();
  }, deps);
}

使い方:

useEffectAsync(async () => {
  // 初期マウント時に一度だけデータを同期で取得する
    const items = await fetchSomeItems();
    console.log(items);
}, []);

現在の state を非同期処理の中でアクセスする

useEffectでコンポーネントマウント時にaddEventListenerし、そのイベント処理内でuseStateで定義したstateにアクセスしたい場合などに。

useRefuseStateのstateの参照を保持するようにして、イベント処理内ではその参照を利用すると現在のstateの値を使える。

以下のようにカスタムフック化すると便利。

import {MutableRefObject, Dispatch, SetStateAction, useState, useRef } from 'react'
const useRefState = <T>(
  initialValue: T
): [T, MutableRefObject<T>, Dispatch<SetStateAction<T>>] => {
  const [state, setState] = useState<T>(initialValue);
  const stateRef = useRef(state);
  useEffect(() => {
    stateRef.current = state;
  }, [state]);
  return [state, stateRef, setState];
};

1秒ごとにカウントアップしながらアラートを表示する場合の例:

import { useEffect } from 'react'

const component = () => {
  const [count, countRef, setCount] = useRefState(0)
  useEffect(() => {
    setInterval(() => {
      alert('Value: ' + countRef.current)
      setCount(countRef.current + 1)
      // 以下のようにしてしまうと初期描画時のcount(=0)がずっと利用されてしまう
      // alert('Value: ' + count)
      // setCount(count + 1)
    }, 1000)
  }, [])
  return <div>{count}</div>
}

このとき、useEffectは第二引数に[]を指定しており最初の一度しか呼ばれないため、setIntervalに指定するコールバック関数でcountを直接指定すると初期描画時のcountの値を利用しつづけることになってしまう。かといってuseEffectで再描画のたびにリスナ登録・リスナ解除のようなことをするのはイケてない。
そういうときにuseRefが使える。

参考:
https://blog.castiel.me/posts/2019-02-19-react-hooks-get-current-state-back-to-the-future/

15
19
2

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
15
19