Issue
I'm currently trying to fetch all of the properties for an object from an API, and display them in a table. The API will return up to 10 results at a time, and will return a value nextPageToken
in the response body if there are more results to be fetched. My goal is to fetch the first 10 results, immediately display them in the table, and add to the table as I continue to hit the API. This was my first attempt at a solution:
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);
};
(Note that the above is a simplification; in practice, there's more logic in getProperties that doesn't need to be repeated on subsequent calls to the API)
The problem that I'm running into with this solution is that when I'm calling loadMoreProperties, the setProperties call isn't yet finished. How can I enforce that the call to loadMoreProperties only happens after setting the previous set of properties? Is there an overall better pattern that I can follow to solve this problem?
Solution
You can use useEffect
to trigger the page loads as a reaction to a completed state change:
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]);
The first effect will cause an update to the state variable page
.
Only after the state change is completed, the second effect will be triggered and initiate the fetch of the second page.
In parallel, the third effect will perform the changes to the state variable properties
, that your table component depends on, after each successful page load and page state update, triggering a re-render after each update.
Answered By - Steffen Frank Answer Checked By - Marilyn (PHPFixing Volunteer)
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.