Home > Enterprise >  how to sort the data from json for the different different routes?
how to sort the data from json for the different different routes?

Time:05-21

this is my app.js The app.js file render the Leaderboard component for each route like /rank,/point,/age,/name

    <Router>
            <Switch>
                <Route path="/">
                    <div className="App">
                        <h8k-navbar header={title}></h8k-navbar>
                        <LeaderBoard />
                    </div>
                </Route>
                <Route path="/name">
                    <div className="App">
                        <h8k-navbar header={title}></h8k-navbar>
                        <LeaderBoard />
                    </div>
                </Route>
                <Route path="/rank">
                    <div className="App">
                        <h8k-navbar header={title}></h8k-navbar>
                        <LeaderBoard sorted = {lists}/>
                    </div>
                </Route>
                <Route path="/age">
                    <div className="App">
                        <h8k-navbar header={title}></h8k-navbar>
                        <LeaderBoard />
                    </div>
                </Route>
                <Route path="/points">
                    <div className="App">
                        <h8k-navbar header={title}></h8k-navbar>
                        <LeaderBoard />
                    </div>
                </Route>
            </Switch>
        </Router>

this is my json: here is my data contain rank,point,name,age. I want this detail should be sorted by rank,point,name,age .that is when the route is /rank The table data in Leaderboard should be sorted by rank and render that

    {"list":[
        {
            "rank":"1",
            "points":"1025",
            "name":"John Doe",
            "age":"27"
        },
        {
            "rank":"3",
            "points":"245",
            "name":"Elizabeth",
            "age":"17"
        },
        {
            "rank":"2",
            "points":"566",
            "name":"Samantha",
            "age":"22"
        }]
    }
    

This is my leaderboard component

    function LeaderBoard({sorted}) {
    let history = useHistory();
    let newList;
    console.log(sorted); 
    let lists = response.list
    const handleClick =()=>{
        history.push('/rank')
    }
    return (
        <div className="text-center mt-50">
            <div> 
                <div>
                    <button data-testid="route-rank" className='outlined' type="button" onClick={handleClick}>Rank</button>
                    <button data-testid="route-name" className='outlined' type="button">Name</button>
                    <button data-testid="route-points" className='outlined' type="button">Points</button>
                    <button data-testid="route-age" className='outlined' type="button">Age</button>
                </div>
            </div>
            <div className="card mx-auto pb-20 mb-30" style={{ width: '50%' }}>
                <table className="mt-50" data-testid="app-table">
                    <thead>
                        <tr>
                            <th>Rank</th>
                            <th>Name</th>
                            <th className="numeric">Points</th>
                            <th className="numeric">Age</th>
                        </tr>
                    </thead>
                    <tbody data-testid="app-tbody">
                    {lists.map((ele,index)=>{
                        // console.log(index)
                        return(
                            <tr key={ele.rank}>
                                <td data-testid={`rank-${index}`}>{ele.rank}</td>
                                <td data-testid={`name-${index}`}>{ele.name}</td>
                                <td data-testid={`points-${index}`} className="numeric">{ele.points}</td>
                                <td data-testid={`age-${index}`} className="numeric">{ele.age}</td>
                            </tr>
                        )
                    })}
                    </tbody>
                </table>
            </div>
        </div>
    );
}
export default LeaderBoard;

how to sort the json file by each rank,name,point,age and render it

CodePudding user response:

  1. You should export the JSON array.

  2. Import that file in Leaderboard component import List from './path/to/json_file/list.json';

  3. Then write the code to sort the array.

  4. if you are lodash library then it's fairly simple

    const orderedList= _.sortBy(List, list => list.rank)

CodePudding user response:

You could just pass a property sortBy (or obtain that information from the URL path) depending on which key you want to sort by and then sort your data within the component based on that key.

Here one way how you could do that:

const data = [
  {
    rank: "1",
    points: "1025",
    name: "John Doe",
    age: "27",
  },
  {
    rank: "3",
    points: "245",
    name: "Elizabeth",
    age: "17",
  },
  {
    rank: "2",
    points: "566",
    name: "Samantha",
    age: "22",
  },
];

const Table = ({ list, sortBy }) => {
  const [data, setData] = React.useState(list);
  const [sortedBy, setSortedBy] = React.useState(sortBy);

  const sorted = data.sort((a, b) => {
    let aVal = a[sortedBy];
    let bVal = b[sortedBy];
    if (typeof aVal === typeof bVal && aVal !== undefined) {
      // parse points to Number so they are sorted correctly
      if (sortedBy === "points") {
        aVal = Number(aVal);
        bVal = Number(bVal);
      }
      if (typeof aVal === "number") return aVal - bVal;
      else if (typeof aVal === "string") return aVal.localeCompare(bVal);
    }
    return 1;
  });

  return (
    <React.Fragment>
      <h3>{`Sorted by '${sortBy}'`}</h3>
      <table>
        <thead>
          <tr className="">
            <th>Rank</th>
            <th>Points</th>
            <th>Name</th>
            <th>Age</th>
          </tr>
        </thead>
        <tbody>
          {sorted.map((item) => (
            <tr key={item.rank}>
              <td>{item.rank}</td>
              <td>{item.points}</td>
              <td>{item.name}</td>
              <td>{item.age}</td>
            </tr>
          ))}
        </tbody>
      </table>
    </React.Fragment>
  );
};

const Wrapper = () => {
  return (
    <React.Fragment>
      <Table list={data} sortBy="rank" />
      <Table list={data} sortBy="points" />
      <Table list={data} sortBy="name" />
      <Table list={data} sortBy="age" />
    </React.Fragment>
  );
};

ReactDOM.render(
  <Wrapper/>,
  document.getElementById("root")
);
<script crossorigin src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script crossorigin src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<div id="root"></div>

The sort() function here only really compares all values that are strings or numbers and parsed points to Number before comparison otherwise a string comparison would be performed yielding unexpected results. You may need to adjust that function to your needs but in essence this example shows what you need to do.

CodePudding user response:

Here you have a demo of the below-proposed solution. Your question seems to be a little bit confusing because you're passing a prop called sorted and, at the same time you're using lists inside the Leaderboard component. So I wasn't sure if you wanted to sort the list outside of Leaderboard or inside it (there's only one route where you actually pass the list through the Leaderboard). So I assumed you just want ideas.

From inside your Leaderboard component you can call useLocation() to get access to the pathname and make the decision based on that. Like this:

const location = useLocation();
// Turns the pathname string into an array
const splittedPathName = location.pathname.split('/');
// Gets the last item in the array to be used as the sort criteria
const path = splittedPathName.pop() ?? '';
// path === 'age', 'rank', '', etc,

Then you can sort your list before returning your actual HTML:

// we don't want to mutate the original data during the sorting
const sortedList = structuredClone(lists);
if (path) {
  // the sorting algorithm here will depend on the type of your
  // data. I'm considering it's always string
  sortedList.sort((a, b) => a[path].localeCompare(b[path]));
}

After that, you can use the sortedList instead of your lists in your returned HTML.

Performance improvement (if required)

If your list is big, sorting it can make your component to cause short freezing periods to the page, which is not a good user experience. You can work it around with the new useDeferredValue hook:

const deferredValue = useDeferredValue(path)
const sortedList = useMemo(() => {
    // we don't want to mutate the original data
    const newList = structuredClone(lists);
    if (!path) {
      return newList;
    }
    // the sorting algorithm here will depend on the type of your
    // data. I'm considering it's always string
    newList.sort((a, b) => a[path].localeCompare(b[path]));
    return newList;
  }, [lists, path]);
  • Related