Search code examples
javascriptreactjsreact-infinite-scroll-componentreact-infinite-scroll

How to use react-infinite-scroll-component inside a Material-UI Dialog modal?


I'm using react-infinite-scroll-component in a project and it works fine outside a Dialog. When I scroll to the bottom of a page, the next set of data is fetched from the server but I can't get the same action inside my Material-UI Dialog.

Here's the Dialog code:

//imports

export default function Posts() {
  const [open, setOpen] = React.useState(false);
   //more consts
   ...
  const [posts, setPosts] = useState([]);
  const [page, setPage] = useState(1);

  const fetchPosts = () => {
    axios.get(`${serverURL}/news?page=${page}`).then((res) => {
      const result = res.data.results;
      setPosts([...posts, ...result]);
      setPage((prev) => prev + 1);
    });
    console.log("page", page);
  };

  useEffect(() => {
    fetchPosts();
  }, []);

  return (
    <div>
      <h1>News</h1>
      <Button variant="outlined" color="primary" onClick={handleClickOpen}>
        Open News Dialog
      </Button>
      <Dialog
        onClose={handleClose}
        aria-labelledby="customized-dialog-title"
        open={open}
      >
        <DialogTitle id="customized-dialog-title" onClose={handleClose}>
           News
        </DialogTitle>

        <DialogContent dividers>
          <ul
            style={{
              display: "inline",
            }}
          >
            <InfiniteScroll
              dataLength={posts.length}
              next={() => fetchPosts()}
              hasMore={true}
              loader={<h4 style={{ textAlign: "center" }}>Loading.....</h4>}
              endMessage={
                <p style={{ textAlign: "center" }}>
                  <b>You read all news posts.</b>
                </p>
              }
            >
              {posts.length > 1 &&
                posts.map((post, i) => {
                  return (
                    <div key={i}>
                      <Card className={classes.root}>
                        <div className={classes.details}>
                          <CardContent className={classes.content}>
                            <Typography
                              className={classes.title}
                              component="a"
                              variant="h5"
                            >
                              {post.title}
                            </Typography>
                            <Typography className={classes.desc}>
                                {post.content}
                            </Typography>
                          </CardContent>
                        </div>
                      </Card>
                    </div>
                  );
                })}
            </InfiniteScroll>
            );
          </ul>
        </DialogContent>
      </Dialog>
    </div>
  );
}

The log doesn’t show that I reach the second page, it just stops after I reach the first 30 posts as defined in my backend.

When I test this code outside a Dialog, there are no issues. The infinite scroll works fine on this small text:

function App() {
  const [posts, setPosts] = useState([]);
  const [page, setPage] = useState(1);

  const fetchPosts = () => {
    axios
      .get(`${serverURL}/api/news?page=${page}`)
      .then((res) => {
        const result = res.data.results;
        setPosts([...posts, ...result]);
        setPage((prev) => prev + 1);
      });
    console.log("page", page);
  };

  useEffect(() => {
    fetchPosts();
  }, []);

  return (
    <div className="App">
      <InfiniteScroll
        dataLength={posts.length}
        next={() => fetchPosts()}
        hasMore={true}
        loader={<h4>Loading.....</h4>}
        endMessage={
          <p style={{ textAlign: "center" }}>
            <b>You read all news posts.</b>
          </p>
        }
      >
        {posts.length > 1 &&
          posts.map((post, i) => (
            <div key={i}>
              <p>{post.title}</p>
              <p>{post.image}</p>
              <p>{post.content}</p>
              <p>{post.link}</p>
            </div>
          ))}
      </InfiniteScroll>
    </div>
  );
}

export default App;

How Can I get the infinite scroll to work inside a Dialog?


Solution

  • I was able to fix this by adding the scrollableTarget prop to the DialogContent like this:

    <InfiniteScroll
                dataLength={posts.length}
                next={() => fetchPosts()}
                hasMore={true}
                loader={<h4 style={{ textAlign: "center" }}>Loading.....</h4>}
                endMessage={
                  <p style={{ textAlign: "center" }}>
                    <b>You read all new posts.</b>
                  </p>
                }
                **scrollableTarget="scrollableDiv"**
              >
    

    And then added the id="scrollableDiv" to DialogContent:

    <DialogContent dividers id="scrollableDiv">
    ...
    </DialogContent>
    

    By default, react-infinite-scroll-component targets the entire window so if you want to apply it to a modal, you must target that window with scrollableTarget prop.