Mateen Kazia
Mateen Kazia

Reputation: 349

Creating a function to sort table React, JSX

Im trying to figure out a way to sort my rows array depending on the sortBy and order state. I currently have a handleSort function which is grabbing the column name and setting it to sortBy state and also toggling the order by either "asc" or "desc" but now I'm trying to figure out how to manipulate the rows depending on the sortBy and order state. I believe it's possible creating a long conditional rendering but wondering does anyone one have simpler way I might be missing. Your help is appreciated thank you.

state = {
columnHeaders: [
  "Meat",
  "Protein (g)",
  "Calories (cal)",
  "Carbohydrates (g)",
  "Fat (g)"
 ],
  rows: [
  ["chicken breast", "25", "200", "37", "8"],
  ["fried chicken", "45", "450", "21", "16"],
    ["baked fish", "15", "250", "30", "9"]
    ],
    sortedBy: "",
    order: "desc",
    query: "all",
    error: false
    };

  handleClose = () => {
  this.setState({ error: !this.state.error });
  };

  handleQuery = keyword => {
  this.setState({
  query: keyword
   });
   if (keyword === "chicken") {
   this.setState({
    rows: this.state.rows.filter(row => row[0].includes("chicken"))
   });
   } else if (keyword === "fish") {
    this.setState({
    rows: this.state.rows.filter(row => row[0].includes("fish"))
   });
   } else if (keyword === "beef") {
    this.setState({
    rows: this.state.rows.filter(row => row[0].includes("beef"))
    });
    } else {
    this.setState({
    error: true
     });
     }
     };

 handleSort = header => {
 this.setState(state => ({
  sortedBy: header,
  order: state.sortedBy === header ? invertDirection[state.order] : 
   "asc"
 }));
 };

  render() {
  const { columnHeaders, rows } = this.state;

return (
  <div className="App mt-3">
    <AlertDialogSlide
      open={this.state.error}
      handleClose={this.handleClose}
    />
    <Search handleQuery={this.handleQuery} />
    <Paper className="mt-3">
      <Header />
      <Table>
        <TableHead>
          <TableRow>
            {columnHeaders.map((header, i) => (
              <TableHeader
                header={header}
                key={`th-${i}`}
                handleSort={this.handleSort.bind(this, header)}
              />
            ))}
          </TableRow>
        </TableHead>
        <TableBody>
          {rows.map((row, i) => (
            <TableRow key={`thc-${i}`}>
              <TableItem row={row} />
            </TableRow>
          ))}
        </TableBody>
      </Table>
    </Paper>
  </div>
   );
  }
  } 

Upvotes: 3

Views: 1018

Answers (1)

Lorenz Henk
Lorenz Henk

Reputation: 781

First of all, you should save the original data and the filtered data in different locations - e.g. the original data comes from the props and the filtered data is in the state. Because if you overwrite the data (like you do at the moment), you won't be able to e.g. search for "fish" after you've searched for "chicken", because the data was filtered to only include "chicken"-entries - all "fish" entries where removed and are not accessible anymore.

Second, if you want to set a new state depending on an old state, you should always provide a function instead of the state object to the setState function (check out this link).

Third, instead of using the if-else blocks in handleQuery, you can just use the keyword directly to filter.

And now to your question: You can use the following code snippet to order and filter your rows:

const { rows } = this.props; // assuming the original data comes from the props!
const { query, sortedBy, order } = this.state;

// filter the data (only if query is not "all"
const newRows = query === "all" ? rows : rows.filter(row => row[0].includes(query));

const sortedRows = sortedBy === "" ? newRows : newRows.sort((a, b) => {
  const valueA = a[sortedBy]; // get the row to sort by
  const valueB = b[sortedBy]; // get the row to sort by

  let sortedValue = 0;

  if (valueA < valueB) {
    sortedValue = -1;
  }
  else if (valueA > valueB) {
    sortedValue = 1;
  }

  if (order === "desc") {
    sortedValue *= -1; // if descending order, turn around the sort order
  }

  return sortedValue;
});

this.setState({rows: sortedRows});

Upvotes: 2

Related Questions