@shaman60

Как правильно вызвать setState из разных методов?

В компоненте есть 2 метода: добавить и удалить. Я хочу сделать метод который обновляет item. Т.е. вначале ищем старый с такими же данными, удаляем его, а на его место вставляем новый (обновленный). Если делаю как на примере ниже, то item просто добавляется, без удаления. Как грамотно это реализовать ?
export default class App extends Component {
  state = {
    items: []
  };
  add = (item) => {
    this.setState({
        items: [...this.state.items, item]
    });
  };
  remove = (id) => {
    let newItem = this.state.favorites.slice();
    newList.splice(index, 1);
    this.setState( {
        items: newList
    });
  };
  updateItem = (id, item) => {
    item.text = 'blabla';
    this.remove(id);
    this.add(item);
  }
  // Дальше остальные методы, рендер итд...
}
  • Вопрос задан
  • 1034 просмотра
Решения вопроса 2
iCoderXXI
@iCoderXXI
React.JS/FrontEnd engineer
Дело в том, что setState меняет состояние не сразу после вызова (не синхронно), а когда-нибудь, поэтому неизвестно заранее, когда именно state будет реально изменени. Поэтому setState в качестве аргумента может принимать как объект так и функцию (коллбэк). И вот в этот самый коллбэк всегда передается текущее актуальное состояние. Поэтому твой код надо переписать как-то так:

export default class App extends Component {
  state = {
    items: []
  };

  add = (item) => {
    this.setState((state) => ({
        ...state,
        items: [...state.items, item]
    }));
  };

  remove = (id) => {
    this.setState((state) => 
      return {
        ...state,
        items: state.filter(item => item.id !== id),
      }
    );
  };

  updateItem = (id, item) => {
    item.text = 'blabla';
    this.remove(id);
    this.add(item);
  }
  // Дальше остальные методы, рендер итд...
}


Другой вариант - отвязать методы add и remove от this.state, и передавать им state непосредственно. И этот вариант более правильный, т.к. он более явный, кроме того каждый вызов setState потенциально ведет к перерендеру, что нежелательно.

Поэтому как-то так:

export default class App extends Component {
  state = {
    items: []
  };

  add = (state, item) => ({
    ...state,
    items: [...state.items, item]
  });

  remove = (state, id) => ({
    ...state,
    items: state.filter(item => item.id !== id),
  });

  updateItem = (id, item) => {
    item.text = 'blabla';
    this.setState(state =>  this.add(this.remove(state, id), item));
  }
  // Дальше остальные методы, рендер итд...
}
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы