I have 2 components, the Favorites component, makes a request to the api and maps the data to Card.
I also have a BtnFav button, which receives an individual item, and renders a full or empty heart according to a boolean.
Clicking on the BtnFav render removes a certain item from the favorites database.
What I need is that in the Favorites component, when I click on the BtnFavs component, the useEffect of Favorites is triggered again to bring the updated favorites.
How can i solve this? I have partially solved it with a global context(favoritesUser), but is there any other neater alternative?
The data flow for now would be something like this:
Favorites component fetches all the complete data and passes it to the Card component, the Card component passes individual data to the BtnFavs component.
Favorites Component:
const fetchWines = async () => {
try {
const vinos = await axios.get(`/api/favoritos/${id}`);
const arrVinos = vinos.data.map((vino) => {
return vino.product;
});
setVinosFavs(arrVinos);
} catch (err) {
console.error(err);
}
};
useEffect(() => {
fetchWines();
}, [favoritesUser]);
return (
<div>
<h1>Mis favoritos</h1>
<Card listWines={vinosFavs} />
</div>
);
BtnFavs:
const handleClickFav = (e) => {
if (!boton) {
axios.post("/api/favoritos/add", { userId, productId }).then((data) => {
setBoton(true);
return;
});
}
axios.put("/api/favoritos/delete ", { userId, productId }).then((data) => {
setBoton(false);
setFavoritesUser(data);
});
};
What I need is that in the Favorites component, when I click on the BtnFavs component, the useEffect of Favorites is triggered again to bring the updated favorites.
How can i solve this? I have partially solved it with a global context(favoritesUser), but is there any other neater alternative?
The pattern you want is called a callback function, just like the onClick of a button. You pass a function to your components that get executed given a condition. If you want fetchWines to be called again, then just pass the function in as a prop.
Favorites Component:
<Card listWines={vinosFavs} refresh={fetchWines} />
Card Component
<BtnFavs onDelete={refresh} ... />
BtnFavs Component
onDelete();
You can name it whatever you want, but generally callbacks will be named like on<condition>.
If you really wanted useEffect to be triggered then you would pass a setState function that set one of the dependencies, but I don't see a point in this case.
I will share code, because this problem its normal for me, i really want to learn and improve that.
const Favorites = () => {
const { favoritesUser } = useFavoritesContext();
const user = useSelector((state) => state.user);
const id = user.id;
const [vinosFavs, setVinosFavs] = useState([]);
const fetchWines = async () => {
try {
const vinos = await axios.get(`/api/favoritos/${id}`);
const arrVinos = vinos.data.map((vino) => {
return vino.product;
});
setVinosFavs(arrVinos);
} catch (err) {
console.error(err);
}
};
useEffect(() => {
fetchWines();
}, [favoritesUser]);
return (
<div>
<h1>My favorits</h1>
<Grid listVinos={vinosFavs} />
</div>
);
};
export default Favorites
Grid
export default function Grid({ listVinos }) {
return (
<div>
<ul className={styles.layoutDeVinos}>
{listVinos?.map((element) => {
return <WineCard key={element.id} vino={element} />;
})}
</ul>
</div>
);
}
Card
export default function WineCard({ vino }) {
return (
<>
<div>
<Link to={`/products/${vino.id}`}>
<li>
<div className={styles.card}>
<div
className={styles.img1}
style={{
backgroundImage: `url(${vino.images})`,
}}
></div>
<div className={styles.text}>{vino.descripcion}</div>
<div className={styles.catagory}>
{vino.nombre}
<i className="fas fa-film"></i>
</div>
<div className={styles.views}>
{vino.bodega}
<i className="far fa-eye"></i>{" "}
</div>
</div>
</li>
</Link>
<div className="botonesUsuario">
<BtnFavs vino={vino} />
</div>
</div>
</>
);
}
BTN FAVS
export default function BtnFavs({ vino }) {
const { setFavoritesUser } = useFavoritesContext();
const [boton, setBoton] = useState(false);
const user = useSelector((state) => state.user);
const userId = user.id;
const productId = vino.id;
useEffect(() => {
axios
.post("/api/favoritos/verify", { userId, productId })
.then((bool) => setBoton(bool.data));
}, []);
const handleClickFav = (e) => {
if (!boton) {
axios.post("/api/favoritos/add", { userId, productId }).then((data) => {
setBoton(true);
return;
});
}
axios.put("/api/favoritos/delete ", { userId, productId }).then((data) => {
setBoton(false);
setFavoritesUser(data);
});
};
return (
<>
{!user.id ? (
<div></div>
) : boton ? (
<span
class="favIcons material-symbols-rounded"
onClick={handleClickFav}
>
favorite
</span>
) : (
<span className="material-symbols-rounded" onClick={handleClickFav}>
favorite
</span>
)}
</>
);
}
Related
I'm trying to filter through some posts based on their category if a button is clicked. For example I have a button that when clicked the only posts that show up are related to software projects.
I have set up a function called searchHandler that I've passed through to my SidebarOptions component, which has the onclick event. But when I pass it through nothing happens.
Here is the code in the (parent) Home Component where the searchHandler is:
function Home() {
const [posts, setPosts] = useState([]);
const [filteredPosts, setFilteredPosts] = useState(null);
const searchHandler = (event) => {
const { value } = event.target;
setFilteredPosts(
value
? posts.filter(
(post) =>
post.question.question.includes(value)
)
: null
);
};
useEffect(() => {
db.collection("questions")
.orderBy("timestamp", "desc")
.onSnapshot((snapshot) =>
setPosts(
snapshot.docs.map((doc) => ({
id: doc.id,
question: doc.data(),
}))
)
);
}, []);
return (
<div className="home">
<div></div>
<Header searchHandler={searchHandler} />
<div className="home__content">
<Sidebar searchHandler={searchHandler} />
<Feed posts={filteredPosts || posts} />
<Widget />
</div>
</div>
);
}
Here is the (child) Sidebar component that receives it:
import React from "react";
import "../Style/Sidebar.css";
import SidebarOptions from "./SidebarOptions";
function Sidebar({ searchHandler }) {
return (
<div className="sidebar">
<SidebarOptions searchHandler={searchHandler} />
</div>
);
}
export default Sidebar;
And here is the (grandchild)SidebarOptions that the function is finally sent to:
function SidebarOptions({ searchHandler }) {
return (
<div className="sidebarOptions">
<div className="sidebarOption" onChange={() => searchHandler}>
<img
src="https://c.pxhere.com/photos/7b/1a/code_coding_computer_developer_developing_development_macbook_notebook-913320.jpg!d"
srcset="https://c.pxhere.com/photos/7b/1a/code_coding_computer_developer_developing_development_macbook_notebook-913320.jpg!d"
alt="Software Projects"
/>
<p>Software Projects</p>
</div>
);
};
I think you need to revisit your SideBarOptions component. I wonder if the onChange handler makes sense on a div. I think it should be input rather than a div if you want your user to type. Also, you need to call your handler with the value that is typed, here you are not calling the handler (notice the missing () after searchHandler in your code for SideBarOptions). Also, it will be better to add something like a debounce so that the filter is not triggered for every character that a user types. It should ideally be triggered once a user stops typing, debounce is precisely that.
Putting some code snippet below based on my guess about how it might work.
const SideBarOptions = ({ searchHandler }) => {
const [filterText, setFilterText] = useState("");
const handleFilter = () => {
searchHandler(filterText);
}
return (
<div className="sidebarOptions">
<input name="filterText" value={filterText} onChange={(e) => setFilterText(e.target.value)} />
<div className="sidebarOption" onChange={() => searchHandler}>
<img src="https://c.pxhere.com/photos/7b/1a/code_coding_computer_developer_developing_development_macbook_notebook-913320.jpg!d" srcset="https://c.pxhere.com/photos/7b/1a/code_coding_computer_developer_developing_development_macbook_notebook-913320.jpg!d"
alt="Software Projects"
/>
<p>Software Projects</p>
<button onClick={handleFilter}>Filter</button>
</div>
</div>
);
}
So I was able to solve this by making a new function called categoryfilter in the Home component that went through the options and looked for the category of the posts in the database:
const categoryFilter = (category = "All") => {
const filtered =
category === "All"
? posts
: posts.filter(({ question }) => question.option === category);
setFilteredPosts(filtered);
};
I then passed that code as a prop to the sidebarOptions div after cleaning up the code a bit and used it to filter the posts based on the category name:
function SidebarOptions({ categoryFilter }) {
const categories = [
//Add all projects
{
name: "All",
imgUrl: "",
},
{
name: "Software Project",
imgUrl:
"https://c.pxhere.com/photos/7b/1a/code_coding_computer_developer_developing_development_macbook_notebook-913320.jpg!d",
},
{
name: "Engineering Project",
imgUrl:
"https://c.pxhere.com/photos/a7/72/gears_cogs_machine_machinery_mechanical_printing_press_gears_and_cogs_technology-818429.jpg!d",
},
];
return (
<div className="sidebarOptions">
{categories.map((category) => (
<div
className="sidebarOption"
onClick={() => categoryFilter(category.name)}
>
{category.imgUrl && (
<img
src={category.imgUrl}
srcSet={category.imgUrl}
alt={category.name}
/>
)}
<p>{category.name}</p>
</div>
))}
<div className="sidebarOption">
<Add />
<p>Suggest Project Space</p>
</div>
</div>
);
}
export default SidebarOptions;
I got this component in React.js which make different kinds of filtering when I click a button, this is my code:
import React, { useContext } from 'react';
import { ModelsContext } from "../context/ModelsContext";
const FilterNav = () => {
const { modelos, guardarModelo } = useContext(ModelsContext);
const filterSegment = e => {
const segment = modelos.filter(modelo => modelo.segment === e.target.name);
guardarModelo(segment);
}
return (
<nav className="filter-container">
<div className="container">
<h3 className="filter-element-title">Filtrar por</h3>
<button type="button" className="filter-element">Todos</button>
<button type="button" className="filter-element" name="Autos" onClick={filterSegment}>Autos</button>
<button type="button" className="filter-element" name="Pickups y Comerciales" onClick={filterSegment}>Pickups y Comerciales</button>
<button type="button" className="filter-element" name="SUVs y Crossovers" onClick={filterSegment}>SUVs y Crossovers</button>
</div>
<p className="filter-element-last">Ordenar por ^</p>
</nav>
);
}
export default FilterNav;
The information I get from the api with useContext in ModelsContext.jsx, here is what I wrote so far:
import React, { createContext, useState, useEffect } from 'react';
export const ModelsContext = createContext();
const ModelsProvider = (props) => {
//State de modelos
const [modelos, guardarModelo] = useState([]);
const consultarAPI = async () => {
const api = await fetch("https://challenge.agenciaego.tech/models");
const modelos = await api.json();
guardarModelo(modelos);
}
//Cargar un modelo
useEffect(() => {
consultarAPI()
}, []);
return (
<ModelsContext.Provider
value={{
modelos,
guardarModelo
}}
>
{props.children}
</ModelsContext.Provider>
)
}
export default ModelsProvider;
My issue is that when I filter the API modelos throught the filterSegment function I don't know how to re-fetch the data from the API, because when I do a new call to the filterSegment function it filters the filtered data. I've tried to add a boolean state, and I was thinking about adding another state with allthedata, but I really lost about implementing it, I'm still very new to React.js.
I've search through stack overflow and google and I cannot get the answer, If you can give me a clue or some sort of guidance it will be appreciated.
Thanks so much!
You can add another state in the ModelsContext:
//State de modelos
const [modelos, guardarModelo] = useState([]);
const [allModelos, guardarAllModelo] = useState([]);
const consultarAPI = async () => {
const api = await fetch("https://challenge.agenciaego.tech/models");
const modelos = await api.json();
guardarAllModelo(modelos);
//uncomment if you want to have initial value for modelos state
//guardarModelo(modelos);
}
// some codes ...
<ModelsContext.Provider
value={{
allModelos,
modelos,
guardarModelo
}}
>
{props.children}
</ModelsContext.Provider>
Then in the FilterNav component:
const {allModelos, modelos, guardarModelo } = useContext(ModelsContext);
const filterSegment = e => {
const segment = allModelos.filter(modelo => modelo.segment === e.target.name);
guardarModelo(segment);
}
But this does not really re-fetch data from your web api. It just re-filters the first fetched data. if you want to re-fetch data from web api you can add consultarAPI in your context provider then call it somewhere.
Thanks code is working
This is my Portfolio gallery code First time load all data when click category then get category dataenter code here
Thanks code is working
This is my Portfolio gallery code First time load all data when click category then get category data`enter code here`
import React, { Component, useEffect, useState } from 'react'`enter code here`;
import Thumnailport_list from './Thumnailport_list';
import Portlightbox from './Portlightbox';
import Functional from './Functional';
import $ from 'jquery';
const Portfolio = () => {
const filterItem = async (categoryitem) => {
const updateitmes = allModelos.filter((curElm) => {
return curElm.categories === categoryitem
})
getporfolioState(updateitmes)
}
const [getporfolio, getporfolioState] = useState([])
const [allModelos, guardarAllModelo] = useState([]);
$(document).ready(function () {
$(".grid-wrap .grid li").unbind().click(function (e) {
console.log(this.className);
var newe = this.className;
$('.' + newe).addClass('current show');
$("#grid-gallery").addClass("slideshow-open");
});
$("#closeport").unbind().click(function (e) {
$("#grid-gallery").removeClass("slideshow-open");
$(".portfolio .grid li").removeClass('current show');
$(".portfolio .slideshow ul > li").removeClass('current show');
});
});
const portadd = () => {
document.body.classList.add('portfolio');
document.body.classList.add('at-top');
document.getElementById('port').classList.add('no-transform');
document.getElementById('port').classList.add('revealator-within');
document.getElementById('port2').classList.add('no-transform');
document.getElementById('port2').classList.add('revealator-within');
document.getElementById('navbar-collapse-toggle').classList.remove('biohidemenu');
}
const getalldata = async () => {
try {
const res = await fetch("/getdata", {
method: 'Get',
headers: {
'Content-Type': 'application/json'
}
})
const data = await res.json()
// console.log("This is our data load")
// console.log(data.portfolio)
getporfolioState(data.portfolio)
guardarAllModelo(data.portfolio)
} catch (error) {
console.log(error)
// history.push("/backoffice/login")
}
}
useEffect(() => {
getalldata()
portadd()
}, []);
return (
<>
<section id="port" class="title-section text-left text-sm-center revealator-slideup revealator-once revealator-delay1">
<h1 >my <span>portfolio</span></h1>
<span class="title-bg">works</span>
</section>
<section id="port2" className="main-content text-center revealator-slideup revealator-once revealator-delay1">
<div class="container">
<button className="btn btn-about " onClick={() => filterItem('mobileapp')}>Mobile</button>
<button className="btn btn-about " onClick={() => filterItem('frontend')}>Frontend</button>
<button className="btn btn-about " onClick={() => filterItem('gdesign')}>Graphics</button>
</div>
<div id="grid-gallery" className="container grid-gallery">
{/* Portfolio Grid Starts */}
<section className="grid-wrap">
<ul className="row grid">
{
getporfolio.map((getdata, index) => {
return (
<>
<Thumnailport_list
key={index}
portID={getdata._id}
imagetag={getdata.imguploadedFile}
figuertext={getdata.projectname}
/>
</>
)
})
}
</ul>
</section>
{/* Portfolio Grid Ends */}
{/* Portfolio Details Starts */}
<section className="slideshow" id="sdfer">
<ul>
{/* Portfolio Item Detail Starts */}
{
getporfolio.map((getdata, index) => {
return (
<>
<Portlightbox
idlight={getdata._id}
imagelight={getdata.imguploadedFile}
langport={getdata.language}
clientport={getdata.client}
projectnameport={getdata.projectname}
previewport={getdata.preview}
/>
</>
)
})
}
</ul>
{/* Portfolio Navigation Starts */}
<nav>
{/*<span className="icon nav-prev prev"><img src="images/left-arrow.png" alt="previous" /></span>
<span className="icon nav-next next"><img src="images/right-arrow.png" alt="next" /></span>*/}
<span className="nav-close" id="closeport"><img src="images/close-button.png" alt="close" /> </span>
</nav>
{/* Portfolio Navigation Ends */}
</section>
</div>
</section>
</>
)
}
export default Portfolio;
I have two React components: ul list and each li item, which is a flash-card. In each item there are two strings: searching word and its translation (api.source, api.target) and also checkbox. After clicking on the checkbox and later on the button (CardList.js) I would like to get my data and send it to my backend. Can anybody please tell me how to get these two strings and pass them into addFlashCards function? Right now I have hardcoded it as dataSet
const CardsList = ({ fetchedApi }) => {
const addFlashCards = () => {
const dataSet = [
{
apiSource: "sampleDataCheckbox",
apiTarget: "sampleDataCheckbox2",
},
{
apiSource: "sampleDataCheckbox",
apiTarget: "sampleDataCheckbox",
},
];
const url = "/api/saveToDB";
axios
.post(url, { data: dataSet, user: "SOME USER" })
.then((res) => {
const fetchedData = res.data;
console.log(fetchedData);
})
.catch((err) => console.error(err));
};
return (
<div className="cards-list">
<button onClick={addFlashCards}>Add</button>
<ul className="cards-list__list">
{fetchedApi.map((api) => {
return <CardItem api={api} />;
})}
</ul>
</div>
);
};
export default CardsList;
const CardItem = ({ api }) => {
const [isChosenCard, setIsChosenCard] = useState(false);
const clickedCheckbox = () => {
setIsChosenCard(!isChosenCard);
};
return (
<>
<li className="card-item">
<input
className="fiszkiBox"
type="checkbox"
onClick={clickedCheckbox}
/>
<div className="flip-card">
<div className="flip-card-inner">
<div className="flip-card-front">
<p id="api-source">{api.source}</p>
</div>
<div className="flip-card-back">
<p className="api-target">{api.target}</p>
</div>
</div>
</div>
</li>
</>
);
};
export default CardItem;
Many thanks!
So as summary you have a list which you render and you want to select items which would be sent to backend. In this case you can add a empty array to your CardList by using useState hook which will contain the selected items.
const CardsList = ({ fetchedApi }) => {
const [selectedItems, setSelectedItems] = useState([]);
const addFlashCards = () => {
// Here you can do some kind of check with mapping the selectedItems Array, as you need
const url = "/api/saveToDB";
axios
.post(url, { data: selectedItems, user: "SOME USER" })
.then((res) => {
const fetchedData = res.data;
console.log(fetchedData);
})
.catch((err) => console.error(err));
};
function selectItem(item){
// So below, we do it to make component render by creating new array instead of mutating the current array. Actually try to play with code, you can even remove these and mutate current and set.
let selectedItemsArray = [...selectedItems];
// Here below, we check if selectedItem already exists in selectedItemsArray, if it exists we would like to remove it right? if it does not exist, we just add it to array by pushing it.
let itemCheck = selectedItemsArray.find((arrayItem) => arrayItem.source === item.source);
if (itemCheck) {
// Here if selected item was in array, we just remove it by filtering the array
selectedItemsArray = selectedItemsArray.filter((arrayItem) => arrayItem.source !== item.source)
}
else{
// Here selected item was not in our array so we just push it
selectedItemsArray.push(item)
}
setSelectedItems(selectedItemsArray);
}
return (
<div className="cards-list">
<button onClick={addFlashCards}>Add</button>
<ul className="cards-list__list">
{fetchedApi.map((api, index) => {
return <CardItem api={api} onItemSelected={item=> selectItem(item)} />;
})}
</ul>
</div>
);
};
const CardItem = ({ api, onItemSelected }) => {
return (
<>
<li className="card-item">
<input
className="fiszkiBox"
type="checkbox"
onClick={() => onItemSelected({
source: api.source,
target: api.target
})}
/>
<div className="flip-card">
<div className="flip-card-inner">
<div className="flip-card-front">
<p id="api-source">{api.source}</p>
</div>
<div className="flip-card-back">
<p className="api-target">{api.target}</p>
</div>
</div>
</div>
</li>
</>
);
};
These codes should work, hope you got the logic also. This approach would be logical in your case.
I have a PostList component with an array of posts objects. I am rendering this list of post using another pure functional component Post using Array.map() method. Post component has another component - LikeButton to like or unlike a post. Now I want to show a spinner during like or unlike on top of that LikeButton component. LikeButton Component looks something like this:
const LikeButton = (props) => {
const likeBtnClasses = [classes.LikeBtn];
const loggedInUserId = useSelector((state) => state.auth.user.id);
const isLoading = useSelector((state) => state.post.loading);
const isPostLiked = props.post.likes.find(
(like) => like.user === loggedInUserId
);
const [isLiked, setLike] = useState(isPostLiked ? true : false);
const token = useSelector((state) => state.auth.token);
const dispatch = useDispatch();
if (isLiked) {
likeBtnClasses.push(classes.Highlight);
}
const postLikeHandler = () => {
if (!isLiked) {
setLike(true);
dispatch(actions.likePost(props.post._id, token));
} else {
setLike(false);
dispatch(actions.unlikePost(props.post._id, token));
}
};
return isLoading ? (
<Spinner />
) : (
<button
className={likeBtnClasses.join(" ")}
onClick={() => postLikeHandler()}
>
<i class="far fa-thumbs-up"></i>
<small>{props.post.likes.length}</small>
</button>
);
};
Instead of showing the spinner to that single post, I am seeing it on all the posts.
My Post component looks like this:
const Post = (props) => {
return (
<div className={classes.Post}>
<div className={classes.Author}>
<img src={props.postData.avatar} alt="avatar" />
<div className={classes.AuthorDetails}>
<h3>{props.postData.name}</h3>
</div>
</div>
<div className={classes.PostText}>
<p>{props.postData.text}</p>
</div>
<hr />
<div className={classes.PostTools}>
<LikeButton post={props.postData} />
<div className={classes.PostBtn}>
<i class="far fa-comments"></i>
<small>3</small>
</div>
<div className={classes.PostBtn}>
<i class="fas fa-share"></i>
<small>2</small>
</div>
</div>
</div>
);
};
PostList component:
class PostList extends React.Component {
state = {
posts: [
{
text: "POST1",
user: "XYZ",
name: "XYZ",
id: "post1",
likes: [],
},
{
text: "POST2",
user: "johndoe#test.com",
name: "John Doe",
id: "post2",
likes: [],
},
],
};
componentDidMount() {
if (this.props.token) {
this.props.onFetchPosts(this.props.token);
this.props.onFetchUserAuthData(this.props.token);
}
}
render() {
let posts = null;
if (this.props.posts.length === 0) {
posts = this.state.posts.map((post) => {
return <Post key={post.id} postData={post} />;
});
} else {
posts = this.props.posts.map((post) => {
return <Post key={post._id} postData={post} />;
});
}
return (
<div>
<CreatePost />
{posts}
</div>
);
}
}
const mapStateToProps = (state) => {
return {
token: state.auth.token,
posts: state.post.posts,
loading: state.post.loading,
error: state.post.err,
};
};
const mapDispatchToProps = (dispatch) => {
return {
onFetchPosts: (token) => dispatch(actions.fetchPosts(token)),
onFetchUserAuthData: (token) => dispatch(actions.fetchUser(token)),
};
};
Please do some change in your to checking like/unlike is loading or not for the LikeButton.
const LikeButton = (props) => {
....
const [isButtonLoading, setButtonLoading] = useState(false);
...
return isButtonLoading ? (
<Spinner />
) : (
<button
className={likeBtnClasses.join(" ")}
onClick={() => postLikeHandler();setButtonLoading(true)}
>
<i class="far fa-thumbs-up"></i>
<small>{props.post.likes.length}</small>
</button>
);
};
Then on your dispatch callback need to set the isButtonLoading value to false.
const buttonCallback() {
// here we need to reset our flag
setButtonLoading(false);
}
const postLikeHandler = () => {
if (!isLiked) {
setLike(true);
// for this action you need to create third parameter called as callback so after response our buttonCallback will call
dispatch(actions.likePost(props.post._id, token, buttonCallback));
} else {
setLike(false);
// for this action you need to create third parameter called as callback so after response our buttonCallback will call
dispatch(actions.unlikePost(props.post._id, token, buttonCallback);
}
};
fore more details please check here.
Hope this will help you.
I have a page with a search input, once the user clicks on submit the results come up.
There can be a lot of results (usually not but there can be thousands of results) and I don't want to load them all at once, how can I get a few dozens and fetch more results from he API as the user scrolls down, what's the correct way to do that? I was thinking that Lodash throttle can fit but I couldn't find a good example for it.
This is my react component:
const getContacts = async (searchString) => {
const { data: contactsInfo} = await axios.get(`api/Contats/Search?contactNum=${searchString}`);
return contactsInfo;
};
export default class Home extends React.Component {
state = {
contactsInfo: [],
searchString: '',
};
handleSubmit = async () => {
const { searchString } = this.state;
const contactsInfo = await getContacts(searchString);
this.setState({ contactsInfo });
};
onInputChange = e => {
this.setState({
searchString: e.target.value,
});
};
onMouseMove = e => {
};
render() {
const { contactsInfo, searchString, } = this.state;
return (
<div css={bodyWrap} onMouseMove={e => this.onMouseMove(e)}>
<Header appName="VERIFY" user={user} />
{user.viewApp && (
<div css={innerWrap}>
<SearchInput
searchIcon
value={searchString || ''}
onChange={e => this.onInputChange(e)}
handleSubmit={this.handleSubmit}
/>
{contactsInfo.map(info => (
<SearchResultPanel
info={info}
isAdmin={user.isAdmin}
key={info.id}
/>
))}
</div>
)}
<Footer />
</div>
);
}
}
If the API supports pagination then you can use React-Infinite-Scroll. It looks like this
<div style="height:700px;overflow:auto;">
<InfiniteScroll
pageStart={0}
loadMore={loadFunc}
hasMore={true || false}
loader={<div className="loader">Loading ...</div>}
useWindow={false}>
{items}
</InfiniteScroll>
</div>
However if the REST API does not support it, you can still load the data and show them in chunks to the user with the same library but you would need to handle the current load state by yourself.