How to set an array with React Hooks?
Asked Answered
W

1

2

I'm following a guide I found on StackOverflow to sort an array in order to change the column order desc/asc of a table I'm populating with an API.

I'm using this Stack answer: sort an array with react hooks

Here is the code:

import { useEffect, useState } from 'react';
import './App.css';
import { IoCaretDown } from "react-icons/io5";
import { IoCaretUp } from "react-icons/io5";

function Countries() {
  const sortByName = () => {
    const sorted = [...data].sort((a, b) => {
      console.log('presort', a.name.common, b.name.common)
      return b.name.common - a.name.common;
    });
    console.log('sorted', sorted);
    setData(sorted);
    console.log('data sorted', data);
  };


  const [data, setData] = useState([]);
  useEffect(() => {
    fetch('https://restcountries.com/v3.1/all?fields=name,continents,population,flag')
      .then((resp) => resp.json())
      .then((apiData) => {
        setData(apiData);
      }, []);
  });
  return (
    <div className="app-container">
      <table>
        <thead>
          <tr>
            <th onClick={sortByName}>Name
              <IoCaretDown/>
              <IoCaretUp/>
              
            </th>
            <th>Continent</th>
            <th>Population</th>
            <th>Flag</th>
          </tr>
        </thead>
        <tbody>
          {data.map((country) => (
            <tr  key={country.flag}>
              <td>{country.name.common}</td>
              <td>{country.continents}</td>
              <td>{country.population}</td>
              <td>{country.flag}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </div>
  );
}

export default Countries;

I'm using the exact same sort as mentioned in the original Stack answer:

const sortByName = () => { const sorted = [...data].sort((a, b) => { console.log('presort', a.name.common, b.name.common) return b.name.common - a.name.common; }); console.log('sorted', sorted); setData(sorted); console.log('data sorted', data); };

But the console.logs show the array unchanged:

enter image description here

I added a console log in the hook to see if the name references are accurate and they're appearing in the log: enter image description here It's not changing the order at all in the array.

Any help would be greatly appreciated.

Wolfson answered 7/3, 2023 at 22:26 Comment(0)
T
1

The first problem is in your sorting method, here is how you sort a table of strings

const sortByName = () => {
 const sorted = [...data].sort((a, b) => {
   if (b.name.common > a.name.common) {
     return -1;
   }
   if (b.name.common > a.name.common) {
     return 1;
   }
   return 0;
  });
 setData(sorted);
};

The second problem is your useEffect, it does execute after each render and set again the data to the default value (not sorted), you have to add an empty array as dependency to make it execute the first time only

 useEffect(() => {
  fetch(
     'https://restcountries.com/v3.1/all? 
     fields=name,continents,population,flag'
   ).then((resp) => resp.json())
    .then((apiData) => {
      setData(apiData);
   }, []);
 }, []);

Here is a working example https://stackblitz.com/edit/react-rmgzfz?file=src%2FApp.js

Tagore answered 7/3, 2023 at 22:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.