1

My issue similar to this, but not the same.

I'm trying to sort an array of objects using localeCompare. It has no reason not to work, but it's not working. Somehow I'm doing something right./sigh/

This is how I fetch the data

  const [data, setData] = useState([]);
  const [isBusy, setBusy] = useState(true)

  useEffect(() => {
    console.log('I was run once');
    async function fetchData() {
      const url = `${
        process.env.REACT_APP_API_BASE
        }/api/v1/endpoint/`;

      axios.get(url).then((response: any) => {
        setBusy(false);
        setData(response.data.results)
        console.log(response.data.results);
      });
    }

    fetchData();
  }, [])

This is the sorting function

  function onSort(event: any, sortKey: string) {
    const newData = data;
    newData.sort((a: any, b: any): any => {
      a[sortKey].toString().localeCompare(b[sortKey]);
    })
    setData(newData);
  }

A typical array of objects is like this

[
  {
    "avatar": "big",
    "name": "Username",
  },
  {
    "avatar": "small",
    "name": "Rex",
  },
  {
    "avatar": "medium",
    "name": "Duh",
  }
]

Then the table header has this

<th scope="col" className="text-center" onClick={e => onSort(e, 'name')}>Name</th>

Although the onSort() function runs without any errors, the objects don't get sorted as per the sortKey

Am I using the localeCompare wrongly? What can I do to make the above right?

Also, the setData, I believe should update the data and thus trigger a rebuild of the table, which seems to be happening, because if I pass in an empty array to the setData, the table blanks.

edit:

The HTML part

              ...
              return (
                <div>
                  <table className="table table-hover">
                    <thead>
                      <tr>
                        <th onClick={e => onSort(e, 'avatar')}>Avatar</th>
                        <th onClick={e => onSort(e, 'name')}>Name</th>
                    </thead>
                    <tbody>
                      {data && data.map((item: any, index: any) => {
                        return (
                          <tr key={index}>
                            <th>{{ item.avatar}}</th>
                            <td>{item.name}</td>
                            <td className="text-center" style={{ 'fontSize': '32px', 'color': '#981c1e' }}>0</td>
                          </tr>
                        )
                      })}

                    </tbody>
                  </table>
                 </div>
              ...

If I understand, if the setData triggers a data change, the render re-renders?

3
  • 2
    See the linked question's answers, your arrow function has no return value. Either newData.sort((a: any, b: any): any => { return a[sortKey].toString().localeCompare(b[sortKey]); }) (added return) or newData.sort((a: any, b: any): any => a[sortKey].toString().localeCompare(b[sortKey])) (no {}). Commented Nov 22, 2019 at 15:51
  • 1
    You can't set state with a mutated version because React won't render You should do: const newData = [...data]; Commented Nov 22, 2019 at 17:34
  • @HMR You're right. That's the solution. Commented Nov 23, 2019 at 21:30

1 Answer 1

5

You need a return statement by using curly brackets in an arrow function

newData.sort((a: any, b: any): any => {
    return a[sortKey].toString().localeCompare(b[sortKey]);
});
Sign up to request clarification or add additional context in comments.

5 Comments

It might appear as the lack of return being the problem, but it's not. With return doesn't still update.
@KhoPhi, you need to update the html part as well after sorting.
@NinaScholz Updated with HTML. To my understanding, that re-rendering is automatically taken care of, if setData is triggered, no?
i don't know react.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.