2019年にReact Hooksが登場して、Reduxもv7.1.0になりReact Hooksに対応したReduxのStoreに接続する方法が増えました。
従来の書き方
connect関数を使う。
新しい書き方
useSelectorとuseDispatchを使う方法、なお、この方法は同じく2019年に登場した「Redux Tool Kit」を使う場合でも一般的になっています。
useSelector
- storeのstateをpresentational componentへ持ってくることができる
- connectしてないコンポーネントでもStoreを参照できる。
- connectしなくてもStoreを参照できるのでContainerコンポーネントが不要になった。
- actionがdispatchされると実行される。
- stateの値が前回と同じであればキャッシュした計算結果を返してくれる。
注意点
以下を意識しないとconnectよりもパフォーマンスが低下します。
1.useSelectorや配列やオブジェクトを返す際はshallowEqualと併用する。
connectだとオブジェクトの中身まで比較してくれていたが、useSelectorの場合はオブジェクト同士を「===」で比較してしまうので、キャッシュされた値が用いられない。
具体的には第二引数にshallowEqualを使うと従来までの比較と同じようにやってくれるので楽です。
1 2 |
import { useSelector, shallowEqual } from 'react-redux' const result = useSelector(state => state.hoge, shallowEqual) |
なお、shallowEqualを使わなくても後述する「reselect」を使うことでもこの再レンダリングの対策はできるみたいです。(メモ化された値を使うため。)
2.重い処理にはreselectを使う。
ここまでは再レンダリングが発生しないようにするための対策でした。
次は、selectorそのものの計算量のパフォーマンスですね。
基本的にuseSelectorはselectorのインスタンスが変わらない限りは再計算は行わないです。ただ、storeの関係ないsliceの関数処理を呼んだ場合でも、再計算は呼ばれまてしまいます。これはselector関数が新しいインスタンスとなるために再計算が行われることになります。そのような処理を扱う場合はreselectを使ってメモ化して再計算が行われないようにしましょう。
useDispatch
- actionをdispatchするために使用する
- connectしなくてもActionを呼び出せるので、Containerコンポーネントが不要になった。
- storeを変更しない限り、返り値のdispatch関数は変更されない
connectとuseSelectorの違い
connect
HOCです。コンポーネントを渡すと以下の作業をすべて行うラッパーコンポーネントを返します。
- storeへのサブスクライブ
- mapStateとmapDispatchの実行
- 結合されたpropsをそのコンポーネントに渡す。
常に、PureComponentやReact.memoと同じように動作しますが、connectはコンポーネントに渡す最終的に結合されたpropsが変更された場合のみに自分のコンポーネントをレンダリングする。
なので、connectを使っているコンポーネントは再レンダリングの影響をかなり小さい部分に止めることが可能。
useSelector
関数コンポーネントの内部で呼び出されるフック。なので、親コンポーネントがレンダリングをされる際に、useSelectorは子コンポーネントのレンダリングを止めることができない。
なので、重いコンポーネントの場合は、React.memoと併用することが必要になる。
この記事へのコメントはありません。