我目前正试图从API中获取对象的所有属性,并将它们显示在表中。API一次将返回最多10个结果,如果有更多的结果要获取,将在响应体中返回一个值nextPageToken
。我的目标是获取前10个结果,立即将它们显示在表中,并在继续访问API时添加到表中。这是我第一次尝试解决方案:
const getProperties = async (id) => {
const properties = await Api.getProperties(id);
setProperties(properties.properties);
if (properties.nextPageToken) loadMoreProperties(id, nextPageToken);
};
const loadMoreProperties = async (id, nextPageToken) => {
const properties = await Api.getProperties(id, nextPageToken);
setProperties(prevProperties => {return [...prevProperties, properties.properties]});
if (properties.nextPageToken) loadMoreProperties(id, properties.nextPageToken);
};
(注意,以上是一个简化;在实践中,getProperties中有更多的逻辑,不需要在后续对API的调用中重复)
我遇到这个解决方案的问题是,当我调用loadMoreProperties, setProperties调用尚未完成。我怎么能强制调用loadMoreProperties只发生设置前一组属性后?是否有一个整体上更好的模式,我可以遵循来解决这个问题?
您可以使用useEffect
来触发页面加载,作为完成状态更改的响应:
const [page, setPage] = useState(); // will be {properties, nextPageToken}
// load first page whenever the id changes
useEffect(() => {
Api.getProperties(id)
.then(page => setPage(page)));
}, [id]);
// load next page (if there is one) - but only after the state changes were processed
useEffect(() => {
if (page?.nextPageToken == null) return;
Api.getProperties(id, page.nextPageToken)
.then(page => setPage(page)));
}, [id, page]
);
// this will trigger the re-render with every newly loaded page
useEffect(()=> setProperties(prev => [...(prev || []), page.properties]), [page]);
第一个效果将导致状态变量page
的更新。
只有状态改变完成后,才会触发第二个效果,并启动第二个页面的抓取。
与此同时,第三种效果将在每次成功加载页面和更新页面状态后对表组件所依赖的状态变量properties
执行更改,并在每次更新后触发重新呈现。我认为你应该传递一个回调参数给你的setProperties"方法,以便在值更新后进行第二次调用,如下所示:
setProperties(properties.properties, () => {
if (properties.nextPageToken)
loadMoreProperties(id, nextPageToken);
);
希望能有所帮助
我的解决方案包括删除loadMoreProperties
方法本身。当第一次调用getProperties
时,可以省略nextPageToken
参数。
getProperties = async(id,nextPageToken) {
var result = await Api.getProperties(id,nextPageToken);
this.setState((state)=>(state.properties.concat(result.properties)), ()=>{
// setState callback
if(result.nextPageToken) {
this.getProperties(id, nextPageToken);
}
});
}