I created a home page that contains three components HomeHeader
, CompanyList
and ScrollToTopBtn
.
Focusing on CompanyList
it is a container component that shows list of CompanyCards
that were fetched using an API in Home
page. List of companies are initialized in Home
page like this
const [companies, setCompanies] = useState([]);
The problem is that initially after making the API call, I use spread operator to update the companies
list like this
const fetchedCompanies = await fetchFeedData(page);
console.log(fetchedCompanies);
setCompanies((prevCompanies=>{return [...prevCompanies,fetchedCompanies]}));
console.log(companies);
But an error occurs Uncaught TypeError: prevCompanies is not iterable
since I believe that companies
list is initially empty.
I tried to use another approach by using concat
method but companies
list stayed empty and showed no companies found
message.
Below is the source code for Home
page
const Home = () => {
const [page, setPage] = useState(1); //In order to avoid showing "no companies found" initially
const [isLoading, setIsLoading] = useState(true);
const [companies, setCompanies] = useState([]);
const [isError, setIsError] = useState(false);
const [hasMore, setHasMore] = useState(false);
useEffect(() => {
const fetchData = async () => {
setIsLoading(true);
setIsError(false);
try {
const fetchedCompanies = await fetchFeedData(page);
setCompanies((prevCompanies=>{prevCompanies.concat(fetchedCompanies)})); //problem here
setHasMore(fetchedCompanies.length > 0)
} catch (e) {
setIsError(true)
setHasMore(false);
}
setIsLoading(false)
}
fetchData();
}, [page])
return (
<div>
<ScrollToTopBtn />
<Helmet>
<title>{stackinfo.title} - {home.title}</title>
</Helmet>
<HomeHeader />
{
isLoading ? (<LoadingSpinner />) :
isError ? (<ErrorBoundary message={somethingWrongError.message}></ErrorBoundary>) :
<CompanyList companies={companies} ></CompanyList>
}
<Container className={"mt-5"}>
<Row>
<Col sm={12}>
{(!isLoading && !isError && hasMore) &&
<CustomBtn
ButtonText={showMoreBtnText.message}
onClick={() => { console.log("Need to increment number of pages") }}
></CustomBtn>}
</Col>
</Row>
</Container>
</div>
)
}
I tried to check the fetchedCompanies
and companies
after making the API call
const fetchedCompanies = await fetchFeedData(page);
//Returning new array containing previous companies and recent fetchedCompanies
console.log(fetchedCompanies);
setCompanies((prevCompanies=>{prevCompanies.concat(fetchedCompanies)}));
console.log(companies);
fetchedCompanies
logged an array that has 9 elements, while companies
as mentioned above logged empty array []
.
Sorry if I missed something, I am still new to React.
CodePudding user response:
You can do this below to update
setCompanies([...companies, ...fetchedCompanies])
If fetched Company are totally new Array containing all with previous record then just do it below;
setCompanies([...fetchedCompanies]);
//OR
setCompanies(fetchedCompanies);
If you have empty strings then do this below
setCompanies([...companies, ...fetchedCompanies.filter(com => !com)]);
CodePudding user response:
This is trying to mutate state, not return a new state (or maybe you just forgot the return
keyword?):
setCompanies((prevCompanies=>{prevCompanies.concat(fetchedCompanies)}));
Your previous attempt was closer:
setCompanies(prevCompanies=>{return [...prevCompanies, fetchedCompanies]});
But if fetchedCompanies
is also an array as the name implies then you forgot its spread operator:
setCompanies(prevCompanies=>{return [...prevCompanies, ...fetchedCompanies]});
Without that the resulting array would be weird at best.
You can also simplify a little:
setCompanies(prevCompanies=>[...prevCompanies, ...fetchedCompanies]);
And if you don't expect these calls to overlap at all, you could potentially simplify a lot:
setCompanies([...companies, ...fetchedCompanies]);
If after that there is still an empty string then it seems that the data has an empty string. In that case you'd have to filter that out manually, and where you do that is really up to you if the act of filtering might mess with the rest of the logic you have there (the hasMore
value, for example). But you can append .filter()
to the resulting array any time you like. When fetching, when updating state, or even just when rendering.
CodePudding user response:
You would be better to look where the empty string is coming from and try to resolve that issue but if you simple want to remove the empty string, use the following.
prevCompanies.concat(fetchedCompanies).filter(Boolean)