I'm using react - redux environment for my web app and I'm not able to make an inifinite scroll, Once i reach the bottom, I'm getting an error that useEffect cannot be used. Here is the code below:
import React, { useEffect } from 'react';
import './Homefeed.css';
import StickyNav from '../StickyNav/StickyNav';
import { fetchHomePosts } from '../Redux/HomeFeed-Redux/HomeFeedActionMethods';
import { connect } from 'react-redux';
import PostCell from '../PostCell/PostCell';
import InfiniteScroll from 'react-infinite-scroll-component';
import { useDispatch } from 'react-redux'
function Homefeed({homeposts,fetchHomePosts}) {
var skipper = 0;
let dispatch = useDispatch()
useEffect(()=>{fetchHomePosts(skipper);},[dispatch]);
function MorePosts(){
console.log(homeposts);
console.log("more");
useEffect(()=>{fetchHomePosts(skipper+10);},[]);
}
return homeposts.isLoading ? (<h2>Loading...</h2>) : homeposts.error ? (<h3>{homeposts.error}</h3>) : (
<div className="homefeed-layout">
<title>Home Feed</title>
<StickyNav />
<InfiniteScroll
dataLength={homeposts.homeposts.length}
hasMore={true}
loader={<h3>Loading</h3>}
next={()=>{MorePosts()}}
>
{
homeposts.homeposts?.map((key,index)=> {
var slug = key.attributes.title;
slug = slug.replace(/\s/g, '-');
slug = slug.toLowerCase();
slug = slug.replace(/[^a-zA-Z0-9\-]/g, '');
slug = slug.replace(/(-)\1+/g, '-');
slug = slug.replace(/-$/, '');
slug = slug.replace(/^-/, '');
return(
<div className="content-area" key={index} >
<PostCell
key ={index}
slug = {slug}
postId = {key.id}
title ={key.attributes.title}
likes ={key.attributes.likes}
comments ={key.attributes.comments}
category ={key.attributes.category}
postimageurl = {key.attributes.postImageURL}
handle ={key.attributes.createdBy.attributes.handle}
timestamp = {key.attributes.createdAt}
subtitle = {key.attributes.subtitle}
realName ={key.attributes.createdBy.attributes.realName}
profileImage = {key.attributes.createdBy.attributes.profileImage?._url}
followers = {key.attributes.createdBy.attributes.followers}
posts = {key.attributes.createdBy.attributes.posts}
name = {key.attributes.createdBy.attributes.name}
/>
</div>
)
})
}
</InfiniteScroll>
</div>
)
}
const mapStatetoProps = (state) =>{
return{
homeposts:state.HomePosts
}
}
const mapDispatchtoProps = (dispatch) =>{
return{
fetchHomePosts:(skipper)=>{dispatch(fetchHomePosts(skipper))},dispatch,
}
}
export default connect(mapStatetoProps,mapDispatchtoProps) (Homefeed)
So here the next prop in the Infinite scroll is supposed to call more data which should append to the existing data. The moreposts function should call the api but react gives me an error saying that you cannot call useEffect inside this function.
If i use useDispatch(), its stuck in an infinite loop, can someone please help me out, I'm pretty new to this.
You cannot call useEffect
inside of another function because this breaks the rules of hooks. But the useEffect
isn't doing anything here. You could just call fetchHomePosts(skipper+10)
from morePosts()
.
That would load the second page. If you want to load the third and the fourth and so on then you need to make skipper
a state rather than a var
. Add 10
to skipper
whenever you load a page.
You can either:
skipper
and call fetchHomePosts()
in your morePosts()
function.skipper
in your morePosts()
function and call fetchHomePosts()
from a useEffect
hook which has skipper
as a dependency so that the effect runs whenever the value of skipper
changes.homePosts
array.You don't need to use useDispatch
and connect
. They are two ways of doing the same thing so you should use one or the other. The hooks are the recommended approach.
This is not perfect but I don't want to overcomplicate things:
export default function Homefeed() {
const homeposts = useSelector((state) => state.HomePosts);
const dispatch = useDispatch();
// want to make sure that the first page is loaded when the component mounts
useEffect(() => {
dispatch(fetchHomePosts(0));
}, [dispatch]);
// starts at 0 and increases when more posts load
const dataLength = homeposts.homeposts.length;
// function to load the next page
const morePosts = () => {
dispatch(fetchHomePosts(dataLength));
};
return homeposts.isLoading ? (
<h2>Loading...</h2>
) : homeposts.error ? (
<h3>{homeposts.error}</h3>
) : (
<div className="homefeed-layout">
<title>Home Feed</title>
<StickyNav />
<InfiniteScroll
dataLength={dataLength}
hasMore={true}
loader={<h3>Loading</h3>}
next={morePosts}
>
{homeposts.homeposts?.map((key, index) => {
// I would store this slug in Redux when you store the post
const slug = key.attributes.title
.replace(/\s/g, "-")
.toLowerCase()
.replace(/[^a-zA-Z0-9-]/g, "")
.replace(/(-)\1+/g, "-")
.replace(/-$/, "")
.replace(/^-/, "");
return (
<div className="content-area" key={index}>
<PostCell
key={index}
slug={slug}
postId={key.id}
title={key.attributes.title}
likes={key.attributes.likes}
comments={key.attributes.comments}
category={key.attributes.category}
postimageurl={key.attributes.postImageURL}
handle={key.attributes.createdBy.attributes.handle}
timestamp={key.attributes.createdAt}
subtitle={key.attributes.subtitle}
realName={key.attributes.createdBy.attributes.realName}
profileImage={
key.attributes.createdBy.attributes.profileImage?._url
}
followers={key.attributes.createdBy.attributes.followers}
posts={key.attributes.createdBy.attributes.posts}
name={key.attributes.createdBy.attributes.name}
/>
</div>
);
})}
</InfiniteScroll>
</div>
);
}