LoginSignup
27
11

More than 5 years have passed since last update.

React.StrictModeがあぶり出す意外な問題点

Posted at

React 16.3で<React.StrictMode>というコンポーネントが登場しました。大半のチェック点はうなずけるものだったのですが、1つ気になることがありました。

<React.StrictMode>とは

JavaScriptをやっている方なら"use strict";によるJavaScript自体のStrictモードはご存知かと思いますが、<React.StrictMode>もそれと同様、今までの書き方で問題が出る部分をあぶり出すためのモードです。なお、React本体のproductionビルドではチェックが無効となりますので、developmentビルドを使う必要があります。

背景

React 17からレンダリングを非同期化するという話が進んでいて、それで問題になるコードをチェックするために<React.StrictMode>が導入された、ということのようです。

deprecatedな機能のチェック

旧式になった機能を使っていると、その旨がコンソールに出力されます。

  • 古い\ライフサイクル(componentWillMountcomponentWillUpdatecomponentWillReceiveProps
  • 文字列によるref指定
  • 旧形式のコンテキスト
  • findDOMNode

とはいえ、このあたりはすでにdeprecatedの宣言もあり移行手順も公開されているので、(依存しているコンポーネントが変更できないなどの状況なら別として)そう大問題にはならないかと思います。

非同期レンダリングのフェーズ

では、ここからが本題です。以前に別な記事で書きましたが、Reactの非同期レンダリングにおいては、状態が「Render Phase」と「Commit Phase」の2つに大きく分けられます。

そして、getSnapshotBeforeUpdatecomponentDidMountcomponentDidUpdatecomponentWillUnmountはCommit Phaseのコールバックですが、それ以外のrender、コンストラクタ、setStateのupdater、getDerivedStateFromPropsshouldComponentUpdateなどはRender Phaseのコールバックです。

そして、非同期レンダリングを行う上では、Commit Phaseのコールバックは実行されるべき1回のレンダリングに対応して確実に1回実行されますが、Render Phaseのコールバックは複数回実行されうるものとなります。そこで、<React.StrictMode>ではそういった問題点の洗い出しのため、render、コンストラクタ、setStateのupdater、getDerivedStateFromPropsを1回のrenderに対して2回実行するようになります。

複数回のコンストラクタ…?

通常、updaterやrenderで副作用のあることを行おうという人はいないかと思いますが1、コンストラクタは他にも影響することを行うので、気になる例もあるかと思います。

実際にCodePenで動かして調べてみると、以下のような感じでした。

  • 確かにコンストラクタは2回実行される
  • もう1個生成されたはずのインスタンスは、componentWillUnmountも何も起こさず消滅する(あとからsetStateしようとするとエラーに)

ということで、コンストラクタでやることは「インスタンス変数の設定」、そして「外部に対しては冪等になる仕事」ということになります。

  • 外部に対して破壊的に働くコードについては、componentDidMountに移動させるのが適当でしょう。
  • CodePenでやったような、「あとから値をsetStateする」ような処理も、componentDidMountから動かす(そして、componentWillUnmountした際には正しく中断できるようにする)ことが必要と考えます。

  1. もっとも、自分は過去にrender()内でsetState()しようとしたことがあります。 

27
11
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
27
11