ファーストビューの効率化のために、ファーストビューのタイミングで不要なものを遅延ロードにしていたのですが、reducerを遅延させるのもいいかなと思えてきました。
reducerが必要となるタイミング
コンポーネントを描画した直後にdispatch
を行う必要性というのは、そうそう生じないものです。ユーザーインタラクションでしかdispatch
が行われない、ということでしたら、コンポーネントを作成したタイミングで遅延ロードを開始して、そこから1秒もしないうちにロードされる、というようなタイミングでじゅうぶん間に合います。
そして、巨大なオブジェクトを取り扱うreducerは、往々にして多くのコードを必要とします。
とはいえ、ふつうのReact.useReducer
では、reducer関数は同期的に必要となってしまいます。
useLazyReducer
を作ってみた
ということで、遅延ロードでreducerをロードするようなHooksを立ててみました。
// ロード前は何もしないreducerを入れておく
const temporaryReducer = (store, _action) => store;
export default function useLazyReducer(lazyReducer, initialArg, initializer) {
// 遅延データを入れる
const reducerRef = React.useRef(temporaryReducer);
React.useEffect(() => {
lazyReducer().then((obj) => {
reducerRef.current = obj.default;
});
}, [lazyReducer]);
const reducer = React.useCallback(
(store, action) => reducerRef.current(store, action),
[]
);
return React.useReducer(reducer, initialArg, initializer);
}
仕掛けとしてはごく単純で、reducerとしてセットする関数はrefの中身につなぐだけ、としておいて、遅延ロードでrefを書き換える、というものです。lazyReducer
として渡すものは、React.lazy
に倣って、「{default: reducer関数}
をresolve
するPromise
を返す関数」を受け取るようにしてあります。
使用感
遅延ロードが間に合わないぐらいのタイミングでユーザー操作に入るのは現実的に困難ですので、これで十分に間に合っている印象です。