How to sort data in ReactJs - reactjs

I have Items data which I am attempting to display array values sorted by cost field in costtable array when roomname is Double and type is 2.Here is my code:
Json:
{
"index": 1,
"id": "5e3961face022d16a03b1de9_1023632_1004876",
"costtable": [
{
"roomname": "Single",
"room_id": "1023632_479490,1004876_385485",
"family": [
{
"title": "adult 1",
"cost": 3.7568000,
"unit": "10",
"type": "2"
}
]
}
]
},
{
"index": 2,
"id": "5e3961face022d16a03b1de9_1088496_1005362",
"costtable": [
{
"roomname": "Double",
"room_id": "1088496_447339,1005362_415279",
"family": [
{
"title": "adult 1",
"cost": 5.6868000,
"unit": "10",
"type": "2"
}
]
}
]
},
{
"index": 3,
"id": "5e3961face022d16a03b1de9_1141859_1005529",
"costtable": [
{
"roomname": "Single",
"room_id": "1141859_74888,1005529_870689",
"family": [
{
"title": "adult 1",
"cost": 5.9586000,
"unit": "10",
"type": "2"
}
]
}
]
}
]
Code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
Items: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null,
}
}
componentDidMount() {
fetch('/json', {
method: 'GET',
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'))
let CostSort = Maindata.map(a => {
return this.renderSort(a)
})
Maindata.sort((a, b) => a.CostSort - b.CostSort);
this.setState(state => ({
...state,
Items: Maindata
}), () => {
this.reorganiseLibrary()
})
}).catch(error => console.error(error))
}
reorganiseLibrary = () => {
const { perPage, Items } = this.state;
let library = Items;
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
renderSort(element) {
let indents = []
let lenFamilies = element.costtable.length
for (let i = 0; i < lenFamilies; i++) {
if (element.costtable[i].roomname.indexOf('Double') > -1) {
for (let j = 0; j < element.costtable[i].family.length; j++) {
if (element.costtable[i].family[j].type == 2) {
indents.push(element.costtable[i].family[j].cost)
break;
}
}
break;
}
}
return (indents)
}
// Previous Page
previousPage = event => {
this.setState({
currentPage: this.state.currentPage - 1
});
};
// Next Page
nextPage = event => {
this.setState({
currentPage: this.state.currentPage + 1
});
};
// handle per page
handlePerPage = (evt) =>
this.setState({
perPage: evt.target.value
}, () => this.reorganiseLibrary());
// handle render of library
renderLibrary = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return '';
}
return library[currentPage - 1].map((item, i) => (
<div className="item-list">
{item.index}
</div>
));
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
<div className="wrapper-data">
{this.renderLibrary()}
</div>
<div class="clr"></div>
<ul id="page-numbers">
<li className="nexprevPage">
{currentPage !== 1 && (
<button onClick={this.previousPage}><span className="fa-backward"></span></button>
)}
</li>
<li className="controlsPage active">{this.state.currentPage}</li>
<li className="restControls">...</li>
<li className="controlsPage">{this.state.maxPage}</li>
<li className="nexprevPage">
{(currentPage < maxPage) && (<button onClick={this.nextPage}><span className="fa-forward"></span></button>
)}
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('Content'));
This code does not give me any errors but displays the values in an unsorted format. How can I sort it?
New Code
Maindata.sort((a, b) => {
let lenFamilies = a.costtable.length
for (let i = 0; i < lenFamilies; i++) {
if( a.costtable[i].roomname.indexOf('Double') > -1){
for (let j = 0; j < a.costtable[i].family.length; j++) {
if( a.costtable[i].family[j].type == 2){
a.costtable[i].family[j].cost- b.costtable[i].family[j].cost
}
}
}
}
}

I do not understand the exact formula that you are using to sort, but what you are doing before the sort is wrong.
In your componentDidMount
let CostSort = Maindata.map(a => { return this.renderSort(a) })
This returns an array into a variable called CostSort and does not affect MainData in any way.
However, later on you do this.
Maindata.sort((a, b) => a.CostSort - b.CostSort);
For first iteration, this will compare Maindata[0] and Maindata[1]. Note that there is no CostSort in either of the objects and hence you are performing operation of undefined - undefined which is NaN. Therefore no sorting happens.
I would suggest you use only the sort function and do your comparison between two values there.
Maindata.sort((a, b) => {
// Do your calculation here
if(a should be before b) {
return -1;
} else {
return 1;
}
}
P.S The convention for variable in js is camelCase and not PascalCase. So, Maindata should he mainData.
EDIT:
Here is a simple sort implementation which works for the above case, you can expand on it according to your full use case.
Maindata.sort((a, b) => {
let lenFamilies = a.costtable.length;
for (let i = 0; i < lenFamilies; i++) {
if (
a.costtable[i].roomname.includes("Double") &&
!b.costtable[i].roomname.includes("Double")
) {
return -1;
}
if (
!a.costtable[i].roomname.includes("Double") &&
b.costtable[i].roomname.includes("Double")
) {
return 1;
}
if (a.costtable[i].roomname.indexOf("Double") > -1) {
for (let j = 0; j < a.costtable[i].family.length; j++) {
if (a.costtable[i].family[j].type == 2) {
a.costtable[i].family[j].cost - b.costtable[i].family[j].cost;
}
}
}
}
});

Omitting the algorithms (bubble, quicksort, by inserting ...). There is possible of sorting in UI context.
Your json have:
title | cost | unit | type
What type of sort You need? (title is string (can eg. sort alphabetically), then cost, unit & type are number (ascending + descending)
It's will be helpfull - when in future You provide only neccessary piece of code.
Here it's ellegant minimalistic function responsible for asc/desc sorting.
Firstly it's need to pass the props(which You wan't to sort) to values state.
function App() {
const [ascValue, setAscValue] = useState(true);
const [values, setValues] = useState([10, 5, 12, 1, 2, 900, 602]);
function sortValues() {
const compare = ascValue ? (a, b) => a - b : (a, b) => b - a;
setValues([...values].sort(compare));
}
useEffect(() => {
sortValues();
}, [ascValue]);
return (
<div>
<h3>{ascValue.toString()}</h3>
<button onClick={() => setAscValue(!ascValue)}>Toggle Asc</button>
{values.map(v => (
<p key={v}>{v}</p>
))}
</div>
);
}
Here is sorting by cost for your object:
let text = [{
"index": 1,
"id": "5e3961face022d16a03b1de9_1023632_1004876",
"costtable": [
{
"roomname": "Single",
"room_id": "1023632_479490,1004876_385485",
"family": [
{
"title": "adult 1",
"cost": 3.7568000,
"unit": "10",
"type": "2"
}
]
}
]
},
{
"index": 2,
"id": "5e3961face022d16a03b1de9_1088496_1005362",
"costtable": [
{
"roomname": "Double",
"room_id": "1088496_447339,1005362_415279",
"family": [
{
"title": "adult 1",
"cost": 5.6868000,
"unit": "10",
"type": "2"
}
]
}
]
},
{
"index": 3,
"id": "5e3961face022d16a03b1de9_1141859_1005529",
"costtable": [
{
"roomname": "Single",
"room_id": "1141859_74888,1005529_870689",
"family": [
{
"title": "adult 1",
"cost": 5.9586000,
"unit": "10",
"type": "2"
}
]
}
]
}
]
const App = () =>{
const usersWithName = Object.keys(text).map(function(key) {
var user = text[key];
return user.costtable[0].family[0].cost;
});
let costArray = usersWithName
const [ascValue, setAscValue] = useState(true);
const [values, setValues] = useState(costArray);
function sortValues() {
const compare = ascValue ? (a, b) => a - b : (a, b) => b - a;
setValues([...values].sort(compare));
}
useEffect(() => {
sortValues();
}, [ascValue]);
return (
<div>
<h3>{ascValue.toString()}</h3>
<button onClick={() => setAscValue(!ascValue)}>Toggle Asc</button>
{values.map(v => (
<p key={v}>{v}</p>
))}
</div>
);
}
export default App;
I don't have idea of performance in this case + if in your json are more costtable & family it should iterate by [i] iterator.

Related

How to access certain element of nested objects in react

I'm struggling to take certain value out of an API. I have no trouble mapping over the parts that I can immediately access using items.value, but when I can't get some of the more nested info. I'm specifically trying to access the value of "quantity" inside of pricing.
Here's my code
import "./StoreDisplay.css"
class StoreDisplay extends Component {
constructor(props) {
super(props)
this.state = {
error: undefined,
isLoaded: false,
items: []
}
}
componentDidMount() {
this.getData();
}
getData() {
fetch(url)
.then((res) => res.json())
.then(
(result) => {
this.setState({
isLoaded: true,
items: result,
});
console.log(result)
},
(error) => {
this.setState({
isLoaded: true,
error
});
}
);
}
render() {
const { error, isLoaded, items } = this.state;
if (error) {
return <div>Error: {error.message}</div>;
} else if (!isLoaded) {
return <div>Loading...</div>;
} else {
return (
<div id = "storeDisplay">
<ul className = "container">
{items.map(item => (
<li key = {item.title}>
<div className = "bundleName"> {item.title} {item.pricing.quantity}</div><img src = {item.asset} className = "img"></img>
</li>
))}
</ul>
</div>
);
}
}
}
Sample part of JSON from API:
[
{
"title": "100-Pack Bundle",
"desc": "",
"tag": "",
"purchaseLimit": 1,
"isAvailable": true,
"expireTimestamp": 1662538288,
"shopType": "specials",
"originalPrice": 10500,
"pricing": [
{
"ref": "Apex Coins",
"quantity": 6700
}
],
"content": [
{
"ref": "weapon_charm_charm_apex_asset_v22_misc_pathfinderemoji01",
"name": "MRVN Monitor",
"quantity": 1
},
{
"ref": "pack_cosmetic_rare",
"name": "Apex Pack",
"quantity": 100
}
],
"offerID": "220823_100-pack_bundle",
"asset": "https:\/\/shop-cdn.mozambiquehe.re\/dl_store_s14_0_bund_epic_100pack_a189.png"
},
It looks like item.pricing is actually an array of objects. From here you have a couple of choices, depending on what you want to do.
item.pricing will only ever have one element.
In this case, you can just take the first element:
<div className = "bundleName"> {item.title} {item.pricing[0].quantity}</div>
You want to list all the quantities
<div className = "bundleName"> {item.title} {item.pricing.map(pricing => pricing.quantity).join(" ")}</div>
or
<div className = "bundleName"> {item.title} {item.pricing.map(pricing => pricing.quantity).join(", ")}</div>
You want to have the sum of all quantities
<div className = "bundleName"> {item.title} {item.pricing.map(pricing => pricing.quantity).reduce((a, b) => a + b, 0)}</div>

ReactHook adding array of an array state without duplicating the key

I am trying to add data grouping by the unit name for showing functionality
const [allData , setAllData]= useState([{'unit':'' , data:[]}])
useEffect(async () => {
await axios.get(`${BACKEND_URL}/data`).then(res => {
res.data.map(elem => {
setAllData(prev =>[...prev , { 'unit': elem.unitName, 'data': [elem.lessonName] }]);
});
});
}, []);
the result is duplicating the key for the subarray which is "unit" for my exampl:
[
{
"unit": "unit 1",
"data": [
"LO1"
]
},
{
"unit": "unit 2",
"data": [
"LO2"
]
},
{
"unit": "unit 3",
"data": [
"LO3"
]
},
{
"unit": "unit 1",
"data": [
"LO15"
]
}
]
Try like that, if find unique property unit rewrite data or push new element to array
useEffect(async () => {
await axios.get(`${BACKEND_URL}/data`).then(res => {
setAllData((prev) => {
let result = [...prev];
res.data.forEach(({ unitName: unit, lessonName }) => {
const index = result.findIndex((elem) => elem.unit === unit);
if (index >= 0) {
result[index].data = [...result[index].data, lessonName]
} else {
result.push({unit, data: [lessonName]});
}
});
return result;
});
});
}, []);

How to get the minimum value by react js

In the code below, I am trying to run {this.renderCost(data,'mina')} with react js. I would like to obtain the minimum value of total using the code below, but total of an object that value of nameis Equal to for example mina(or other name because it will be changed).
I tried the following :
Firstly push the value of total using indents.push(elem.total), the expected output for this part is [2000,1000] and then get minimum value of array by Math.min(...indents),the expected output for this part is [1000] but the function doesn't work.
const data = [
{
"obj": {
"no": "1",
"info": [
{
"name": "maya"
},
{
"name": "mina"
}
],
"total":"2000"
}
},
{
"obj": {
"no": "2",
"info": [
{
"name": "maya"
}
],
"total":"1000"
}
},
{
"obj": {
"no": "3",
"info": [
{
"name": "mina"
},
{
"name": "Mike"
}
],
"total":"1000"
}
}
]
renderCost(data,name){
let indents = [];
data.map((elem) => {
this.renderTotal(elem,name,indents)
})
}
renderTotal(elem,name,indents){
for(let i = 0 ; i < elem.info.length;i++){
if (elem.info[i].name == name){
indents.push(elem.total)
}
return (
Math.min(...indents)
)
}
}
The data structure you're working with isn't ideal for this particular search however you can get to your answer with the following:
const minTotalByName = (data, name) => {
const totals = data
.filter(x =>
x.obj.info.find(y => y.name === name)
).map(x => x.obj.total);
return Math.min(...totals);
}
const min = minTotalByName(data, "mina"); // 1000
To find the min value for the name you can use below code:
const { useState } = React;
function App() {
const [name, setName] = useState("");
const filtered = data
.filter(obj => obj.obj.info.some(n => n.name === name))
.map(obj => Number(obj.obj.total));
const min = filtered.length !== 0 ? Math.min(...filtered) : "";
return (
<div>
<input onChange={(e) => setName(e.target.value)} />
<div>The result is: {min}</div>
</div>
);
}
const data = [
{
obj: {
no: "1",
info: [ { name: "maya" }, { name: "mina" } ],
total: "2000"
}
},
{
obj: {
no: "2",
info: [ { name: "maya" } ],
total: "1000"
}
},
{
obj: {
no: "3",
info: [ { name: "maya" }, { name: "Mike" } ],
total: "1000"
}
}
];
ReactDOM.render(<App />, document.getElementById("root"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>
<div id="root"></div>

Pass an items prop with the items within the category key

I can't seem to pass certain items into an item prop if they relate to the category that I am looping through
I have a JSON like this:
{
"Categories": [
{
"Name": "Music",
},
{
"Name": "Comedy",
},
{
"Name": "Sport",
},
{
"Name": "Family",
},
],
"Items": [
{
"Name": "Dolly Parton",
"NameId": "dolly-parton",
"Category": "Music",
},
{
"Name": "Cee Lo Green",
"NameId": "cee-lo-green",
"Category": "Music",
},
{
"Name": "Take That",
"NameId": "take-that",
"Category": "Music",
},
{
"Name": "Football",
"NameId": "football",
"Category": "Sport",
},
{
"Name": "Hockey",
"NameId": "hockey",
"Category": "Sport",
}
]
}
I'm looping through all the categories and then printing them into a list while trying to only pass items that relate to that category in an items prop. I have the code below but it is passing all my data to each element and I'm not sure why.
class CategoryItems extends Component {
constructor(props) {
super(props);
}
state = {
items: this.props.items,
categories: this.props.categories,
};
render() {
const items = this.state.items;
return (
<section className="category-wrapper">
<div className="container">
<div className="category-wrapper__inner">
{this.state.categories.map((category, index) => (
<CategoryItem
key={category.Name}
items={items.map((item, index) => {
item.Category === category.Name ? item : '';
})}
/>
))}
</div>
</div>
</section>
);
}
}
All the data is there and in the react dev-tools it says each element has 667 items but I know there should only be 7 items on the sports category.
Apply a filter instead of a map.
<CategoryItem
key={category.Name}
items={items.filter(i => item.Category === category.Name)}
/>
You can try this ,
class CategoryItems extends Component {
constructor(props) {
super(props);
}
state = {
items: this.props.items,
categories: this.props.categories,
};
render() {
const items = this.state.items;
const renderList = this.state.categories.reduce((total, category) => {
const list = items.filter(item => item.Category === category.Name);
if(list.length > 0){
total.push(<CategoryItem
key={category.Name}
items={list}
/>);
}
return total
},[])
return (
<section className="category-wrapper">
<div className="container">
<div className="category-wrapper__inner">
{renderList}
</div>
</div>
</section>
);
}
}

How to map json data with array in react native

I have array like this in react native
const data = [
{ key: 1, label: 'Service1'},
{ key: 2, label: 'Service2' },
{ key: 3, label: 'Service3' },
{ key: 4, label: 'Service4' },
{ key: 5, label: 'Service4' },
];
and json data:
"services": [
{
"id": 1,
"name": "Hotels",
},
{
"id": 2,
"name": "Embassies",
},
]
How to map id to key and name to label???
You want to fill your const data with values from JSON, correct?
Try this:
var jsonData = {
"services": [
{ "id": 1, "name": "Hotels" },
{ "id": 2, "name": "Embassies" }
]
};
var data = jsonData.services.map(function(item) {
return {
key: item.id,
label: item.name
};
});
console.log(data);
if your data like below (removed services key)
var jsonData = [
{ "id": 1, "name": "Hotels" },
{ "id": 2, "name": "Embassies" }
];
var data = jsonData.map(function(item) {
return {
key: item.id,
label: item.name
};
});
console.log(data);
i know it to much late,but i hope its helpfull for others,How to fetch the response of JSON array in react native?How to map json data with array in react native
export default class ExpenseNew extends Component {
constructor(){
super();
this.state={
PickerSelectedVal : '',
accountnameMain:[],
}
}
componentDidMount(){
var account_nam=[]
fetch('your Url', {
method: 'GET',
headers: { 'Authorization': 'Bearer ' + your token }
})
.then((response) => response.json())
.then((customerselect) => {
// alert(JSON.stringify(customerselect))
global.customerdata = JSON.stringify(customerselect)
var customername = JSON.parse(customerdata);
//alert(JSON.stringify(customername));
for (i = 0; i < customername.cus_data.length; i++) {
var dataa = customername.cus_data[i]["account_name"];
account_nam.push(dataa)
}
this.setState({accountnameMain:account_nam});
})
.done();
}
render() {
return (
<Picker
selectedValue={this.state.PickerSelectedVal}
placeholder="Select your customer"
mode="dropdown"
iosIcon={<Icon name="arrow-down" />}
onValueChange={(itemValue, itemIndex) => this.setState({PickerSelectedVal: itemValue})} >
{this.state.accountnameMain.map((item, key)=>(
<Picker.Item label={item} value={item} key={key}/>)
)}
</Picker>
)
}
}
the above example is fetch array of data from json,and map data in to dropdown/picker,i hope its helpfull for others,if you have any query, asked from me

Resources