Finding Maximum value in an Array of Objects by ReactJs - reactjs

I have a series of data that contains some objects in an array(json file) and it will be shown by fetch request.There is a renderMaxTotal() function that must get me the max number of in totalcomof all data of json file but it shows me the max number of in totalcom in the current page and by going to another page the amount of renderMaxTotal() will be changed.
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null,
};
}
componentDidMount() {
fetch('/json.bc', {
method: 'get',
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'))
this.setState(state => ({
...state,
data: Maindata
}), () => {
this.reorganiseLibrary()
})
}).catch(error => console.error(error))
}
reorganiseLibrary = () => {
const { perPage, data } = this.state;
let library = data;
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
})
}
// 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 <div className="nodata">No Result</div>
}
return library[currentPage - 1].sort((a, b) => a.total - b.total).map((item, i) => (
<div className="item">
<span>{this.renderTotalcom(item)}</span>
</div>
))
}
// handle render of library
renderMaxTotal = () => {
const { library, currentPage } = this.state;
if (!library || (library && library.length === 0)) {
return <div className="nodata">No Result</div>
}
return Math.max(...library[currentPage].map(item => item.totalCom))
}
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
<span className="max">{this.renderMaxTotal()}</span>
{this.renderLibrary()}
<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>
)
}
renderTotalcom(element) {
console.log(typeof element.totalCom)
return element.totalCom
}
}
ReactDOM.render(<App />, document.getElementById('Result'))
If I change renderMaxTotal() to this:
Math.max(...library[0].map(item=>item.totalCom))
it will show me the max of first page and by turning to another page it does not change.
If I change renderMaxTotal() to this:
Math.max(...library.map(item=>item.totalCom))
it will be NaN.
How can I have the max amount of totalcom in whole pages?

The code below will get the max of each pages and compare it with the current Max.
// handle render of library
renderMaxTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return <div className="nodata">No Result</div>
}
return library.reduce((acc,lib)=>{
const libMax = Math.max(...lib.map(item => item.totalCom))
return libMax > acc ? libMax : acc
},0)
}

Related

React class component button setState sorting not working as intended

