とりあえず実装すると以下のような形か。
import React from 'react'; const Counter = () => { const [count, setCount] = React.useState(0); const handleClick = React.useCallback((e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { setCount(c => c + 1); }, []); return ( <div> <p>Count: {count}</p> <input type="button" value="Up" handleClick={handleClick}> </div> ); }; export { Counter }
カウント処理をuseCallbackで無駄に生成しないようにしている。
このカウント処理を、ほかのコンポーネント、特に子のコンポーネントで実施したいことがある。 子コンポーネントをRichButtonとすると、こんな感じか。
import React from 'react'; import { RichButton } from './RichButton'; const Counter = () => { const [count, setCount] = React.useState(0); const handleClick = React.useCallback((e: React.MouseEvent<HTMLInputElement, MouseEvent>) => { setCount(c => c + 1); }, []); return ( <div> <p>Count: {count}</p> <RichButton handleClick={handleClick}></RichButton> </div> ); }; export { Counter }
ただ、Reactは親コンポーネントが更新されると、子コンポーネントも更新されるらしい。
今回だと、Counter(親コンポーネント)で管理しているcountを更新するとCounterコンポーネント以下のコンポーネントすべてに更新がかかる。しかし、RichButtonなどは状態が変わっていない(そもそも状態を持っていない)ので別に更新する必要はない。
その場合は、React.memoで関数コンポーネントをラップする必要があるらしい。
import React from 'react'; interface Prop { handleClick: (event: React.MouseEvent<HTMLInputElement, MouseEvent>) => void; } const RichButton = React.memo((props: Prop) => { const { handleClick } = props; return <input type="button" value="Button" onClick={handleClick}></input>; }); export { RichButton }
ただ、memoするのにもコストはかかるので、どちらが効果的かはちゃんと計測していく必要があるらしい。 React、なんとなくでも動いちゃうが、パフォーマンスを気にする場合は結構めんどくさい。