4

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?

Tholle
  • 108,070
  • 19
  • 198
  • 189

1 Answers1

2

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>;
  }
}
Tholle
  • 108,070
  • 19
  • 198
  • 189