React setState array not getting sorted

Viewed 2183

My code is this:

handleFavourite = id => {
    const { restaurants } = this.state;
    let newRestaurants = [...restaurants];
    newRestaurants = sort(newRestaurants, 'favourite');
    console.log(newRestaurants); // ALL GOOD
    this.setState({ restaurants: newRestaurants }, () => console.log(this.state.restaurants)); // CONSOLE LOG POSTS OLD DATA
};

So there. The callback function in setState shows old data and in UI nothing gets sorted as well. Why is it that way?

edit: Found the problem. I'm also using static getDerivedStateFromProps and it's resetting the state every time.

3 Answers

I'd be checking this.state.restaurants in componentDidUpdate as that's the best way to see if your component has been updated.

It feels like you're doing things correctly if your first log is indeed correct (it seems an odd way to sort to me, I'd be calling array.sort() on the newRestaurants).

Maybe somewhere after your component updates, something is setting the restaurants back to it's original value again.

handleFavourite seems to work a O.K.

class App extends React.Component {
  state = {
    restaurants: ["a", "b", "c"]
  }
  
  handleFavourite = id => {
    const { restaurants } = this.state;
    let newRestaurants = [...restaurants];
    newRestaurants = sort(newRestaurants, 'favourite');
    console.log(newRestaurants); // ALL GOOD
    this.setState({ restaurants: newRestaurants }, () => console.log(this.state.restaurants)); // CONSOLE LOG POSTS OLD DATA
}

render() {
  const restaurants = this.state.restaurants.map(r => <p>{r}</p>)
  return (
    <div>
      {restaurants}
    <hr/>
    <button onClick={this.handleFavourite}>sort</button>
    </div>
  )
}
}

function sort(r) {
  return r.reverse();
}

ReactDOM.render(<App/>, document.getElementById("root"))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

 newRestaurants = sort(newRestaurants, 'favourite'); 
// This mutates the original array and does not create a new copy.

A workaround is to create a new copy using slice function
    newRestaurants = sort(newRestaurants, 'favourite').slice(); 
    this.setState({ restaurants: newRestaurants });
Related