I am creating a react app and I want to show only show 21 number of elements at a time and keep the rest in idle and show another 21 elements when scroll to bottom of page.
I have my component that gets the products and insets an add every 20 products. I want to only show 21 elements at a time (20 products and 1 add) while keeping the rest idle to load another 21 elements when they scroll down. Is there a way to pre-emptively fetch the next batch of results in advance and keep them idle till they need displaying (when user reaches end of the last bach of results).
this is my component
import React from "react";
import { Loading } from "./LoadingComponent";
const axios = require('axios');
class Products extends React.Component {
constructor(props){
super(props);
this.state = {
displayedList : [],
indexDisplayed : 0,
isLoading: false,
error: null
}
}
_injectAdsInList = list => {
// an array of your ads
this.setState({ isLoading: false });
const AdsList = ['111','2222'];
if (Array.isArray(list)) {
const insertAdAt = 21;
const productsAndAdsList = list.map((item, index) => {
// not sure about this calculation
// but this should be done here
if (index % insertAdAt === 0 && index !== 0) {
// its the 20th item insert an ad
return AdsList[0];
}
// otherwise insert the item
return item;
});
this.setState({ productsAndAdsList });
}
};
_getProducts = () => {
this.setState({ isLoading: true });
// make the fetch call
// use axios (https://www.npmjs.com/package/axios)
// for making http requests
axios.get('http://localhost:3000/products').then(list => this._injectAdsInList(list.data))
.catch(error => this.setState({ error, isLoading: false }));
};
_addToDisplay = ()=> {
let displayedList = this.state.displayedList;
let indexDisplayed = this.state.displayedList;
let productsAndAdsList = this.state.displayedList;
for(let i = indexDisplayed + 1; i <= indexDisplayed + 21; i++ ){
displayedList.push(productsAndAdsList[i]);
}
this.setState({
indexDisplayed : this.state.indexDisplayed+21,
displayedList : displayedList
});
}
_sortPrice = () => {
const { productsAndAdsList } = this.state;
// instead of mutating the origin array
// create a new one, and update the state
const sortedProducts = productsAndAdsList.sort((a, b) => a.price - b.price);
this.setState({ productsAndAdsList: sortedProducts });
};
_sortSize = () => {
const { productsAndAdsList } = this.state;
// instead of mutating the origin array
// create a new one, and update the state
const sortedProducts = productsAndAdsList.sort((a, b) => a.size - b.size);
this.setState({ productsAndAdsList: sortedProducts });
};
_sortId = () => {
const { productsAndAdsList } = this.state;
const sortedProducts = productsAndAdsList.sort((a, b) => {
if (a.id < b.id)
return -1;
if (a.id > b.id)
return 1;
return 0;
});
this.setState({ productsAndAdsList: sortedProducts });
}
_timeAgo = (prevDate) => {
const diff = Number(new Date()) - prevDate;
const minute = 60 * 1000;
const hour = minute * 60;
const day = hour * 24;
const month = day * 30;
const year = day * 365;
switch (true) {
case diff < minute:
const seconds = Math.round(diff / 1000);
return `${seconds} ${seconds > 1 ? 'seconds' : 'second'} ago`
case diff < hour:
return Math.round(diff / minute) + ' minutes ago';
case diff < day:
return Math.round(diff / hour) + ' hours ago';
case diff < month:
return Math.round(diff / day) + ' days ago';
case diff < year:
return Math.round(diff / month) + ' months ago';
case diff > year:
return Math.round(diff / year) + ' years ago';
default:
return "";
}
};
componentDidMount() {
// I personally prefer not to make any
// http calls directly in componentDidMount
// instead, creating a new function makes sense
this._getProducts();
}
render() {
const { isLoading, hasError } = this.state;
console.log(this._addToDisplay());
// show spinner
if (!hasError && isLoading) {
return <Loading />;
}
// show error
if (hasError && !isLoading) {
return <p>error.message</p>;
}
return (
<div>
<div className="row">
<div className="col-12">
<button onClick={this._sortPrice}>sort by price lower to higher</button>
<button onClick={this._sortSize}>sort by size small to big</button>
<button onClick={this._sortId}>sort by Id</button>
</div>
</div>
{ this.state.displayedList.map(item => { return (
<div className="row">
<div className="col-4">
<p> Price: ${(item.price / 100).toFixed(2)}</p>
</div>
<div className="col-4">
<p style={{ fontSize: `${item.size}px` }}> {item.face}</p>
</div>
<div className="col-3">
<p>Published: {this._timeAgo(new Date(item.date).getTime())}</p>
</div>
</div>
) } )
}
<button onClick={this._addToDisplay()}>Load 21 MORE</button>
<div className="row">
<div className="col-12">
<p>END OF CATALOG</p>
</div>
</div>
</div>
);
}
}
export default Products;