Search code examples
javascriptreactjsevent-handlinguse-effectuse-state

React: Sorting of table not rendering via useEffect or eventHandler?


I am building a table (here it is); Which will have a child component whose job it will be to render the rows of data it gets from props; Problem thus far is:

useEffect does not fire the the function in it which show be triggered by a change in its in default mode i.e. firstName or by lastName in the useState value.

Here is my code:

function TableHeaders({ headerData, handleDataSort }) {
  function convertCamelToTitleCase(text) {
    const result = text.replace(/([A-Z])/g, " $1");
    return result.charAt(0).toUpperCase() + result.slice(1);
  }
  
  return (
   <>
    <thead>
      <th>
        <button onClick={()=> handleDataSort('firstName')}>first - default</button>
        <button onClick={()=> handleDataSort('lastName')}>last</button>
      </th>
      {headerData.map((headerName, index) => {
        return (
        <>
          <th key={index} scope="col">
            {convertCamelToTitleCase(headerName)}
          </th>
        </>
        );
      })}
    </thead>
   </>
  );
}

function TableData({rowData}) {
  return (
    <tbody>
      {rowData.map(({
       company, 
       dateJoined, 
       firstName, 
       id, 
       isSiteAdmin,
       jobTitle,
       lastName,
       state
      }) => {
        return (
       
         <tr key={id}>
           <td></td>
           <td>{id}</td>
           <td>{firstName}</td>
           <td>{lastName}</td>
           <td>{company}</td>
           <td>{jobTitle}</td>
           <td>{state}</td>
           <td>{isSiteAdmin}</td>
           <td>{dateJoined}</td> 
         </tr>
         
        )
      })}
    </tbody>
    )
}

const MemoTableData = React.memo(TableData)

const App = () => {
const [headerData, setHeaderData] = React.useState(() => Object.keys(window.userData[0]));
const [rowData, setRowData] = React.useState([]);
const [sortType, setSortType] = React.useState('firstName')
  
  React.useEffect(() => {
    const sortArray = property => {
      const sorted = [...window.userData].sort((a, b) => {
        return b[property] - a[property]});
      setRowData(sorted);
    };

    sortArray(sortType);
  }, [sortType]);
  
  return (
    <table>
      <caption>Zerocater Frontend Take Home Exam</caption>
      <TableHeaders headerData={headerData} handleDataSort={setSortType} />
      <MemoTableData rowData={rowData} />
    </table>
  );
};

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

Solution

  • The useEffect itself is triggered correctly, so the sortType changes on button clicks accordingly.

    The reason that the table is not updated at all is that your sorting function

    (a, b) => {
      return b[property] - a[property]
    }
    

    returns NaN because a[property] and b[property] are strings.

    What you need is a correct sorting function (reference):

    function compare(a, b) {
      if (a is less than b by some ordering criterion) {
        return -1;
      }
      if (a is greater than b by the ordering criterion) {
        return 1;
      }
      // a must be equal to b
      return 0;
    }