【React】Strictモードの挙動【バージョン18による】

## はじめに
2022年3月29日に、React のバージョン 18 がリリースされましたね。

弊社でも6月からReact新機能勉強会が開始されたので、今回は予習を兼ねて勉強会の範囲内から物によって範囲外のものについてもまとめていこうかなと思います！

今回はStrictModeの挙動が**React18**にバージョンアップした際に変更されたので説明していきます。



## そもそもStrictモードとは?
以下MDNから引用
> JavaScript のStrictは、 JavaScript の制限された変化形を利用する方法であり、それによって暗黙的に "sloppy mode" をやめることができます。厳格モードは単なるサブセットではありません。通常のコードとは意図的に異なる意味を持っています。

端的にいうと**javascriptのコードを通常より厳しくエラーチェックする**ことのできる仕組みのことです。

メリットとして
- **将来の ECMAScript で予定されている構文(キーワードを変数名として使用するなど) を禁止して、バージョンが変わった後の動作を修正を無くことができる。**
- **Javascriptの構文としてはエラーにはならないが、バグを誘発するようなコードを検出することができる**

などがあげられます。

## React18でのStrictモードの新たな挙動
以下React公式より引用
> 将来的に、React が state を保ったままで UI の一部分を追加・削除できるような機能を導入したいと考えています。
この機能により、React の標準状態でのパフォーマンスが向上しますが、コンポーネントは副作用が何度も登録されたり破棄されたりすることに対して耐性を持つことが必要になります。ほとんどの副作用は何の変更もなく動作しますが、一部の副作用は一度しか登録・破棄されないものと想定しています。
この問題に気付きやすくするために、React 18 は strict モードに新しい開発時専用のチェックを導入します。この新しいチェックは、コンポーネントが初めてマウントされるたびに、すべてのコンポーネントを自動的にアンマウント・再マウントし、かつ 2 回目のマウントで以前の state を復元します。

パッと見てわかる方なら **「完全に理解した！」** となるかも知れませんが、自分は頭の中でスッキリしなかったので実コードを用いて検証してみました。

今回は`React17`と`React18`のコードを使用して動作の方を見ていきましょう!

### React17の挙動

以下の記事を見ながらReact17の環境構築をしてください！

https://qiita.com/kim_t0814/items/d90254c807c7280c2db7


環境構築が終わったら以下のコードを`src/App.tsx`に記述してください。

```App.tsx
import { useEffect } from 'react';
import logo from './logo.svg';
import './App.css';

function App() {
  console.log('App rendered!')

  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.tsx</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;
```

![スクリーンショット 2023-06-18 23.57.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/f957968e-621e-3014-6998-2208a1546cec.png)

上記のスクリーンショットで分かるように、Appコンポーネントが1度だけレンダリングされていることが分かると思います!

### React18の挙動
同様のコードを`src/App.tsx`に記述してください。

そうすると...

![スクリーンショット 2023-06-19 0.11.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/57978482-12ad-3b12-a508-10425b65e71a.png)

`App rendaring!`という文章が2回出力されており、2回`App`コンポーネントが
レンダリングされているのがわかると思います。
このような形でReact18では、コンポーネントが表示された瞬間にそれを1度破棄して、
またすぐ表示するみたいなことを裏側で行うような動きをしています。

なぜ、このような一見無駄な動きをしているのかというと今後のReactの**機能追加を想定**しているためです。

具体的にいうと、`オフスクリーン(offscreen)`という機能が追加されると言われています。
タブ遷移のように画面からは1度遷移させてまた元の画面に戻って状態を復活させたりなど、
ユーザーが**高速**に表示させる際にその時の状態をステートを復元させることでよりユーザーに**高速**
にアプリを使ってもらえるような仕組みが提供されようとしています。

上記で説明した`オフスクリーン(offsereen)`でアプリが再マウントされるような動きになってしまうため、
React18の**Stricモード**では2回レンダリングされる仕様となっております。

### **Strictモード**をオフにしたい際は...?

`src/index.tsx`を下記の部分を削除してください。
```diff_tsx
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(
  document.getElementById('root') as HTMLElement
);
root.render(
-  <React.StrictMode>
    <App />
-  </React.StrictMode>
);

// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
reportWebVitals();
```

そうすると、**React17**以前同様に1度だけレンダリングされます。

また、**Stricモード**に関しては開発環境のみ適用されるもので
本番環境では1回のレンダリングの動きしかしないことを覚えておいてください!

## 最後に
なるべく、**Strictモード**をオンにしてアプリをアンマント・再マウントしても
開発環境で不具合が起きないような作り方をしていくのが今後の**React**においての開発に
重要になっていくのかなと思います。

今回の内容のウケが良ければ、またReact18の新機能関連の記事について
投稿していこうかなと思います!

本記事が**React18**を学習している方の参考になれば嬉しいです！

## 参考文献・動画
- [今後のフロントエンド開発で必須知識となるReact v18の機能を丁寧に理解する](https://www.udemy.com/course/react_v18/)
- [React v18.0 公式](https://ja.legacy.reactjs.org/blog/2022/03/29/react-v18.html)
- [MDN 厳格モード](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Strict_mode)
- [(初心者向け) JavaScript の Strict モードの概要](https://qiita.com/tadnakam/items/700bd526b33f8f92702a)