Selectorとは
Reduxでは状態を保存する場所としてStoreという概念が取り入れられています。
そのStoreの状態を扱うときに登場する重要な概念がSelectorです。
一言でいうと、
Selector = Reduxのstateから必要な値だけを取り出すための関数
です。
コンポーネントがStore内のどの値を使うかをSelectorで明確にし、
UIとStore(状態)を疎結合にする役割を果たします。
なぜSelectorが必要なのか?
前提として、Storeにはあらゆる状態が入っています。
各ReactコンポーネントはStore内の状態全体を知る必要はありません。
そこでSelectorを使います。
例えば下記のような状態がstoreに保存されているとします
{
user: { id: 1, name: 'Taro' },
posts: [...],
ui: { loading: false }
}
user.nameの状態を取得するSelectorは下記のように定義します
export const selectUserName = (state: RootState) => state.user.name
Reactコンポーネント側では下記のように呼び出します
const userName = useSelector(selectUserName)
stateに変化があると再実行され、前回と値が異なる場合は再レンダリングされます
shallowEqual
selectorで取得するstateがオブジェクトの場合は要注意です!
取得したstateがオブジェクトの場合、中身の変更がない場合でも別のインスタンスとして生成されるため、
差分があるとみなされ不要な再レンダリングが起こってしまいます。
これを防ぐ仕組みとしてshallowEqual(浅い比較)があります
const selectedData = useSelector(selectorReturningObject, shallowEqual)
このように指定することで厳密等価による判定ではなくなり、不要な再レンダリングを防ぐことができます
下記のようにオブジェクト用のselectorを作っておくのも良いかと思います
import { useSelector, shallowEqual } from 'react-redux'
export function useShallowEqualSelector(selector) {
return useSelector(selector, shallowEqual)
}
取得するstateがオブジェクトかどうかで使い分けが必要になってきますが、私は結構忘れがちです…
フロントのパフォーマンス改善を行う際にこちらをまず疑ってみるのも良いかと思います!
終わりに
最後まで読んでいただきありがとうございます!
今年初めてこの辺りを触り、useShallowEqualSelectorとの使い分けを知らないまま、ガンガン状態を参照していたせいでパフォーマンスを悪くしてしまったのも良い経験です・・・😭
しくじRedux、俺みたいになるな
参考