import AuthorSidebar from "../SubPages/AuthorSidebar";
import ReactPaginate from 'react-paginate';
import { Card, Button } from 'react-bootstrap';
export default class Author extends React.Component {
constructor(props) {
super(props);
this.state = {
author: [],
AuthorTempState: [],
selectedPage: 0,
Postsperpage: 4,
PagesVisited: 0
}
this.handlePageClick = this.handlePageClick.bind(this);
}
async recievedData() {
const res = await fetch(`https://api.quotable.io/authors?limit=30`);
const data = await res.json();
for (const element of data.results) {
element.idfav = false;
}
data.results.sort((a, b) => (a._id > b._id) ? 1 : -1)
this.setState({
author: data.results,
AuthorTempState: data.results
});
}
componentDidMount() {
if (localStorage.getItem('authors')) {
this.setState({
author: JSON.parse(localStorage.getItem('authors')),
AuthorTempState: JSON.parse(localStorage.getItem('authors'))
})
} else {
this.recievedData();
}
}
componentDidUpdate(prevProps, prevState) {
if (this.state.author !== prevState.author) {
localStorage.setItem('authors', JSON.stringify(this.state.author))
}
}
favBttn(Auth) {
const filterData = this.state.AuthorTempState.filter(data => data._id !== Auth._id)
Auth.idfav = true;
const updateAuthor = [Auth, ...filterData];
updateAuthor.sort((a, b) => (a._id > b._id) ? 1 : -1)
this.setState({
author: updateAuthor
});
}
remfavBttn(Auth) {
const filterData = this.state.AuthorTempState.filter(data => data._id !== Auth._id)
Auth.idfav = false;
const updateAuthor = [Auth, ...filterData]
updateAuthor.sort((a, b) => (a._id > b._id) ? 1 : -1)
this.setState({
author: updateAuthor
});
}
handlePageClick = (e) => {
const SelectedPage = e.selected;
const Offset = SelectedPage * this.state.Postsperpage;
this.setState({
selectedPage: SelectedPage,
PagesVisited: Offset
}, () => {
this.recievedData();
});
};
render() {
const { author } = this.state;
const PageCount = Math.ceil(author.length / this.state.Postsperpage);
console.log(author)
let sliced = author.slice(this.state.PagesVisited, this.state.PagesVisited + this.state.Postsperpage);
return (
<div className="AppWhole">
<AuthorSidebar />
<div className="App">
<div className="author">
{sliced.map(
(Author) => (
<div key={Author._id}>
<Card style={{ margin: 20 }} border="dark" bg="light" text="grey">
<Card.Body>
<Card.Title>Name: {Author.name}
{
(Author.idfav) ? (<Button size="sm" className='right' onClick={() =>
this.remfavBttn(Author)
}>Remove Favt.</Button >) : (<Button size="sm" className='right' onClick={() =>
this.favBttn(Author)
}>Add Favt.</Button >)
}
</Card.Title>
<Card.Text>
Bio: {Author.bio}
</Card.Text>
</Card.Body>
<Card.Footer>Wiki: <a href='{Author.link}'>{Author.link}</a></Card.Footer>
</Card>
</div>
))}
<div >
<ReactPaginate
pageCount={PageCount}
onPageChange={this.handlePageClick}
previousLabel={"<<"}
nextLabel={">>"}
containerClassName={'paginationLinks'}
disabledClassName={'paginationDisabled'}
activeClassName={'paginationActive'}
/>
</div>
</div>
</div>
</div>
);
}
}
So my page is an Author page which shows different authors and their details in each card which I fetched from API and then mapped. https://i.stack.imgur.com/QitTe.png
And in each card after onclick it changes to Remove Favourite. The card which is favourited makes the idfav true in the object array of the author state and false if not favourited. And there is a 2nd page which shows all the favourite authors. Now after clicking once on a card to remove fav and then clicking another card also to remove favourite the former card gets turned to add favourite automatically.
Please help me I have been stuck on this for 2 weeks now. Thank you.
Since you need to update a single object in-place in a list, here's how you do that really simply.
const bttn = (idfav) => Auth => this.setState({
author: this.state.author.map(a =>
a._id === Auth._id
// When we find the auth to update, change its idfav
? {...a, idfav }
: a
});
const favBttn = bttn(true);
const remfavBttn = bttn(false);
Or if you prefer the undried version:
function async favBttn(Auth) {
this.setState({
author: this.state.author.map(a =>
a._id === Auth._id
// When we find the auth to update, change its idfav
? {...a, idfav: true }
: a
});
}
function async favBttn(Auth) {
this.setState({
author: this.state.author.map(a =>
a._id === Auth._id
// When we find the auth to update, change its idfav
? {...a, idfav: false }
: a
});
}

Sorting an array that is in another array in ReactJs

I have a json file called by fetch request that looks like this:
[
{
"Infos": [
{
"id": {
"Id": "105254"
},
"total": 142854739
},
{
"id": {
"Id": "105255"
},
"total": 112854739
},
{
"id": {
"Id": "105256"
},
"total": 132854739
},
{
"id": {
"Id": "106540"
},
"total": 122868818
}
]
}
]
I want to sort data based on total field ,but as you can see all objects are in another array called Infos and I can not to sort data like this:
Maindata.sort((a, b) => a.total - b.total);
How can I sort data based on total field that is in another an array?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null,
}
}
componentDidMount() {
fetch('/json.bc', {
method: 'get',
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'))
Maindata.sort((a, b) => a.Infos[i].total - b.Infos[i].total) // I want to sort data here /////
this.setState(state => ({
...state,
data: Maindata
}), () => {
this.reorganiseLibrary()
})
}).catch(error => console.error(error))
}
reorganiseLibrary = () => {
const { perPage, data } = this.state;
let library = data;
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
})
}
// 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 <div>NOResult</div>
}
return library[currentPage - 1].map((item, i) => (
<div className="Wrapper">{this.renderInfo(item)}</div>
))
}
renderInfo(element){
let len =element.Infos.length
for (let i = 0; i < len; i++) {
return element.Infos[i].total
}
}
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
{this.renderLibrary()}
<ul id="page-numbers">
<li className="nexprevPage">
{currentPage !== 1 && (
<button onClick={this.previousPage}><span className="fa-backward"></span></button>
)}
</li>
<li className="controlsPage activeCnt">{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('Result'))
You can sort the inner field by mapping over the outer array and sorting the inner one like
Maindata = Maindata.map((data) => ({Infos: data.Infos.sort((a, b) => a.total - b.total)}))

How to set a default value into a prop in ReactJs?

