【发布时间】:2021-03-22 02:41:09
【问题描述】:
免责声明:请不要将此标记为重复。我见过类似的问题和答案。但它们都不适合我。我只是在学习 React。
我想要实现的基本上是无限滚动。这样当用户滚动到页面末尾时,会加载更多数据。
我使用scroll eventListener 来实现这一点。它正在工作。
但是我遇到了变量状态的问题。
首先,我已将loading 状态更改为true。然后获取数据并将状态设置为 false。
第二,当滚动到页面末尾时,我再次将loading状态更改为true。用pageNo 添加1。然后再次获取数据并将loading 状态设置为false。
问题是:
-
loading状态以某种方式保持true。 - 更改
pageNo状态无效。pageNo始终保留为 1。 - 实际上没有一个州按预期工作。
我的目标:(顺序)
-
将
loading设置为true。 -
在组件初始化后从 API 获取 10 个帖子。
-
将
loading设置为false。 -
用户滚动页尾后,用
pageNo加1。 -
重复第 1 步到第 3 步,直到所有帖子都加载完毕。
-
从 API 集
allPostsLoaded到true获得空响应后。
我的尝试:
我尝试将所有状态添加到 useEffect 挂钩的依赖列表数组中。但随后发生了无限循环。
我也尝试只向数组添加 pageNo 和 loading 状态,但同样发生了无限循环。
来源:
import React, { lazy, useState } from 'react';
import { PostSection } from './Home.styles';
import { BlogPost } from '../../models/BlogPost';
import { PostService } from '../../services/PostService';
const defaultPosts: BlogPost[] = [{
Id: 'asdfg',
Content: 'Hi, this is demo content',
Title: 'Demo title',
sections: [],
subTitle: '',
ReadTime: 1,
CreatedDate: new Date()
}];
const defaultPageNo = 1;
const PostCardComponent = lazy(() => import('./../PostCard/PostCard'));
const postService = new PostService();
const Home = (props: any) => {
const [posts, setPosts]: [BlogPost[], (posts: BlogPost[]) => void] = useState(defaultPosts);
const [pageNo, setPageNo] = useState(defaultPageNo);
const [pageSize, setPageSize] = useState(10);
const [loading, setLoading] = useState(false);
const [allPostsLoaded, setAllPostsLoaded] = useState(false);
const [featuredPost, setFeaturedPost]: [BlogPost, (featuredPost: BlogPost) => void] = useState(defaultPosts[0]);
async function getPosts() {
return await postService.getPosts(pageSize, pageNo);
}
async function getFeaturedPost() {
return await postService.getFeaturedPost();
}
function handleScroll(event: any) {
console.log('loading ' + loading);
console.log('allPostsLoaded ' + allPostsLoaded);
var target = event.target.scrollingElement;
if (!loading && !allPostsLoaded && target.scrollTop + target.clientHeight === target.scrollHeight) {
setLoading(true);
setPageNo(pageNo => pageNo + 1);
setTimeout(()=>{
getPosts()
.then(response => {
const newPosts = response.data.data;
setLoading(false);
if (newPosts.length) {
const temp = [ ...posts ];
newPosts.forEach(post => !temp.map(m => m.Id).includes(post.Id) ? temp.push(post) : null);
setPosts(temp);
} else {
setAllPostsLoaded(true);
}
})
}, 1000);
}
}
function init() {
setLoading(true);
Promise.all([getFeaturedPost(), getPosts()])
.then(
responses => {
setLoading(false);
setFeaturedPost(responses[0].data.data);
setPosts(responses[1].data.data);
}
);
}
React.useEffect(() => {
window.addEventListener("scroll", handleScroll);
init();
return () => {
window.removeEventListener("scroll", handleScroll);
};
}, []
);
return (
<PostSection className="px-3 py-5 p-md-5">
<div className="container">
<div className="item mb-5">
{posts.map(post => (
<PostCardComponent
key={post.Id}
Title={post.Title}
intro={post.Content}
Id={post.Id}
ReadTime={post.ReadTime}
CreatedDate={post.CreatedDate}
/>
))}
</div>
</div>
</PostSection>
);
};
export default Home;
【问题讨论】:
-
UseEffect触发对其依赖项的更改,所以是的,如果您在useEffect块中更改pageNo,将pageNo添加到您的部门将导致无限循环,您这样做.与loading相同 -
我不确定这是否是您的全部问题,但我怀疑您需要将
handleScroll的定义移到useEffect块之外,因为一旦块落下,它可能会变得未定义超出范围。 -
@samuei,重点是我正在尝试更新
pageNo和loading属性。他们都没有被改变。pageNo始终保持为 1,loading始终保持为真。 -
请尝试将您的函数定义移到
useEffect块之外。 -
您在第一次渲染时为
useEffect创建回调,并且您的pageNo被烘焙到闭包中。因此它永远不会改变。但是 - 请原谅我的坦率 - 你的组件代码是相当复杂的混乱。你可能想清除它。古语有云:“看不清就做不好”。 (可能是孔子,公元 400 年)
标签: reactjs react-hooks react-typescript