Redux Toolkitでシリアライズ化できない値を扱う方法

## はじめに
弊社のプロダクトでは、アラートの状態を[Redux Toolkit](https://redux-toolkit.js.org/)で管理しています。
詳細な実装については今回は触れませんが、例えば「保存しました」というアラートを表示したいときは以下のように書いています。
```typescript
dispatch(alertActions.open({ description: '保存しました' }))
```
このdescriptionにstring型ではなく、ReactNode型を渡す必要がありました。
そこで型を変更してみると、見たことのないエラーが発生しました。
その理由と、解消方法について紹介します。

先に結論を書きます。

:::note alert
- Redux storeにシリアライズ化できない値を格納するのは非推奨
- `serializableCheck`を無効にすれば、シリアライズ化できない値を格納することが可能になる
- `serializableCheck`は以下のように個別で設定できる
```typescript:
configureStore({
  //...
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        // Ignore these action types
        ignoredActions: ['your/action/type'],
        // Ignore these field paths in all actions
        ignoredActionPaths: ['meta.arg', 'payload.timestamp'],
        // Ignore these paths in the state
        ignoredPaths: ['items.dates'],
      },
    }),
})
```
:::

### 余談
なぜReactNode型を渡す必要があったのかについて、触れておきます。
プロダクトを多言語対応させるために、[react-i18next](https://react.i18next.com/)を導入しています。
基本的には[`t`関数](https://react.i18next.com/latest/usetranslation-hook)を使用して`t('保存しました')`のようにラベルを指定しています。しかし、`<a>`タグや`<br>`タグなどを含めたラベルにしたい場合、`t`関数だけでは実装できません。このようなときに[`<Trans>`コンポーネント](https://react.i18next.com/latest/trans-component)を使用します。
この`<Trans>`コンポーネントの返り値はReactNode型です。今回は`<Trans>`コンポーネントを使用したかったため、型を変更する必要がありました。

## 発生したエラー
descriptionにReactNode型を渡せるようにするため、`description: string | ReactNode`に変更しました。
そしてアラートを表示したとき事件が起こりました🚨
```:エラー文
A non-serializable value was detected in the state, in the path: `alerts.description.$$typeof`. Value:
["symbol" failed to stringify]
Take a look at the reducer(s) handling this action type:alerts/open.
(See https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)
```
「A non-serializable value was detected in the state」ってなんだ？🧐
調べてみましょう！

## シリアライズ化ってなんですの？？
シリアライズ化とは、**データ構造やオブジェクトを保存や送信が可能な形式（通常は文字列形式）に変換するプロセスのこと**です。

シリアライズ化ができない値には、関数、Promise、Symbol、MapやSetなどの特殊なオブジェクト、クラスインスタンスなどが含まれます。これらの値は、シリアライズ化の過程で失われたり、正しく再現できなかったりするため、シリアライズ化には適していません。

エラー文から、今回はSymbolをシリアライズ化できないよと言われているようです😢

## storeにシリアライズ化できない値を格納するのは非推奨
エラー文に載っていた[公式ドキュメント](https://redux.js.org/faq/organizing-state#can-i-put-functions-promises-or-other-non-serializable-items-in-my-store-state)を調べてみました。

> It is highly recommended that you only put plain serializable objects, arrays, and primitives into your store. It's technically possible to insert non-serializable items into the store, but doing so can break the ability to persist and rehydrate the contents of a store, as well as interfere with time-travel debugging.

「*storeには、プレーンなシリアライズ可能なオブジェクト、配列、プリミティブ値のみを格納することを強く推奨する*」と書かれていますね。
**シリアライズ化できない値を入れることもできるけど、非推奨**のようです。

## 解決方法
シリアライズ化できない値を入れることは推奨はされませんが、storeの設定を変更すれば可能です🎉
[公式ドキュメント](https://redux-toolkit.js.org/usage/usage-guide#working-with-non-serializable-data)で方法が紹介されていました。こちらを参考に、storeの設定を変更してみました。
```typescript
export const store = configureStore({
  middleware: (getDefaultMiddleware) =>
    getDefaultMiddleware({
      serializableCheck: {
        ignoredActions: ['alerts/open'],
        ignoredPaths: ['alerts.description']
      }
    }),
  // ...
```
これでアラートを表示してもエラーは発生しなくなりました。

## 疑問
### なぜシリアライズ化できない値を入れることが非推奨??
そもそもなぜシリアライズ化できない値を入れることが非推奨なのでしょうか。

実は公式ドキュメントにも書かれているこの理由がよくわかリません😢

1つは**Redux DevToolsなどのデバッグツールがうまく機能しない**からです。これは実際にRedux DevToolsで検証できたので納得できました。storeの設定を変更後にデバッグしてみたところ、descriptionで表示しているラベルを確認することはできませんでした。デバッグしてもstoreに格納されている情報を見ることができなくなってしまうから、非推奨ということだと思われます。

他の理由がわかりませんでした。
> but doing so can break the ability to persist and rehydrate the contents of a store, 

直訳すると「*storeの内容の永続化と再水和化の機能が損なわれる*」ですが、永続化と再水和化が何を指すのかがわかりません…ここは別途調べておこうと思います💡

### `$$typeof`ってなんですの??
ReactNode型でdescriptionを指定しましたが、エラー文で引っかかったのは「*Symbolをシリアライズ化できない*」でした。
よくエラー文を読んでみると、`alerts.description.$$typeof`と書いてあります。想像ですが、React Nodeには`$$typeof`プロパティが存在するのではないでしょうか。そしてこの`$$typeof`プロパティがSymbol型なのではないでしょうか。ここも別途調査したいです。

## 終わりに
公式で非推奨になっている内容を設定を変更することで無理やり実装しました。
アラートに関する情報はstoreに保持し続けておく必要がないし、デバッグで表示内容を確認したいこともなさそうなので、今のところは問題なさそうです。
「永続化と再水和化」、「`$$typeof`」については、調べておこうと思います。