search
LoginSignup
12
Help us understand the problem. What are the problem?

More than 1 year has passed since last update.

React Hooks Advent Calendar 2019 Day 3

posted at

updated at

Organization

useStateとuseReducerの関係(どっちが強力?同じ?わずかな違い?決定的な違い?)

はじめに

React HooksのuseStateとuseReducerに関する小ネタです。

useStateはuseReducerで実装されている

内部実装ではuseStateはuseReducerで実装されていると、どこかに書いてありました。こちらのブログ記事にuserlandでの実装例が載っています。

const stateReducer = (prevState, newState) =>
  typeof newState === 'function' ? newState(prevState) : newState;

const stateInitializer = initialValue =>
  typeof initialValue === 'function' ? initialValue() : initialValue;

const useState = initialValue =>
  useReducer(stateReducer, initialValue, stateInitializer);

こんな感じになります。

つまり、useStateでできることは全てuseReducerでもできるということです。では、useReducerだけでしかできないことはあるのでしょうか。

useReducerはuseStateでも実装できる

実は、useReducerはuseStateでも実装できます。こちらのブログ記事にuserlandでの実装例があります。

const useReducer = (reducer, initialArg, init) => {
  const [state, setState] = useState(
    init ? () => init(initialArg) : initialArg,
  );
  const dispatch = useCallback(
    action => setState(prev => reducer(prev, action)),
    [reducer],
  );
  return useMemo(() => [state, dispatch], [state, dispatch]);
};

こんな感じになります。つまり、機能的には同等ということになります。

実はわずかな違いがある

こちらのツイートにあるように、useReducerではinitArgとinitが分離されているため、initをpropsに依存しないように書くことができます。これにより、hookの外側で関数定義することもできますし、inline関数で書いたとしてもJavaScriptのランタイムエンジンで最適化される可能性が高いです。

決定的な違いもあるにはある

お勧めしませんが、useReducerには非常に特殊な利用法もあります。それはreducerをコンポーネント内で定義できることです。reducerをコンポーネント内で定義すると未来のpropsを読み込めちゃいます。"cheat mode"と呼ばれたりします。

詳細は、こちらのブログ記事のセクションをご参照ください。

追記(12/4)

このcheat modeは上記のuserland実装では再現できていないですね。

おわりに

小ネタにしようかと思っていましたが、書き始めたらマニアックなネタになってしまいました。楽しんでくれた方がいらしたら幸いです。

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
What you can do with signing up
12
Help us understand the problem. What are the problem?