I have a series of data that contains some objects in an array(json file) and it will be shown by fetch request.There is a renderMinTotal() function that must get me the min number of in totalcomof all data of json file.This function works correctly but I want the default value of FilterTotal be the result of renderMinTotal().For this I write this code :
let defaultFilterTotal = null;
defaultFilterTotal = FilterTotal
? (FilterTotal)
: (this.renderMinTotal ());
but the default value is empty. Why it is not been set as default value of
FilterTotal?
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null,
FilterTotal: "",
};
}
componentDidMount() {
fetch('/json.bc', {
method: 'get',
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'))
this.setState(state => ({
...state,
data: Maindata
}), () => {
this.reorganiseLibrary()
})
}).catch(error => console.error(error))
}
reorganiseLibrary = () => {
const { FilterTotal, perPage, data } = this.state;
let library = data;
let defaultFilterTotal = null;
defaultFilterTotal = FilterTotal
? (FilterTotal)
: (this.renderMinTotal()); //The default value of FilterTotal is not been set .////
if (FilterTotal !== "") {
library = library.filter(item =>
item.totalCom > FilterTotal
)
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
})
}
// 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 <div className="nodata">No Result</div>
}
return library[currentPage - 1].sort((a, b) => a.total - b.total).map((item, i) => (
<div className="item">
<span>{this.renderTotalcom(item)}</span>
</div>
))
}
// handle render of library
renderMinTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return ''
}
return library.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom))
return acc === undefined ? libMin : libMin < acc ? libMin : acc
}, undefined)
}
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
<span className="max">{this.renderMinTotal()}</span>
{this.renderLibrary()}
<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>
)
}
renderTotalcom(element) {
return element.totalCom
}
}
ReactDOM.render(<App />, document.getElementById('Result'))
The code returns this if there's no library, so it will be an empty string just like how this.state.FilterTotal is originally an empty string
if (!library || (library && library.length === 0)) {
return ''
}

DefaultValue in input by type=range

