Mateen Kazia
Mateen Kazia

Reputation: 349

React/Javascript Sort complex function

I'm trying to handle a sort function that toggles between dsc and asc. It also needs to handle a certain table column name which is referred to as "header". The expected outcome is to sort either "days" or "station" and have it toggle separately between dsc and asc.

handleClick={(val: any, header: string) =>
  val((val: any) => {
    const result = [...val].sort((a: any, b: any) => {
      return sortOrder === 'asc'
        ? header === 'Station'
          ? b.station - a.station
          : b.days - a.days
        : header === 'Station'
          ? a.station - b.station
          : a.days - b.days;
    });
    setSortOrder(sortOrder === 'asc' ? 'dsc' : 'asc');
    return result;
  })
}

This is my current function station filters properly but "Days Since Last Event" doesn't seem to work.

This is the handleClick on the child function

onClick={() => props.handleClick(setFilteredData, header)}

This is the sample of the data

[
  {
    days: 23,
    station: "Braidwood",
  },
  {
    days: 18,
    station: "Byron",
  },
  {
    days: 28,
    station: "Byron",
  },
  {
    days: 32,
    station: "Calvert Cliffs",
  },
  {
    days: 20,
    station: "Dresden",
  },
  {
    days: 320,
    station: "Dresden",
  },
];

Upvotes: 1

Views: 156

Answers (1)

Drew Reese
Drew Reese

Reputation: 202618

Issues

As-written, your handler sorts a copy of the filteredData and then toggles the sorting order. This means the actual order is always inverted from the current sortOrder state.

If I had to guess, I would say the onClick handler is supposed to toggle the sorting order, and then you want the filteredData state to be resorted.

Solution

The onClick handler should toggle the state, and the resorting can be done in an useEffect hook with a dependency on the sortOrder and header state.

React.useEffect(() => {
  setFilteredData(data => data.slice().sort((a: any, b: any) => {
    return sortOrder === 'asc'
      ? header === 'Station'
        ? b.station - a.station
        : b.days - a.days
      : header === 'Station'
        ? a.station - b.station
        : a.days - b.days;
  }));
}, [header, sortOrder]);

const toggleSortOrder = (header: string) => () => {
  setSortOrder(sortOrder === 'asc' ? 'dsc' : 'asc');
  setSortHeader(header);
};

...

handleClick={toggleSortOrder(header)}

Additionally, since the ascending/descending functionality is basically the same, I'd suggest converting the sort comparator into a higher order function that swaps the inputs and return a simpler comparator function.

const customSort = (sortOrder = 'asc', header = 'Station') => {
  const comparator = (a: any, b: any) => header === 'Station'
    ? b.station - a.station
    : b.days - a.days;
  return sortOrder === 'asc' ? comparator : (a, b) => comparator(b, a);
}

React.useEffect(() => {
  setFilteredData(data => data.slice().sort(customSort(sortOrder, header)));
}, [header, sortOrder]);

Upvotes: 1

Related Questions