I have the following app that allows me to click on todos in a list and only have one todo selected at a time:
class State {
@observable todos = [
{ id: '1', description: 'Do this' },
{ id: '2', description: 'Do that' },
{ id: '3', description: 'Do this third thing' }
]
}
const state = new State();
const TodoView = observer(({ todo, isSelected, onClick }) => (
<div onClick={onClick}>
{ todo.description } { isSelected && ' (selected)' }
</div>
));
@observer
class App extends Component {
@observable selected = null;
render () {
return <div>
{ state.todos.map((todo) =>
<TodoView
key={todo.id}
todo={todo}
isSelected={this.selected === todo}
onClick={() => this.selected = todo} />
)}
</div>;
}
}
The entire list of todos is re-rendered when I select a new todo. Is there any way to just re-render the selected and deselected todos, without cluttering the state with additional data?
Instead of having a selected observable in the App component that every TodoView relies on, you can use an observable map and give each TodoView an own key to observe. Pass this map as a prop to the TodoView and check if the map has the todo's id as a key. This way only the selected and deselected todos will be re-rendered:
class State {
@observable todos = [
{ id: '1', description: 'Do this' },
{ id: '2', description: 'Do that' },
{ id: '3', description: 'Do this third thing' }
]
}
const state = new State();
const TodoView = observer(({ todo, selectedMap, onClick }) => (
<div onClick={onClick}>
{ todo.description } { selectedMap.has(todo.id) && ' (selected)' }
</div>
));
@observer
class App extends Component {
selectedMap = observable.map({});
onClick = (todo) => {
this.selectedMap.clear();
this.selectedMap.set(todo.id, todo);
};
render () {
return <div>
{ state.todos.map((todo, idx) =>
<TodoView
key={todo.id}
todo={todo}
selectedMap={this.selectedMap}
onClick={() => this.onClick(todo)} />
)}
</div>;
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With