I'm currently working on a ruby on rails + react app, fetching and rendering some records with axios and useEffect. It works fine as is, displays the data after fetching all.
How could I fetch/render individually or in controlled batches? Meaning I would like to fetch for example 1 by one or 5 at a time and render after each record/batch is available (so the list would be progressively growing from the user point of view). I'm not looking for either pagination nor infinite scroll.
The total of records varies and is unknown.
const [isLoading, setIsLoading] = useState(false)
useEffect(() => {
setIsLoading(true)
recordGateway.getRecords(recordId)
.then(res => setOtherRecords(res.data.other_records))
.catch(() => setHasError(true))
.finally(() => (setIsLoading(false)))
}, [])
getRecords = (recordId: number) =>
this.axios.get<{ other_records: OtherRecord[] }>(
`/api/v1/record_card/${recordId}/other_records`
)
I'm reading documentation about offset
and promises
but can't seem to understand it enough to apply it or maybe that's not at all what I should be looking for.
I would suggest, you use Promise.allSettled () alongside a state variable to hold the records in the array. You can batch your Axios API calls inside it. The promise will be resolved after all your API calls are complete.
When the user
scrolls
to theend
of thelist
, you canstart
abatch
request &expand
thestate array
with the batch result.
I'm outlining an example for you below. Adjust it according to your needs.
const [records, setRecords] = useState([]);
useEffect(() => {
// your other codes
// ...
// ...
Promise.allSettled([
recordGateway.getRecords(recordId),
recordGateway.getRecords(recordId),
recordGateway.getRecords(recordId),
// add more if you need
]).then(results => {
const fetchedRecords = results.map(r => r.value.data.other_records);
setRecords([...records, ...fetchedRecords])
})
// your other codes
//...
//...
}, [])
recordGateway.getRecords(recordId)
means that each is a record that will be fetched, meaning in your example, 4 would be fetched and later on 4 more? Or does it mean that's the full number of records that would be fetched? Because the aim is to eventually fetch all records (total unknown) just not having to wait for all to be fetched before starting the rendering state
variable. Pass the variable as the dependency to the useEffect
. When the user scrolls to a certain position, set the variable to true
& inside useEffect use an if
statement to run data fetching only when
the variable
is set to true
. After the fetching is complete, reset the variable to false
. This way you can go on with your data loading as long as you want to scroll. isLoading
variable, do it like this const [isLoading, setIsLoading] = useState(true)
. This way you can make sure to load data on the first render too! Promise.allSettled
. After the promise settles, you can update the state & do whatever you want to do. As for which records to fetch next, you can keep some time of flag that points to the last record id that was fetched. In next batch you start after that (wishing it helps you!)