8

I'm doing a simple sort of an array with react hooks, but its not updating state. Can anyone point out what I'm going here?

import React, { useState } from "react";
import ReactDOM from "react-dom";

import "./styles.css";

const dogs = [{ name: "fido", age: 22 }, { name: "will", age: 50 }];

function App() {
  const [dogList, setDogList] = useState(dogs);

  const sortByAge = () => {
    const sorted = dogList.sort((a, b) => {
      return b.age - a.age;
    });
    setDogList(sorted);
    alert(sorted[0].name);
  };

  return (
    <div>
      {dogs.map((dog, i) => {
        return <p key={i}>{dog.name}</p>;
      })}
      <div onClick={sortByAge}>sort by age</div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);
1
  • do you have a code example? Commented Sep 24, 2019 at 20:48

3 Answers 3

17

First: because Array.prototype.sort() is in place, clone before you sort:

const sorted = [...dogList].sort((a, b) => {
  return b.age - a.age;
});

Without this the change detection will not detect the array changed.

You call map on dogs. Fix:

  return (
    <div>
      {dogList.map((dog, i) => {
        return <p key={i}>{dog.name}</p>;
      })}
      <div onClick={sortByAge}>sort by age</div>
    </div>
  );

Demo: https://jsfiddle.net/acdcjunior/kpwb8sq2/1/

Sign up to request clarification or add additional context in comments.

4 Comments

I knew it was something related to this ty!
@acdcjunior I'm having the same problem. I tried your solution but it didn't work. Woud you mind taking a look at my Stack post stackoverflow.com/questions/75667791/…
Can you explain why spreading the state into an array with the spread operator ([...dogList].sort) is different from just using dogList.sort?
@Cjmaret because the .sort methods sorts "in place", meaning it changes the original array. Doing [...dogList] creates a clone of the original array and then sorts the clone. This leaves the original array unmodified.
3

const dogs = [{ name: "fido", age: 22 }, { name: "will", age: 50 }];
class Application extends React.Component {
  state = {dogList: dogs};

  sortByAge = () => {
    const sorted = this.state.dogList.sort((a, b) => {
      return b.age - a.age;
    });
    this.setState({dogList: sorted});
  };

  render() {
    return (
      <div>
        {this.state.dogList.map((dog, i) => {
          return <p key={i}>{dog.name}</p>;
        })}
        <button onClick={this.sortByAge}>sort by age</button>
      </div>
    );
  }
}
React.render(<Application />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/0.13.0/react.min.js"></script>
<div id="root"></div>

This is the code using hooks

import React, { useState } from "react";
import ReactDOM from "react-dom";
import "./styles.css";

const dogs = [{ name: "fido", age: 22 }, { name: "will", age: 50 }];
function Application() {
  const [dogList, setDogList] = useState(dogs);
  const sortByAge = () => {
    const sorted = dogList.sort((a, b) => {
      return b.age - a.age;
    });
    setDogList(sorted);
  };
  return (
    <div>
      {dogList.map((dog, i) => {
        return <p key={i}>{dog.name}</p>;
      })}
      <button onClick={sortByAge}>sort by age</button>
    </div>
  );
}

ReactDOM.render(<Application />, document.getElementById('root'));

4 Comments

Nice answer. Just add some explanation and context next time.
Why did you provide an answer using a class component when the request was for a solution using hooks? (Your answer is not wrong btw)
@evolutionxbox. because I want to show you a live example with code snippet. so I use class component. but if you want I will provide example which uses the hooks.
No no that’s fine. It just seemed odd to me that’s all
1

sort by name example...

const dogs = [{ name: "bido", age: 22 }, { name: "aill", age: 50 }, { name: "test", age: 90 }];

function App() {
  const [dogList, setDogList] = React.useState(dogs);
  function compare(a, b) 
{
  if (a.name > b.name) return 1;
  if (a.name < b.name) return -1;
  return 0;
}
  const sortByAge = () =>
{

    const sorted = [...dogList].sort(compare);//calling compare function
    setDogList(sorted);//storing sorted values
    
  };

  return (
    <div>
      {dogList.map((dog, i) => {
        return <p key={i}>{dog.name}{dog.age}</p>;
      })}
      <div onClick={sortByAge}>sort by age</div>
    </div>
  );
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.