5

I'm using the react-infinite-scroll-component to implement the infinite scroll component. The configuration of the component is:

<div id="scrollableDiv" style={{ height: 300, overflow: "auto" }}>
       <InfiniteScroll
         dataLength={texts.length}
         next={getText}
         hasMore={true}
         loader={<h5>Loading...</h5>}
         endMessage={<p style={{textAlign:'center'}}><b>Yay! You've seen it all!</b></p>}
         scrollableTarget="scrollableDiv"
         >
         {<Texts texts = {texts}/>}
         </InfiniteScroll>
</div>

where texts is simply a state array of some text objects; const [texts, setTexts] = useState([])
This is the getText method to be called in next :

const getText = async ()=>{

        const res = await axios.get("http://localhost:3001/api/sth",{
            params: {
                ids: followings.map(i => i.id),
                str_ids: followings.map(i => i.str_id)
              },
              paramsSerializer: params => {
                return qs.stringify(params)
              }
        });

        let str_ids_res = res.data.map(i => i.string_id)
        let texts_res = res.data.map(i => i.texts)
        console.log(texts_res)

        const filtered_res = //some processing here on texts_res
        /* eslint eqeqeq: 0 */
        if(!arrayIsEqual(filtered_res,texts)){
            console.log("Not equal")
            // append arrays to a array state
            setTexts((prevtexts) => prevtexts.concat([...filtered_res]))
        }

    }

await axios.get("http://localhost:3001/api/sth")

always return two different texts from DB so setTexts should always get called.

component is a card component from semantic UI tho.

const Texts = ({texts}) =>{
    return (
        <>
            {texts.map(text =>(
                <div key={text.id}>
                    <Card>
                        <Card.Content>
                            <Card.Description>
                            {text.full_text}
                            </Card.Description>
                        </Card.Content>
                    </Card>
                </div>
            ))}
        </>
    );
}

InfiniteScroll component only fires Next once even though my datalength variable is setting correctly.
PS. the texts is empty initially so when I start the app, only 'Loading....' is called

zxcisnoias
  • 494
  • 3
  • 19

2 Answers2

11

After some experiments, passing height = {some height} as props to InfiniteScroll does the trick..

<div id="scrollableDiv" style={{ height: 300, overflow: "auto" }}>
                                    <InfiniteScroll
                                    dataLength={tweets.length}
                                    next={handleScrolling}
                                    hasMore={!isEnd}
                                    loader={<h5>Loading...</h5>}
                                    scrollThreshold={1}
                                    height={300}
                                    endMessage={
                                        <p style={{textAlign:'center'}}><b>Yay! You've seen it all!</b></p>
                                    }
                                    scrollableTarget="scrollableDiv"
                                    >
                                    {<Tweets tweets = {tweets}/>}
                                    </InfiniteScroll>
</div>
zxcisnoias
  • 494
  • 3
  • 19
0

Please do not initialize 'texts' with an empty array, you must initialize the 'texts' array with some array of objects (for example 10 or 20).

In the initial render of your code (at the first time). you can just fire an API in

useEffect(()=>{
  // make API call which your firing in the next call function
},[])

So your component gets initialization then after it will start behaving as expected.

For your understanding, Please refer to the sample example in "code sandbox" https://codesandbox.io/s/elated-danny-k4hylp?file=/src/index.js