I made a multi selectable list and have been trying to improve its re-rendering performance. The below code shows what I made (in my actual project, a list is much longer). Currently, when I click a list item, it re-renders every row. I want to render only a clicked row. It seems it is possible with React.memo, React.useCallback, but I haven't succeeded to use them properly for this use cases. Any feedback is welcomed! Thanks in advance.
<div id="app" />
const animals = ['Cat', 'Dog', 'Bird', 'Fish']
interface AnimalProps {
selected: boolean;
name: string;
onClick: (name: string) => void;
}
const Animal = ({selected, name, onClick}: AnimalProps) => (
<div onClick={onClick}>{`[${selected ? 'X' : ' '}]`} {name}</div>
)
const useFilter = (initialValue: string[]) => {
const [items, setItems] = React.useState<string[]>(initialValue)
const makeOnClick = (item: string) => () => {
const ix = items.indexOf(item)
const newItems = (ix > -1) ?
[...items.slice(0, ix), ...items.slice(ix + 1)]
:
[...items, item]
setItems(newItems)
}
const isSelected = (item: string) => items.indexOf(item) > -1
return { items, makeOnClick, isSelected };
}
const App = () => {
const {items, makeOnClick, isSelected} = useFilter([])
return (
<div>
<ul>
{animals.map(i => (
<Animal name={i} selected={isSelected(i)} onClick={makeOnClick(i)} key={i} />
))}
</ul>
<div>Selected: {items.join(', ')}</div>
</div>
)
}
ReactDOM.render(<App />, document.querySelector('#app'))
"react": "17.0.2",
"react-dom": "17.0.2",