反应无限滚动组件 - dataLength 不工作

React infinite scroll component - dataLength not working

我有一个函数 newsFeed,它由 useEffect 调用并向端点发出请求以获取登录用户以及他们关注的任何用户发布的所有帖子,然后保存数据响应状态:

const [posts, setPosts] = useState([])
const [page, setPage] = useState(1)

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

const newsFeed = async () => {
    await axios.post(
        `${process.env.REACT_APP_API}/news-feed/${page}`,
    )
    .then((res) => {
        setPosts(res.data);
        setPage(page + 1);
    })
    .catch((err) => {
        console.log(err);
    });
};

router.post('/news-feed/:page', newsFeed);

exports.newsFeed = async (req, res) => {
    try {
        const user = await User.findById(req.body.user._id);
        let following = user.following;
        following.push(req.body.user._id);

        const currentPage = req.params.page || 1;
        const perPage = 5;

        const posts = await Post.find({ postedBy: { $in: following } })
        .skip((currentPage - 1) * perPage)
        .sort({createdAt: -1})
        .limit(perPage);
        res.json(posts);
    } catch (err) {
        console.log(err);
    }
};

我想使用 react-infinite-scroll-component 在页面加载时仅获取前 20 个帖子,然后在用户滚动到底部时获取另外 20 个帖子等。

我目前有此代码来呈现帖子:

<div id='scrollableDiv' style={{ overflow: 'auto' }}>
    <InfiniteScroll
      dataLength={20}
      next={newsFeed}
      hasMore={true}
      loader={<FontAwesomeIcon icon={faSpinner} spin />}
      endMessage={
        <p style={{ textAlign: 'center' }}>
          <b>Yay! You have seen it all</b>
        </p>
      }
      scrollableTarget='scrollableDiv'
    >
        {posts.map((post) => (
        ...)}
    </InfiniteScroll>
</div>

现在的情况是只呈现前 20 个帖子,加载微调器持续显示在下方。

我尝试添加 page 作为 useEffect 回调的依赖项,这确实导致以 20 个块的形式加载帖子,但是它们每秒自动呈现并与前一个块重叠,就像应用程序一样确实在更改页面,当所有内容都呈现后显示一个空白屏幕。

您的问题似乎是您的后端在您每次调用它时都return处理所有记录,因为没有传递给它的参数:

await axios.post(
    `${process.env.REACT_APP_API}/news-feed`,
)

这与声明的组件文档不一致:

The data is passed as children to the InfiniteScroll component and the data should contain previous items too. e.g. Initial data = [1, 2, 3] and then next load of data should be [1, 2, 3, 4, 5, 6].

因此,您需要告诉后端要 return 的哪一组项目,然后将这些项目附加到您在之前调用中已加载的帖子中。

例如,保留您需要的页面的引用 returned 并使用参数调用后端:

//In state declaration
const [pageNumber, setPageNumber] = useState(1);

//In loader function
await axios.post(
    `${process.env.REACT_APP_API}/news-feed/{pageNumber}`,
) 

其中 pageNumber 是您与当前页码保持状态的变量,然后在每次收到项目时递增它。大致如下:

await axios.post(
    `${process.env.REACT_APP_API}/news-feed/{pageNumber}`,
)
.then((res) => {
    let newPosts = posts;
    newPosts.concat(res.data);
    setPosts(newPosts);
    setPageNumber(pageNumber + 1);
})

如果您无法修改后端以支持分页,那么您将不得不每次都检索所有记录并将它们切片为 select 您需要追加的记录。不是特别困难,但效率很低。像这样:

//In state declaration
const [pageNumber, setPageNumber] = useState(0); //0 based

//In data loader
await axios.post(
    `${process.env.REACT_APP_API}/news-feed`,
)
.then((res) => {
    let newPosts = posts;
    let start = (pageNumber === 0) ? 0 : (pageNumber * 20) - 1;
    let addPosts = res.data.slice(start, 20);
    newPosts = newPosts.concat(addPosts);
    setPosts(newPosts);
    setPageNumber(pageNumber + 1);
})

我写这篇文章很匆忙,所以请务必检查记录的一致性和结尾。你明白了。 :-)