S
S
shaman602019-01-07 22:39:06
React
shaman60, 2019-01-07 22:39:06

How to correctly call setState from different methods?

The component has 2 methods: add and remove. I want to make a method that updates item. Those. first, we look for the old one with the same data, delete it, and insert a new (updated) one in its place. If I do as in the example below, then the item is simply added, without being removed. How to correctly implement it?

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);
  }
  // Дальше остальные методы, рендер итд...
}

Answer the question

In order to leave comments, you need to log in

1 answer(s)
A
Andrew, 2019-01-08
@shaman60

The fact is that setState does not change the state immediately after the call (not synchronously), but sometime, so it is not known in advance exactly when the state will actually change. Therefore, setState can take both an object and a function (callback) as an argument. And the current actual state is always transferred to this very callback. So your code should be rewritten like this:

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);
  }
  // Дальше остальные методы, рендер итд...
}

Another option is to unbind the add and remove methods from this.state, and pass state directly to them. And this option is more correct, because. it's more explicit, and every call to setState potentially leads to a rerender, which is undesirable.
So something like this:
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));
  }
  // Дальше остальные методы, рендер итд...
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question