I have an Input by type=range that the value of min , max and defaultvalue would be set by {this.renderMinTotal()} and {this.renderMaxTotal()} and as you can see the value of defaultvalue is the output of {this.renderMaxTotal()} but the thumb of input looks that the value of defaultvalue is {this.renderMinTotal()} while the value of defaultvalue is {this.renderMaxTotal()} and in inspector the values of min , max and defaultvalue are correct.
The output of input in inspector:
<input type="range" min="17386000" max="178124000" step="1000" class="multirange" value="178124000">
It must be like this:
=============[]
while it looks like this:
[]=============
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
perPage: 20,
currentPage: 1,
maxPage: null
};
}
componentDidMount() {
fetch("/json.bc", {
method: "get"
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
reorganiseLibrary = () => {
const { perPage, data } = this.state;
let library = data;
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// 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 <div className="nodata">NoResult</div>;
}
return library[currentPage - 1]
.sort((a, b) => a.total - b.total)
.map((item, i) => (
<div className="item">
<span>{item._id.value} </span>
</div>
));
};
renderMinTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom));
return acc === undefined ? libMin : libMin < acc ? libMin : acc;
}, undefined);
};
renderMaxTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMax = Math.max(...lib.map(item => item.totalCom));
return libMax > acc ? libMax : acc;
}, 0);
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div>
<div>
<input
type="range"
min={this.renderMinTotal()}
max={this.renderMaxTotal()}
defaultValue={this.renderMaxTotal()}
step="1000"
className="multirange"
/>
</div>
{this.renderLibrary()}
<ul id="page-numbers">
<li className="nexprevPage">
{currentPage !== 1 && (
<button onClick={this.previousPage}>
<span className="fa-backward" />
</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" />
</button>
)}
</li>
</ul>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('Result'))
Edited Code:
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
data: [],
library: null,
};
}
componentDidMount() {
fetch("/json.bc", {
method: "get"
})
.then(response => response.text())
.then(text => {
let Maindata = JSON.parse(text.replace(/\'/g, '"'));
this.setState(
state => ({
...state,
data: Maindata
}),
() => {
this.reorganiseLibrary();
}
);
})
.catch(error => console.error(error));
}
reorganiseLibrary = () => {
const { data } = this.state;
let library = data;
library = _.chunk(library);
this.setState({
library,
});
};
// handle per page
handlePerPage = evt =>
this.setState(
{
perPage: evt.target.value
},
() => this.reorganiseLibrary()
);
renderMinTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMin = Math.min(...lib.map(item => item.totalCom));
return acc === undefined ? libMin : libMin < acc ? libMin : acc;
}, undefined);
};
renderMaxTotal = () => {
const { library } = this.state;
if (!library || (library && library.length === 0)) {
return "";
}
return library.reduce((acc, lib) => {
const libMax = Math.max(...lib.map(item => item.totalCom));
return libMax > acc ? libMax : acc;
}, 0);
};
render() {
const { library } = this.state;
return (
<div>
<div>
<input
type="range"
min={this.renderMinTotal()}
max={this.renderMaxTotal()}
defaultValue={this.renderMaxTotal()}
step="1000"
className="multirange"
/>
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('Result'))

Set the result of ajax in react

Why the result of ajax request doesn't set in Library which is [] by default.When the data of Library is set statically there would not be problem :
Library:[{'id': '5c0b6cd9e1382352759fbc25', 'hotelinfo': {'name': 'Korston Hotel', 'hotelsearch': {'realname': 'Korston Hotel Moscow', 'hotelid': 1011702.0, 'hotelimage': 'htl207110100001', 'countryid': 1002035.0, 'ecountryname': 'Russia', 'countryname': '', 'cityid': 1182348.0, 'ecityname': 'Moscow', 'cityname': '', 'star': 4.0, 'services': 'H.B', 'desc': ' ', 'enable': '1', 'delete': '0'}, 'information': {'viewname': ''}, 'validatedate': {'fdate': '1397-12-01', 'tdate': '1397-12-29', 'tdateid': 10592.0, 'fdateid': 10564.0}}, 'families': [{'availablerooms': [{'info': {'room': 'Single', 'cost': 2400.0, 'availability': 'onrequest', 'withbed': 0.0, 'withoutbed': 0.0, 'adults': 1.0, 'infant': 0.0, 'roomid': '1011702_483587', 'double': '0'}}], 'optionId': '1011702_483587###5c0b6cd9e1382352759fbc25', 'totalPrice': 2400.0, 'services': 'H.B', .....]
but Library is going to be dynamic and the data will be sent from another page to this page by ajax request.
What should I do to set the result of ajax request in Library.
class App extends React.Component {
constructor(props) {
super();
this.state = {
Library: [],
library: null,
perPage: 1,
currentPage: 1,
maxPage: null,
filter: ""
};
$.ajax({
url: "/json.bc",
type: "post",
data: {
cityid: "1182348",
rooms: JSON.stringify({ "rooms": [{ "adultcount": "1", "childcountandage": "0" }] }),
},
success: (result) => {
this.setState({ Library: eval(result) });
}
})
}
componentDidMount() {
this.reorganiseLibrary();
}
// Calculates the library
reorganiseLibrary = () => {
const { filter, perPage, Library } = this.state;
let library = Library;
console.log(Library) //There is no result here//
if (filter !== "") {
library = library.filter(item =>
item.hotelinfo.hotelsearch.realname.toLowerCase().includes(filter)
);
}
library = _.chunk(library, perPage);
this.setState({
library,
currentPage: 1,
maxPage: library.length === 0 ? 1 : library.length
});
};
// Previous Page
previousPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage - 1
}));
// Next Page
nextPage = () =>
this.setState(prevState => ({
currentPage: prevState.currentPage + 1
}));
// handle filter
handleFilter = evt =>
this.setState(
{
filter: evt.target.value.toLowerCase()
},
() => {
this.reorganiseLibrary();
}
);
// 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 <div>No results</div>;
}
return library[currentPage - 1].map(item => (
<div key={item.hotelinfo.hotelsearch.realname}>{item.hotelinfo.hotelsearch.realname}</div>
));
};
render() {
const { library, currentPage, perPage, maxPage } = this.state;
return (
<div className="library">
<h1>Library</h1>
<div className="d-flex">
<div className="flex-fill">
<label className="library__filter-label">Filter</label>
<input value={this.state.filter} onChange={this.handleFilter} />
</div>
<div className="flex-fill text-right">
<label className="library__per-page-label">Per page</label>
<input placeholder="per page" value={this.state.perPage} onChange={this.handlePerPage} />
</div>
</div>
<div className="library__book-shelf">
{this.renderLibrary()}
</div>
<div className="d-flex">
<div className="flex-fill">
{currentPage !== 1 && (
<button onClick={this.previousPage}>Previous</button>
)}
</div>
<div className="flex-fill text-right">
{(currentPage < maxPage) && (
<button onClick={this.nextPage}>Next</button>
)}
</div>
</div>
<div className="library__page-info text-right">
{this.state.currentPage} of {this.state.maxPage}
</div>
</div>
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
First off, unless you really, really have to, try to avoid using jQuery in React. It's just going to lead to a massive headache.
You need to move that Ajax request out of the constructor and into your componentDidMount method. For example:
class App extends React.Component {
constructor(props) {
super(props)
this.state = {
Library: [],
}
}
componentDidMount() {
fetch('/json.cs')
.then(response => response.json())
.then(data => {
this.setState(state => ({
...state,
Library: data
}), () => {
this.reorganiseLibrary()
})
}
}
}
You have to call Ajax to load remote content inside componentDidMount
componentDidMount() {
// call your ajax and set state
}
Moreover, you need to remove this.reorganiseLibrary(); inside componentDidMount or call it along with this.setState({ Library: eval(result) }); after calling ajax to improve performance.

Resources