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?
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.
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.
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.
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.
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.
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}
/>)}
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}
/>
)}
}
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With