Sorting data objects in React

Sorting some data (such as search results) is common in web applications. We often sort data to find our appropriate option faster and more precisely. Generally, there are two ways for a web developer to sort some data to render. First, is the backend sorting where we ask for the sorted data from our backend. The second type is sorting on the client-side with the help of Javascript. In this post, we will see how to sort client-side in ReactJs.

Before we start, here are the React version and needed libraries for this article:

"dependencies": {
    "@testing-library/jest-dom": "^5.16.3",
    "@testing-library/react": "^12.0.0",
    "@testing-library/user-event": "^12.0.0",
    "react": "^17.0.2",
    "react-dom": "^17.0.2",
    "react-router-dom": "^5.2.0",
    "react-scripts": "5.0.1",
    "web-vitals": "^2.1.4",
    "query-string": "^7.1.1"
  },

Note: Some decisions such as the code structure, function name, etc are my personal subjective choices. I am not claiming they are the best and you do not have to use the same.

Scenario

Imagine we are dealing with a list of objects. We like to render them in a list for our users. Each object has a “text” that is the label. It also has “val1”,  “val2”, and “val3” which are the properties that users can utilize to sort the list of objects.

data: [
                {"text": "Sample A", "val1": 1, "val2": 4, "val3": 9},
                {"text": "Sample B", "val1": 3, "val2": 1, "val3": 6},
                {"text": "Sample C", "val1": 2, "val2": 3, "val3": 1}
            ]

Implementation

First, we define our class component in React named SortResults. The component is defined inside a directory named components so our new component path is like: “/src/components/SortResults.jsx

After defining our class component, we define a constructor for it to set the initial state. Our state contains the list of data objects as discussed and a variable name “sortField” with the initial value null. We use this state variable to set the sorting value later (between val1, val2, and val3 in data objects). 

class SortResults extends React.Component{
    constructor(props){
        super(props);
        this.state = ({  
            sortField: "null",          
            data: [
                {"text": "Sample A", "val1": 1, "val2": 4, "val3": 9},
                {"text": "Sample B", "val1": 3, "val2": 1, "val3": 6},
                {"text": "Sample C", "val1": 2, "val2": 3, "val3": 1}
            ]
        });
    }

The next step is to define a function to build the list of the data objects for rendering. Later we call this function in the render function. (remember to bind it in the class constructor)

createResultToRender(){
        let result = [];
        this.state.data.map((item) => {
            result.push(
                <div className="sort-card">
                    <div>{item['text']}</div>
                </div>                
            );
        });
        return result;
    }

Now, we implement the most important function which is the actual sorting. To do this, we use the array sort in JS by passing a callback function to sort the list of objects based on an object property.

sortBasedOnKey (array, property) {
        return array.sort(function (o1, o2) {
            let x = o1[property];
            let y = o2[property];
            return ((x < y) ? -1 : ((x > y) ? 1 : 0))
        })
    }

Since we want to use a dropdown list to select the sort fields, before we write the render function, we need a change handler function. This function calls the sorting function on the list of objects in our state to sort the results when a user selects an option in the dropdown. (remember to bind it in the class constructor)

handleSortChange = (e) => {
        if(e.target.value !== "null"){
            let sortedData = this.sortBasedOnKey(this.state.data, e.target.value);
            this.setState({
            sortField: e.target.value,
            data: sortedData
            });
        }        
      }

The final part is to implement the class render function. Here we need a select/option for our dropdown and calling the createResultToRender function as we defined before.

render(){
        return(
            <div className="sort-render">
                <div className='col-sm-4 form-inline'  id="sort-grid">
                    <div class="form-group">
                        <label for="list-sorting" className='col-form-label'>sorted by </label>
                        <select  id="list-sorting" value={this.state.sortField} onChange={this.handleSortChange}>
                            <option selected disabled value={'null'} key="val0">Choose ...</option>
                            <option value={'val1'} key="val1">Val 1</option>
                            <option value={'val2'} key="val2">Val 2</option>
                            <option value={'val3'} key="val3">Val 3</option>
                        </select>  
                    </div>
                </div>
                <br></br>
                {this.createResultToRender()}
            </div>            
        );
    }

Here is the link to the source code: 

https://github.com/Pooya-Oladazimi/blog-post-app/blob/main/src/components/SortResults.jsx

The End.