React Nativeパフォーマンス向上をHooksで
こんにちは、外資系企業のエンジニアとして働いています。タロイモともうします。
前回はReact Nativeでパフォーマンスを向上するための基礎知識をまとめました。今回は実際にHooksを使いパフォーマンスチューニングをしていきます。
renderItemの無名関数を回避する
FlatListを使用しているときに、FlatListコンポーネントの内側にレンダーアイテムを置くと、親コンポーネントがレンダリングされるたびに、レンダーアイテムもレンダリングされてしまいます。そのため、レンダーアイテムはFlatListの外側に出し、不必要な再レンダリングを防ぎましょう。
Before
export default function ParentComponent() {
const [childState, setChildState] = useState(0);
return(
<FlatList
renderItem={
({item})=>(
<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />
)}
keyExtractor={(item)=>`awesome-child-key-${item.id}`}
/>}
)
}
After
export default function ParentComponent() {
const [childState, setChildState] = useState(0);
//外側に出す。
const awesomeChildListRenderItem = ({item})=>(<AwesomeChild {...item} onPress={(number)=>{setChildState(number)}} />)
const awesomeChildListKeyExtractor = (item)=>(`awesome-child-key-${item.id}`);
return(
<FlatList
renderItem={awesomeChildListRenderItem}
keyExtractor={awesomeChildListKeyExtractor}
/>
)
}
【参考】https://reactnative.dev/docs/optimizing-flatlist-configuration#avoid-anonymous-function-on-renderitem
【参考】https://dev.to/ltsharma24/performance-optimisation-react-native-with-hooks-a77
React.memoとuseCallBackを使う
React.memo()は()の第二引数に比較関数を置きpropsの値に変化があった場合のみ再レンダリングを行います。そのため、第一引数に指定した関数が再レンダリングされそうになった場合に再レンダリングが必要かどうかをチェックし、必要な場合のみ再レンダリングを行います。
React.memo
//関数
const AwesomeChild =({props})=>{
return(
<Text>{props.count}</Text>
)
}
//比較関数
const areEqual=(prevProps, nextProps)=>{
// prevProps.countがnextProps.countが違えば、falseを返し、再レンダリングする。
return prevProps.count === nextProps.count
// そうでなければ、trueを返し、再レンダリングしない。
return true
}
export default React.memo(AwesomeChild,areEqual)
useCallBackはReact.memoと一緒に使う。
before
ButtonコンポーネントはParentComponentの再レンダリングのたびに一緒に再レンダリングされてしまう。
export default ParentComponent()=>{
const [pressCount, setPressCount] = useState(0);
const updateButtonPress = useCallback(() => {
setPressCount(pressCount + 1);
}, [pressCount]);
return (
<View>
<Button onPress={updateButtonPress} title="Add count" />
<Text>{pressCount}</Text>
</View>
);
}
after
ChildComponentはParentComponentの再レンダリングのたびに一緒に再レンダリングされることを防ぐ。※onPressしても、ChildComponentのpropsに変化はないので、第二引数はいらない。
const ChildComponent = React.memo((props) => {
return <Button onPress={props.onPress} title="Add count" />
});
export default ParentComponent()=>{
const [pressCount, setPressCount] = useState(0);
const updateButtonPress = useCallback(() => {
setPressCount(pressCount + 1);
}, [pressCount]);
return (
<View>
<ChildComponent onPress={updateButtonPress}/>
<Text>{pressCount}</Text>
</View>
);
}
【参考】https://sbfl.net/blog/2019/11/12/react-hooks-introduction/
まとめ
今回はReact Hooksを使いパフォーマンスの向上を行う方法を紹介しました。
今後もReact Nativeのパフォーマンス向上の記事を書いていきたいと思います。
ご精読ありがとうございました。