最初に
react-reduxのパフォーマンスについての記事です。
問題となるコード
console.log(store.getState())
//{
// childState1:"hoge"
// childState2:"fuga"
//}
const ParentComponent = () => {
const storeState = useSelector(state=>state);
return (
<>
<ChildComponent text={state.childState1}/>
<ChildComponent text={state.childState2}/>
</>
);
}
const ChildComponent = ({text}) => {
return(
<div>{text}</div>
)
}
何が問題なのか
storeState
はChildComponent
のための値なのに、ParentComponent
のStateとして扱われます。
(厳密にはstateではありませんが、わかりやすくするためにstateとさせてください)
もし、childState1
もしくは、childState2
のどちらかの値が更新されると、ParentComponent
と二つのChildComponent
すべてが再レンダリングされてしまいます。
再レンダリングされるコンポーネントが多くなれば、それだけパフォーマンスも悪くなります。
修正
const ParentComponent = () => {
return (
<>
<ChildComponent objKey={"childState1"}/>
<ChildComponent objKey={"childState2"}/>
</>
);
}
const ChildComponent = ({objKey}) => {
const text = useSelector(state=>state[objKey]);
return(
<div>{text}</div>
)
}
useSelecotorが多く実行されることは問題ではないのか
まず、useSelectorの仕組みについて説明します。
const storeState = useSelector(state=>state)
storeは値が変更されるとuseSeletor
によって登録されたListenerを使ってuseSelectorに通知します。
useSelectorは新しい値と古い値を比較し、違いがあればコンポーネントを再レンダリングします。
ここで、問題となるのがuseSelectorが登録するlistenerの処理量と再レンダリングされるreactコンポーネントの処理量です。
知っての通り、Reactコンポーネントを再レンダリングすると処理量が大きくなります。
useSelectorではlistenerの登録、値の比較、更新のみの処理となります。
よって、storeの値はpropsで受け渡しするよりもuseSelectorで直接取得した方が、パフォーマンスが良くなります。