LoginSignup
1
1

More than 3 years have passed since last update.

[React] React Hooksでどのdependencyが変化したのかわからないだって? そう、そんなときはusePreviousだ!

Posted at

こんにちは。 @nerikosans です。みなさん、React Hooksしていらっしゃいますでしょうか。
今日は僕がHooksで詰まって3時間溶かして学んだことのメモを書いていこうと思います。

悲劇

例えば arrow function があったとして、それをhooksのdepsに入れてしまうと各render毎に異なるオブジェクトとして認識されてしまうのは日本書紀にも記述がありますね。
つまり


const getMySuperBenriFunction = () => {
  return (a: number, b: number) => a + b;
}

const benri1 = getMySuperBenriFunction();
const benri2 = getMySuperBenriFunction();

console.log(benri1 === benri2)  // => false

であり、


import getMySuperBenriFunction from './getMySuperBenriFunction';

const MySupremeComponent: React.FC = () => {
  const benri = getMySuperBenriFunction();
  const [v1, setV1] = React.useState(1);
  const [v2, setV2] = React.useState(3);

  // v1, v2が変わると出力
  // benriが変化することは想定してない
  React.useEffect(() => {
    console.log(benri(v1, v2));
  }, [v1, v2, benri]);

  return (
    <div>
      (ここにすごいUI)
    </div>
  )
}

みたいなことをすると全renderで useEffect が走って非常につらい気持ちになります。

デバッグ策

さて、前述のarrow functionの件はもちろんヤマトタケルの時代から決まっているのですが、うっかりこれを失念してしまったとしましょう。

そんなとき、「なぜこの useEffect が走るのかわからない...どのdepsが変化しているんや...」という調査を比較的ラクにできる手法を紹介します。
つまり、変数の値を前サイクルと比較できればよいのです。

ということでご登場願いましょう、usePreviousさーん!

usePreviousさん

function usePrevious<T>(value: T) {
  const ref = React.useRef<T>();
  React.useEffect(() => {
    ref.current = value;
  });
  return ref.current;
}

usePreviousさんの勇姿



function usePrevious<T>(value: T) { /*...*/ }

const MySupremeComponent: React.FC = () => {
  /* ... */
  console.log(usePrevious(benri) === benri) // => false

  React.useEffect(() => {
    console.log(benri(v1, v2));
  }, [v1, v2, benri]);

  return (
    {  /*...*/ }
  )
}

ということで、 usePrevious さんを用いて前サイクルと比較すれば、どのdepsの変化でEffectが発火しているのか、比較的早く発見できるでしょう。最高!

usePreviousさんの出自

なお、御大はReact公式FAQで紹介されています。公式hookになる可能性もあるみたいです。

おまけ

hooksプロのみなさんには言うまでもないかと思いますが、この問題の解決策は

const getMySuperBenriFunction = () => {
  return React.useCallback((a: number, b: number) => a + b, []);
}

benri 自体をcallbackに入れることですね。

1
1
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
1
1