React useEffectの働き方

前回の記事で useStateはどうやって働いているのか、わかりやすく説明しました。今回はuseEffectを説明します。

https://zanp.life/js/544

まだ読んでいない方は、↑の記事をご覧になってください。

下準備

個人的には、hooksはCache見たいなもの。key-value的なcacheじゃなくて、実行順序に基づいてのcache システム。

では、useEffectはどう動いているのか、まずuseEffectのtypeを見ましょう。

function useEffect(effect: EffectCallback, deps?: readonly any[]): void

要するに、depsが変わったら、実行される。

show me the code

前回のuseStateのコードを見よう。

const React = {
  data: [],
  currentIndex: 0,
  useState(initValue) {
    const index = this.currentIndex;
    // dataないなら、引数の初期値を挿入
    if (this.data.length <= index) {
      this.data.push(initValue);
    }

    this.currentIndex = index + 1;

    //値とsetterを返す
    return [
      this.data[index],
      newValue => {
        this.data.splice(index, 1, newValue);
      }
    ];
  },
  // indexをreset
  resetIndex() {
    this.currentIndex = 0;
  }
};

そちらに各hookにはdataあり、そのdataにdepsを保存すれば、useEffectが作れます。コードは大体こんな感じ

useEffect(callback, deps) {
    const index = this.currentIndex;
    // depsが変わったら、callbackを実行する
    const prevDep = this.data[index];
    if (!prevDep || deps.some((val, index) => val !== prevDep[index])) {
      callback();
    }
    this.data[index] = deps;
    this.currentIndex = index + 1;
  }

コードがシンプルで、テストしてみましょう. CounterにuseEffectを追加する。

const Counter = () => {
  const [count, setCount] = React.useState(0);
  React.useEffect(() => {
    console.log("useEffect is called");
  }, [count]);
  return {
    // click をmockする
    click() {
      setCount(count + 1);
    },
    render() {
      return count;
    }
  };
};

これでrenderをシミュレーションする

console.log("1st");
let counter1 = Counter();
counter1.render();

console.log("2st");
React.resetIndex();
counter1 = Counter();

console.log("3st");
React.resetIndex();
counter1.click();
counter1 = Counter();

1回目ではcallback実行されて、2回目はcountが変わらなくて、callbackが実行されない。3回目ではcountが変わったので、callbackはもう一回実行される。

以上は予想だけだが、consoleを見ると、確かにこうなっている。

これでuseEffectも理解できました、次回はuseContextをみましょう。お楽しみに

以上では各投稿者の観点であり、zanp.lifeに責任負い兼ねます。

#js#typescript#react#hooks

jser  2019-10-10