ankeetmaini / react-infinite-scroll-component

An awesome Infinite Scroll component in react.
https://react-infinite-scroll-component.netlify.com/
MIT License
2.84k stars 320 forks source link

React infinite scroll next has called only once #307

Open Erwan2005 opened 2 years ago

Erwan2005 commented 2 years ago

I'm training to develop my little app with react, and I'm stuck in infinite scrolling I'm using react infinite scroll components, it calls the fetchmoredata function but just once, how to fix this kind of problem with my code below

`import React, {Fragment} from 'react' import { Card,CardHeader,CardActionArea, CardMedia,CardContent, Typography, CardActions,withStyles, Avatar,IconButton,Collapse,Button, InputAdornment,FormControl,Input,List, ListItem,ListItemText,ListItemAvatar, CircularProgress,InputBase,Divider,Box } from '@material-ui/core'; import { MoreVert,FavoriteBorder,Share,Telegram,PermMedia,Room,EmojiEmotions,Favorite } from '@material-ui/icons'; import {format} from 'timeago.js'; import { Link } from 'react-router-dom'; import NumericLabel from 'react-pretty-numbers'; import axios from 'axios'; import { AuthContext } from "../context/AuthContext"; import InfiniteScroll from 'react-infinite-scroll-component'; import _ from 'lodash';

const useStyles = theme => ({ media:{ height: 250,

  height: 150,
},

}, card:{ marginBottom: theme.spacing(1), boxShadow: 'none', backgroundColor: '#424242', }, tile:{ height: theme.spacing(40), display: "flex", flexDirection: "column", margin: 5,

}, name:{ fontSize: 16, fontWeight: 500, color: "#848484", }, card_action:{ display: "flex", justifyContent: "space-between", borderTop: '1px solid #484848', }, card_header:{ backgroundColor: "#424242", }, item:{ display: "flex", alignItems: "center", spacing: theme.spacing(1), color: "#848484", }, link:{ display: "flex", textDecoration: "none", color: "#848484", textTransform: 'capitalize', }, share:{ backgroundColor: '#424242', marginBottom: theme.spacing(1), padding: theme.spacing(2), borderRadius: theme.spacing(1), //boxShadow: '0px 1px 7px 0px rgba(0,0,0,0.37)', }, share_top:{ display: 'flex', alignItems: 'center', }, shareBottom:{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', paddingTop: '10px' }, options:{ display: 'flex', marginLeft: theme.spacing(6.2), }, option:{ display: 'flex', alignItems: 'center',

padding: theme.spacing(1),
cursor: 'pointer',
"&:hover": {
      background: '#454545',
      borderRadius: theme.spacing(1),
},
[theme.breakpoints.down("xs")]:{
  marginRight: '2px',
},

}, shareIcon:{ fontSize: '18px', marginRight: '3px', }, shareOptionText:{ fontSize: '12px', fontWeight: '500', color: "#848484",

  display: 'none',
},

}, shareButton:{ textTransform: 'none', background: 'green', color: 'white', fontWeight: '500', "&:hover": { background: 'green', fontWeight: 'bold', },

  width: '45px',
  height: '30px',
  fontSize: '13px',
  padding: '3px',
},

}, });

export class Post extends React.Component { static contextType = AuthContext; constructor(props){ super(props); this.refImg = React.createRef(); this.state={ expanded:false, anchorElP: '', comment: '', share: '', comments: [], publication: [], users: [], current: [], next_url: 'http://127.0.0.1:8000/userapp/publication/', count: null, more_exist: true, image: '', liked: false, like: [], };

};

handleExpandClick = (id) => { this.setState({ [expanded_${id}]: .isUndefined(this.state[`expanded${id}])?true:!this.state[expanded_${id}`] }); };

handleProfileMenuOpenP = (event) => { this.setState({anchorElP:event.currentTarget}); };

handleMenuCloseP = () => { this.setState({anchorElP:null});

}; getPub = async() =>{ await axios({ method: 'get', url: this.state.next_url, headers:{ Authorization: Token ${this.context.user.token}, }, }).then(res =>{ var has_more = false if(res.data.next){ has_more = true } this.setState({ next_url: res.data.next, count: res.data.count, publication: res.data.results, more_exist: has_more, }) }) }; getLike = async() =>{ let data = await axios.get('http://127.0.0.1:8000/userapp/like/') .then(({data})=>data) this.setState({like: data}) };

getCom = async() =>{ let data = await axios({ method: 'get', url: 'http://127.0.0.1:8000/userapp/comment/', }).then(({data}) => data) this.setState({comments: data}) }; getUser = async() =>{ let data = await axios({ method: 'get', url: 'http://127.0.0.1:8000/userapp/users/', }).then(({data}) => data) this.setState({users: data}) }; getCurrentUser = async() =>{ let data = await axios({ method: 'get', url: http://127.0.0.1:8000/userapp/users/${this.context.user.id}/,

}).then(({data}) => data)
this.setState({current: data})

};

btnComment = async(content,id_post) => { let author = parseInt(this.context.user.id, 10) let post_connected = parseInt(id_post, 10) const contents = {content:content,author:author,post_connected:post_connected} let data = await axios.post('http://127.0.0.1:8000/userapp/comment/',contents) .then(({data}) => data) this.setState({comments: this.state.comments.concat(data)}) this.setState({comment:''})

};

btnShare = async()=>{ let author = parseInt(this.context.user.id, 10) const contents = {user:author,message: this.state.share,image:this.state.image} await axios.post('http://127.0.0.1:8000/userapp/publication/',contents,{ headers:{ Authorization: Token ${this.context.user.token} } }).then(res=>{ console.log(res) }) this.setState({share:'',image:''}) };

fetchData = async() =>{ await axios({ method: 'get', url: this.state.next_url, headers:{ Authorization: Token ${this.context.user.token}, }, }).then(res =>{ var has_more = false if(res.data.next){ has_more = true } this.setState({ next_url: res.data.next, count: res.data.count, publication: this.state.publication.concat(res.data.results), more_exist: has_more, }) console.log(this.state.count) }) };

imageHandler = async (e) => {

  const reader = new FileReader();
  reader.onload = () =>{
    if(reader.readyState === 2){
      this.setState({image:reader.result})
    }
  }
  reader.readAsDataURL(e.target.files[0])
  const file = e.target.files[0];
  const base64 = await this.convertBase64(file);
  this.setState({image:base64})
};

convertBase64 = (file) => { return new Promise((resolve, reject) => { const fileReader = new FileReader(); fileReader.readAsDataURL(file);

    fileReader.onload = () => {
      resolve(fileReader.result);
    };

    fileReader.onerror = (error) => {
      reject(error);
    };
  });
};

checkLiked = (userId,postId) =>{ if (this.state.like.filter(item=> item.author == userId && item.post_connected === postId).length == 0) return false else return true };

dlt =async(id)=>{ await axios.delete(http://127.0.0.1:8000/userapp/like/${id}) this.getLike() };

dltLike = (userId,postId)=>{ this.state.like.filter(item=> item.author == userId && item.post_connected === postId).map(cheked=>(this.dlt(cheked.id))) };

postLike = async(author,post_connected) =>{ let data = await axios.post('http://127.0.0.1:8000/userapp/like/',{author,post_connected}) .then(({data})=>data) this.setState({like: this.state.like.concat(data)}) };

componentDidMount(){ this.getUser() this.getPub() this.getCom() this.getCurrentUser() this.getLike() }; render() { const { classes } = this.props; return ( <InfiniteScroll pageStart={0} dataLength={this.state.more_exist} //This is important field to render the next data next={this.fetchData} hasMore={this.state.more_exist} loader={

Loinding ...

    }
    endMessage={
      <p style={{ textAlign: 'center' }}>
        <b>Yay! You have seen it all</b>
      </p>
    }
    // below props only if you need pull down functionality
    pullDownToRefreshContent={
      <h3 style={{ textAlign: 'center' }}>&#8595; Pull down to refresh</h3>
    }
    releaseToRefreshContent={
      <h3 style={{ textAlign: 'center' }}>&#8593; Release to refresh</h3>
    }
  >
    <div className={classes.share}>
      <div className={classes.share_top}>
        <Avatar src={this.state.current.avatar} style={{marginRight: 10}}/>
        <div style={{width: '100%'}}>
          <InputBase
            placeholder="Share your advice ... "
            multiline
            fullWidth
            value = {this.state.share}
            onChange = {e => this.setState({share:e.target.value})}
            style={{color: '#848484'}}
          />
          <Divider style={{backgroundColor: '#848484'}}/>
        </div>
      </div>
      <div className={classes.shareBottom}>
        <div className={classes.options}>
          <div className={classes.option} onClick={(event) => {
            event.preventDefault();
            this.refImg.current.click();
            }}>
            <PermMedia htmlColor="tomato" className={classes.shareIcon}/>
            <span className={classes.shareOptionText}>Photo / video</span>
          </div>
          <input type='file' id='file-img' onChange={(e) => {
            this.imageHandler(e);
          }} ref={this.refImg} style={{display: 'none'}}/>

          <div className={classes.option}>
            <Room htmlColor="green" className={classes.shareIcon}/>
            <span className={classes.shareOptionText}>Location</span>
          </div>

          <div className={classes.option}>
            <EmojiEmotions htmlColor="goldenrod" className={classes.shareIcon}/>
            <span className={classes.shareOptionText}>Feellings</span>
          </div>
        </div>
        <Button className={classes.shareButton} onClick={this.btnShare}>Share</Button>
      </div>
    </div>
    {this.state.publication && this.state.publication.map((pub, index) => {
      return(
      <div key = {pub.id}>
        {this.state.users && this.state.users.map(profile => {
          if (pub.user === profile.id){
            //const id_pub = pub.user
            //const id_aut = this.state.current.id
            return(
              <div key = {profile.id}>
                <Card className={classes.card}>
                  <CardHeader 
                    className={classes.card_header}
                    avatar={
                      <Avatar src={profile.avatar}/>
                    }
                    action={
                      <IconButton>
                        <MoreVert/>
                      </IconButton>
                    }
                    title={
                      <Link exact to={`/home/profile/${profile.id}`} className={classes.link}>
                        <Typography className={classes.name}> {profile.username}</Typography>
                      </Link>
                    }
                    subheader={format(pub.date)}
                  />
                  <CardActionArea>
                    <CardMedia className={classes.media} image={pub.image} />
                    <CardContent>
                      <Typography variant="h6">{pub.message}</Typography>
                    </CardContent>
                  </CardActionArea>
                  <CardActions className={classes.card_action}>
                    <div className={classes.item}>
                      {(this.checkLiked(this.state.current.id,pub.id)) ? (
                        <Favorite htmlColor="pink" style={{cursor: 'pointer'}} onClick={() => this.dltLike(this.state.current.id,pub.id)}/>
                        ):(
                        <FavoriteBorder htmlColor="pink" style={{cursor: 'pointer'}} onClick={() => this.postLike(this.state.current.id,pub.id)}/>
                      )
                      }
                      <Button className={classes.link} size="small" variant="text" disabled><NumericLabel params={{shortFormat: true,}}>{this.state.like.filter(item=> item.post_connected === pub.id).length}</NumericLabel>&nbsp; Like</Button>
                    </div>
                    <div className={classes.item}>
                      <Button className={classes.link} size="small" onClick={() => this.handleExpandClick(pub.id)}
                      aria-expanded={this.state[`expanded_${pub.id}`] || false}
                      ><NumericLabel params={{shortFormat: true,}}>{this.state.comments.filter(item=> item.post_connected === pub.id).length}</NumericLabel>&nbsp; Comment</Button>

                      <IconButton size="small" className={classes.right}>
                        <Share/>
                      </IconButton>
                    </div>
                  </CardActions>
                  <Collapse in={this.state[`expanded_${pub.id}`] || false} timeout="auto" unmountOnExit>
                    <CardContent>
                       <div className={classes.item}>
                        <Avatar src={this.state.current.avatar}/>&emsp;
                        <div style={{width: '100%'}}>
                          <InputBase
                            placeholder="Your comments... "
                            multiline
                            fullWidth
                            value = {this.state.comment}
                            onChange = {e => this.setState({comment:e.target.value})}
                            style={{color: '#848484'}}
                          />
                          <Divider style={{backgroundColor: '#848484'}}/>
                        </div>
                        <IconButton
                          edge="end"
                          onClick={() => this.btnComment(this.state.comment,pub.id)}
                        >
                          <Telegram />
                        </IconButton>

                        </div>
                        <div style={{maxHeight: 150,overflowY: "scroll",}}>
                          {this.state.users && this.state.users.map(author => {
                            return(
                              <div key={author.id}>
                                {this.state.comments && this.state.comments.map(post_com => {
                                  if (author.id === post_com.author && post_com.post_connected === pub.id){
                                    return(
                                      <div key={post_com.id}>
                                        <div className={classes.item}>
                                          <List sx={{ width: '100%', bgcolor: 'background.paper', overflow: 'auto' }}>
                                            <ListItem alignItems="flex-start">
                                              <ListItemAvatar>
                                                <Avatar src={author.avatar} />
                                              </ListItemAvatar>
                                              <ListItemText
                                                primary=<Link className={classes.link}>{author.username}</Link>
                                                secondary={
                                                  <Fragment>
                                                  <Typography
                                                    sx={{ display: 'inline' }}
                                                    component="span"
                                                    variant="body2"
                                                    color="text.primary"
                                                  >
                                                    {post_com.content}
                                                  </Typography>
                                                  {" — ("+format(post_com.date_posted)+")"}
                                                  </Fragment>
                                                }
                                                />
                                            </ListItem>
                                          </List>
                                        </div>
                                      </div>
                                    )
                                  }else return null
                                })}
                              </div>
                            )
                          })}
                        </div>
                      </CardContent>
                  </Collapse>
                </Card>
              </div>
            )}else return null
        })}

      </div>)
    })}
  </InfiniteScroll>
)

} }

export default withStyles(useStyles)(Post);`

Mujaddadi commented 2 years ago

Yes same issue. But please reformate your code example.

maitrungduc1410 commented 2 years ago

same issue, in my case I have around 5 pages, but it only load first 2 pages, don't know why the rest 3 pages can't be loaded

Mujaddadi commented 2 years ago

I am using a different infinite scroll component now https://github.com/danbovey/react-infinite-scroller. That seems to be working fine. In my case DOM scroll events code is working

zhangwei900808 commented 2 years ago

same issue and I set scrollableTarget="scrollableDiv" in div id=scrollableDiv its worked!

<div id="scrollableDiv" className={styles.noticeBody}>
              <InfiniteScroll
                dataLength={remindList.length}
                next={loadMoreData}
                hasMore={remindList.length < remindListTotal}
                loader={<Skeleton avatar paragraph={{rows: 1}} active/>}
                endMessage={null}
                scrollableTarget="scrollableDiv"
              >
EugeneFoo commented 2 years ago

same issue, only load first page and second page, then it will not loading third page onwards

orahul1 commented 2 years ago

any solution ?

orahul1 commented 2 years ago

https://github.com/ankeetmaini/react-infinite-scroll-component/issues/274#issuecomment-846626389 this answer fixed my issue

clam61 commented 2 years ago

Thanks @orahul1 You saved me. That part of the documentation was a bit fuzzy in the wording.

smshahrukh-cm commented 2 years ago

https://github.com/ankeetmaini/react-infinite-scroll-component/issues/307#issuecomment-1013802958 Fixes the issue.

ducfilan commented 2 years ago

Set dataLength={items.length} instead of total items to be loaded.

skyfore commented 8 months ago

same issue for me Edit sparkling-sky-qpqlcz

carlos-dubon commented 7 months ago

https://stackoverflow.com/questions/67699376/react-infinite-scroll-component-stopped-working-after-one-call-loadmore-only

jasonpyf commented 2 days ago

I solved it this way by rewriting his method, if next error

import InfiniteScroll, { Props } from "react-infinite-scroll-component";

export default class MyInfiniteScroll extends InfiniteScroll {
  componentDidUpdate(prevProps: Props) {
    prevProps.dataLength = 0;
    super.componentDidUpdate(prevProps);
  }
}