ひょんな事から以前書いた React開発環境ではなぜかコンポーネントが2回描画される、しかしconsole.logは1回しか表示されない が解決しました!
もう一度問題を確認しましょう
以下のコードを実行すると、ブラウザーの画面にはcount = 1と表示されるように思えます。
(このコードはReactの設計思想からすると望ましくないコードですが、初心者は書いてしまいがちなコードです。)
import React from 'react'
let count = 0
export const App: React.FC = () => {
count++
console.log(`count: ${count}`)
return (<div>count = {count}</div>)
}
しかし、なぜかcount = 2と表示されます!
ただし、プロダクション(本番)用コードではcount = 1と表示されます。
React 18の新機能を読んでいたら・・・
React 18の変更点に Adding Strict Effects to StrictMode(日本語記事:React 18 alpha版発表まとめ)を読んでいたら、
React は従来からStrictModeというコンポーネントを提供しており、これは“正しく”実装されていないコンポーネントを炙り出すのに有効とされています。例えば、関数コンポーネントの関数をわざと 2 回呼ぶことで、副作用を持ってしまっているコンポーネントを検出できる可能性があります。
と書かれていました! これが原因でした。
StrictMode
create-react-appで作成したアプリのindex.tsxは以下のようにReact 16.3で追加された<React.StrictMode>
コンポーネントの中でアプリを実行しています。
import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById('root')
)
詳細はstrict モードに書かれていますが、
- 安全でないライフサイクルの特定
- レガシーな文字列 ref API の使用に対する警告
- 非推奨な findDOMNode の使用に対する警告
- 意図しない副作用の検出
- レガシーなコンテクスト API の検出
のチェックを行っています。意図しない副作用の検出のために、Appコンポーネントを2回呼び出しているそうです。
ちゃんとドキュメントに書かれていましたね 😔
StrictModeを外して実行するとcount = 1と表示されました。StrictModeの有効性が証明されていますね!
import React from 'react'
import ReactDOM from 'react-dom'
import { App } from './App'
ReactDOM.render(
<App />,
document.getElementById('root')
)
React 18のStrictMode
最後にReact 18への予習シリーズ的には、React 18でのStrictModeの変更に付いて書いておきたいと思います。
React 18のStrictModeではコンポーネントのmount → unmount → mountを行うようになるそうです。mount(コンポーネントの作成・表示)が2回おこなわれます。現在と大きく違うのはuseEffect
Hockが1回ではなく、2回実行されるようになります。
これは将来導入されるOffscreenAPIが入ると、コンポーネントが生成されているが表示されていない状態が追加されることへの準備だそうです。useEffect
Hockが最初にしか実行されないという前提でコードを書いてはいけないということです。
まとめ
StrictModeではAppコンポーネントを2回呼び出されることは、ドキュメントにちゃんと書かれていました。 Reactドキュメントの目次(右側)に知らないものが登場したら必ず読んでおきましょう 😇