Rahul Raj
Rahul Raj

Reputation: 516

Sorting Html table Columns reactjs

i am trying to sort html table by ASC and desc order but this table is not working properly its working only for first column when i put id name can you please help me for make this work sorting func by ASC and Desc. this is my code so far i tried but its not working Thanks

import React from "react";

class Th extends React.Component {
  handleClick = () => {
    const { onClick, id } = this.props;
    onClick(id);
  };
  render() {
    const { value } = this.props;
    return <th onClick={this.handleClick}>{value}</th>;
  }
}

class App extends React.Component {
  state = {
    users: []
  };

  async componentDidMount() {
    const res = await fetch(
      `https://run.mocky.io/v3/6982a190-6166-402e-905f-139aef40e6ef`
    );
    const users = await res.json();
    this.setState({
      users
    });

  }

  handleSort = id => {
    this.setState(prev => {
      return {
        [id]: !prev[id],
        users: prev.users.sort((a, b) =>
          prev[id] ? a[id] < b[id] : a[id] > b[id]
        )
      };
    });
  };
  render() {
    const { users } = this.state;
    return (
      <table>
        <thead>
          <tr>
            <Th onClick={this.handleSort} id="mileage" value="Mileage" />
            <Th onClick={this.handleSort} id="overall_score" value="Overall score" />
            <Th onClick={this.handleSort} id="fuel_consumed" value="Fuel Consumed" />
          </tr>
        </thead>
        <tbody>
          {users.map(user => (
            <tr>
              <td>{user.span.mileage.value}</td>
              <td>{user.span.overall_score.value}</td>
              <td>{user.span.fuel_consumed.value}</td>
            </tr>
          ))}
        </tbody>
      </table>
    );
  }
}
export default App;

Upvotes: 0

Views: 93

Answers (1)

macborowy
macborowy

Reputation: 1534

To make it works you need to change a few thigs:

  • the setState merges new data with old one, so [id]: !prev[id] adds new property to state for each column you filter without removing old one. It's better to store column to filter in dedicated state property (e.g. sortBy).
  • fix sorting function to make it sorting the users by correct object properties
  • remove async from componentDidMount and change fetch to use then/catch instead of async/await (it makes your code more React-ish).

Use example below as an inspiration:

class App extends React.Component {
  state = {
    sortBy: null,
    order: "ASC",
    users: []
  };

  componentDidMount() {
    fetch(`https://run.mocky.io/v3/6982a190-6166-402e-905f-139aef40e6ef`)
      .then(response => response.json())
      .then(users => this.setState({users}))
      .catch(err => console.log('Error', err));
  }

  handleSort = id => {
    this.setState(prev => {
      const ordered = prev.users.sort((a, b) =>
        prev.order === "ASC"
          ? a["span"][id]["value"] < b["span"][id]["value"]
          : a["span"][id]["value"] > b["span"][id]["value"]
      );

      return {
        sortBy: id,
        order: prev.order === "ASC" ? "DESC" : "ASC",
        users: ordered
      };
    });
  };
  render() {
    const { users } = this.state;
    return (
      <table>
        <thead>
          <tr>
            <Th onClick={this.handleSort} id="mileage" value="Mileage" />
            <Th
              onClick={this.handleSort}
              id="overall_score"
              value="Overall score"
            />
            <Th
              onClick={this.handleSort}
              id="fuel_consumed"
              value="Fuel Consumed"
            />
          </tr>
        </thead>
        <tbody>
          {users.map(user => (
            <tr>
              <td>{user.span.mileage.value}</td>
              <td>{user.span.overall_score.value}</td>
              <td>{user.span.fuel_consumed.value}</td>
            </tr>
          ))}
        </tbody>
      </table>
    );
  }
}

class Th extends React.Component {
  handleClick = () => {
    const { onClick, id } = this.props;
    onClick(id);
  };
  render() {
    const { value } = this.props;
    return <th onClick={this.handleClick}>{value}</th>;
  }
}

ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Keep in mind that in only works with the current data schema and fields you already have. If you want to change the fields to sort by you need to update sorting function.

Upvotes: 2

Related Questions