Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to sort list of React components based on different properties?

Tags:

reactjs

redux

So, this is a code snippet from my frontend.

{store.results.data.map( result =>
  <ResultItem 
    key={result.id}
    title={result.title}
    description={result.description}
    start_date={result.start_date}
    end_date={result.end_date}
    vendor_name={result.vendor.name}
    buyer_name={result.buyer.name}
    preview_file={result.preview_file}
    status={result.status}
  />
)}

Basically, I'm mapping all the data in my Redux store into ResultItems. I want to be able to sort all my ResultItems by different properties like title, description, start_date, end_date, vendor_name, and buyer_name.

Any ideas on how to do that?

like image 959
AliciaGuerra Avatar asked Feb 13 '18 10:02

AliciaGuerra


People also ask

How do I sort a list in Reactjs?

First, in a new blank React app, we will create an array of strings which will be our list. Then we will map it out as an unordered list. We will also create the dropdown to select which type of sorting needs to be applied. import { React, useState } from "react"; import "./App.

How do you sort an array of objects by a property value in react?

To sort an array of objects in React: Create a shallow copy of the array. Call the sort() method on the array passing it a function. The function is used to define the sort order.

How do you organize your react components?

Open the component's file and start editing away. Then you need to edit your styles, so you also navigate to your styles folder, find the button and open that. Now the component is updated, the tests are broken and some stories need to be updated. You navigate to those respective folders and open tests/button.

How do you implement sorting in react?

The Grid component supports sorting data by one or several column values. Use the corresponding plugins and UI (column headers and Group Panel) to manage the sorting state and sort data programmatically. Click several columns while holding Shift to sort data by these columns.


4 Answers

I would create a Sort component and wrap the result items with it like this:

<Sort by='title'>
{store.results.data.map( result =>
  <ResultItem 
    key={result.id}
    title={result.title}
    description={result.description}
    start_date={result.start_date}
    end_date={result.end_date}
    vendor_name={result.vendor.name}
    buyer_name={result.buyer.name}
    preview_file={result.preview_file}
    status={result.status}
  />
)}
</Sort>

// Note: The 'by' prop passed into <Sort> in my example is hardcoded by you can grab it from redux or set it when user selects something from a list. Also you can pass another prop to indicate whether to sort by ascending or descending order etc

Then within the Sort component you can access the array of result items like this React.Children.toArray and use the sort method for arrays and pass the sort method a 'compare' function.

// Sort.js

import React from 'react';

// Compare function needed by the Sort component
const compare =(a, b) => {
    // you can access the relevant property like this a.props[by]
// depending whether you are sorting by tilte or year, you can write a compare function here, 

  }

const Sort= ({children, by})=> {
If (!by) {
// If no 'sort by property' provided, return original list
return children
}
return React.Children.toArray(children).sort(compare)

}

The main advantage with above is that you can use the Sort component anywhere else and you can keep the sorting logic neatly separate from mapping over the initial results.

like image 89
user1275105 Avatar answered Oct 07 '22 04:10

user1275105


You have to sort the data before doing the map part. For example imagine you want to sort by id:

    {store.results.data.sort((a, b) => a.id - b.id).map( result =>
            <ResultItem key={result.id}
            title={result.title}
            description={result.description}
            start_date={result.start_date}
            end_date={result.end_date}
            vendor_name={result.vendor.name}
            buyer_name={result.buyer.name}
            preview_file={result.preview_file}
            status={result.status}
   />)}
like image 24
Rodius Avatar answered Oct 07 '22 05:10

Rodius


First of all, you should know that is is nearly impossible to process react components - this includes sorting them as well.

Secondly, if you have an array (say arr) and you call .sort() method on it, the array will get sorted in-place, i.e., arr will get modified.

Now, time for your question. As you point out here, you want to implement dynamic sorting. This requires some custom compareFunctions that know how to compare objects based on their keys. Here's an example:

arr = [
    {
        num: 1,
        text: 'z',
    },

    {
        num: 2,
        text: 'y'
    },

    {
        num: 3,
        text: 'x'
    },
];

const ASC = 'ascending';
const DSC = 'descending';

function sortByNum(a, b, order = ASC) {
    const diff = a.num - b.num;

    if (order === ASC) {
        return diff;
    }

    return -1 * diff;
}

function sortByText(a, b, order = ASC) {
    const diff = a.text.toLowerCase().localeCompare(b.text.toLowerCase());

    if (order === ASC) {
        return diff;
    }

    return -1 * diff;
}

console.log(arr.sort((a, b) => sortByNum(a, b, DSC)))
console.log(arr.sort((a, b) => sortByText(a, b, ASC)))

Here's how your code might look:

const ASC = 'ascending';
const DSC = 'descending';

function sortByTitle(a, b, order = ASC) {
    ...
}

function sortByStatus(a, b, order = ASC) {
    ...
}

function render() {
    let sortChoice = ... // from `props` perhaps?

    const data = store.results.data;
    switch (sortChoice) {
        case 'title':
            data.sort(sortByTitle);
            break;

        case 'status':
            data.sort(sortByStatus);
            break;

        ...
    }

    return {data.map(result =>
      <ResultItem 
        key={result.id}
        title={result.title}
        description={result.description}
        start_date={result.start_date}
        end_date={result.end_date}
        vendor_name={result.vendor.name}
        buyer_name={result.buyer.name}
        preview_file={result.preview_file}
        status={result.status}
      />
    )}
}
like image 23
zhirzh Avatar answered Oct 07 '22 06:10

zhirzh


Lodash library can serve this purpose.

{_.sortBy(store.results.data, ['status', 'start_date']).map( result =>
        <ResultItem key={result.id}
        title={result.title}
        description={result.description}
        start_date={result.start_date}
        end_date={result.end_date}
        vendor_name={result.vendor.name}
        buyer_name={result.buyer.name}
        preview_file={result.preview_file}
        status={result.status}

/>)}

You can provide multiple fields in ['status', 'start_date',...]by which you want to sort.

like image 37
Deepak Avatar answered Oct 07 '22 05:10

Deepak