react-reduxをv5からv8にアップデートした
react-reduxの破壊的変更まとめメモ。
文脈として、 2019年9月にやろうとして破壊的変更があって後回しとしていて、そのまま自分がプロジェクト離れてたから今の今まで後回しとなっていた。
Reduxの開発者ツール周りの整備をするにしても、まずここまで古いバージョンを使ってたら問題が発生しても、問題の箇所の切り分けが困難だろうという判断の元、アップデートを行うことにした。
破壊的変更まとめ
メジャーバージョンアップ以外で破壊的変更は行われてないだろうという楽観的な予測の上、現在v5でv8にする差分のリリースノートをまとめる。
Releases · reduxjs/react-redux をそのまま参照して作業するのはbetaとかrcとかマイナーアップデートとかが混ざるので難しい。
最新版でもサポートされているReactを使っていることは確認済みなので、 Reactのバージョン要求レベルの変更とかはメモしない。今回問題になりそうな変更点だけメモしていきたい。
v6.0.0
Release v6.0.0 · reduxjs/react-redux
withRef
が何か変わったけど使ってないはず- propとしてstoreを渡せなくなった
- レガシーコンテキストからstoreにアクセスできなくなった(?)
- react-router関係が壊れるかもしれない
- react-routerも古いバージョンを使っているのでバージョンアップが必要かもしれないが、激しく破壊的変更があることを確認したのでなるべく別の作業で行いたい
componentWillMount
関係で挙動が変わった- これ昔は使ってたけどちゃんとunsafe含めて消したので今では問題にならないはず
React.createContext()
を使うようになった
v7.0.1
Release v7.0.1 · reduxjs/react-redux
v7.0.0のドキュメントは存在しない。
なんか内部的変更だけど諸事情でメジャーバージョンアップするようにしたらしい。
connect
がReact.memo()
を使ってオブジェクトを返すようになったので、コンポーネントが関数とは限らなくなった- 明記しただけで元から間違ってたらしい?
- v6で禁止となったpropでstoreを渡す機能が復活した
- バッチアップデート周りで色々あるらしいが多分今回は関係がない
v8.0.0
Release v8.0.0 · reduxjs/react-redux
変更ページがデカすぎて一発でDeepL翻訳できない。
高度なAPIを使っていない場合は基本的に互換性があるらしい。
本体がTypeScriptで書かれるようになったのでtypes系のパッケージが不要になった。
実際に発生した問題
遷移した後一部コンポーネントがロードされない
componentWillMount
消したはずだと思っていたけれど警告には出てくるし、一部ロードが出来なくなっている。
依存ライブラリの問題だと思われる。
依存ライブラリを更新して警告を消したが、依然としてロードされない。
componentWillMount
は関係ないらしい。
全然分からない、ちゃんとReduxのdispatchで新規に生成したデータを設定しているはずなのに、単純な関数コンポーネントたちで再描画が発生せずローディングのままになっている。
ちゃんと破壊的変更は追ったはずなんですが… react-reduxのアップデートでstore周りが更新されて古い方法だと動かなくなっている可能性がありますね。
'createStore' is deprecated.
とも出ていますし。
@reduxjs/toolkit
のSliceなどの新規機能を使う予定は今のところ無いのですが、とりあえずそれが公式の推奨方法なので使います。
@reduxjs/toolkit
の生成手法に変更してみたら即座に例外が発生しました。関係ない所のようだが、
stateの可変を検知して例外を出してくれているようです。
ReduxのStateが変更されたのに再レンダリングされない問題 - Qiita とか見て一回ミューテーションを検査してみるかと思っていたので、公式でこういうのが提供されているのは嬉しいですね。
しかし頑張って自分も弾いていると思っていたのですが可変が存在するのか… やはりJavaScript/TypeScriptでRedux使って管理開発するのは難しそうですね。もちろんReduxが悪いわけではなく可変をガンガン出来てしまう言語の方に悪さがあるのですが。
関連性の無さそうなデータなので関係ないだろうなと思いましたが、やはり特に今回のバグには関係ないようです。
やっぱりreact-routerを最新版にしないといけないんですかね、かなりの破壊的変更があるようなのであまりやりたくないのですが…
useSelectorを使うと正常に動作した
解決しないだろうと思いつつuseSelector
をgetState
の代わりに使ってみると、解決してしまった。
解決しても既存の巨大なコードのgetState
を全て書き換えるというのは、現実的な選択肢ではあるのですが、ひたすらに面倒くさいという問題があります。
いや、ちゃんとgetState
で動くようにしましょう。
useSelector
でちゃんと動くというのは、多分connect
周りの設定をミスっているからなんだと思います。
defaultProps
をやめたら通った、初期化時点の問題?
コンポーネントのdefaultProps
でpropsを初期化するのをやめて、
JavaScriptネイティブの関数のデフォルト引数の機能で初期化するようにしたら、問題なくgetState
でも更新を検知してロードが終わるようになりました。
何が起きているのか今一つ分かっていない。
defaultProps
での初期化がReduxの初期化の前に行われたりして正常にコンポーネントが登録されないとかだろうか。
ちゃんと内容を把握するべきかもしれないが、気が進まない。何故かというと、
PropTypesなんてものはTypeScriptによって抹消するべきもので、その際にもJavaScript標準のデフォルト引数で対処するのは極めて正しいからです。
PropTypesを避けることで問題が解決するならば何も問題はなく、これを調べてもPropTypesでしかもgetState
を使い、カスタムHooksではない旧世代のReact-Reduxにおける限定的なトラブルの知識しか身につかない。
PropTypesでの処理を消して解決するのならば万々歳ですし、どちらにしてもTypeScript移行時に同じことをする予定でした。
他のコードでも同じようなことをしていないか確かめて、全てデフォルト引数に書き換えた方が良いだろう。
しかし不思議だ。前から動かないというのならともかく、アップデートで動かなくなるとは…
レガシーコンテキストからstoreにアクセスできなくなった
という破壊的変更が影響しているのかもしれない。しかし完全にアクセス出来なくなったのではなく、アクセスは出来るけどstore更新時に再レンダリングされなくなったというものなのですよね。一応破壊的変更には一通り目を通したのですが、元から推奨されていない行為をしていたということで決着ですかね。いやしかし、一昔前はPropTypesは推奨だったんですが。