Webエンジニアの備忘録

およそ自己の作業メモとして残しております。

componentWillMountをReactフックで書く方法を考えた

componentWillMountの今…

v16以前、componentWillMountというライフサイクルイベントがありました。(過去形…)
v17以降は非推奨となり、UNSAFE_componentWillMount と名称変更されています。

嫌われるcomponentWillMount

v16以前からReactを利用しているプロジェクトではしばしばReactフックへの移行の話が上がり、componentWillMountの対応方法について求めるコメントが上がっています。ただし、解決方法については有識者からは冴えない返答が散見されます。

  • Reactフックを使えばconstructorはいらないよ!
  • useEffectを使えばcomponentDidMount相応の挙動だ。(ただしレンダー後に実行)
  • そもそもcomponentWillMountを使うな。

言い回しは変わっていますが、すべて3つ目の「使うな」の言い換えになっています。
有識者側の言い分としては、実装を無くすよう検討してくれということなのです。

非推奨な理由を考察

そもそもComponentのレンダー前にやっている処理はComponentに関係ない処理である可能性が高いです。
何かしら計算が必要であれば計算後の値をpropsに送ればよいし、レンダーに関わる処理はComponent呼び出し前に済まされているのが理想的です。

おそらく、v16以前はすべてをComponentで行う志向が強く、ライフサイクルにすべての処理を内包するのが作法だったかのように思えます。
(本当はもっと前からですが)v17ではパラダイムシフトが起きており、債務を絞った、より軽微なComponentを目指すのがトレンドになってきました。

非推奨でも使いたい

設計思想の変化は理解しつつも、すでに動いているサービスの改修は別問題です。 useMemoを利用するのがシンプルかと思います。

const Componnet = ({ updateTrigger }) => {
  const key = useMemo(() => {
    // ここに前処理を書ける
    return updateTrigger;
  }, [updateTrigger]);

  return (
    <div key={key} />
  );
};

値を返す特性上、レンダリングより早く動作し、propsを外部更新のトリガーにすればcomponentWillUpdateの代替としても利用できます。 本当に初期実行時にしか動作しないのであれば、useStateを実行済みフラグなどとして利用する手段も浮かびましたが、こちらのほうがキレイかと思いました。


フィードバックなどあれば、コメントいただければ嬉しいです!