vct12345
vct12345

Reputation: 1

Best way to structure 'useEffect' for data fetching with pagination in React? (specific use-case)

I am going to avoid copy pasting a lot of code, but I will explain what is going on:

Now, without going too deep into if and how I should modify this structure, let's talk about how to best manage this on the front-end application:

I have these following states:

  1. filter
  2. order of sorting
  3. mark

Changing the state of the first two will cause a new fetch from the server AND RESET THE MARK.

Clicking 'load more elements' will trigger a fetch from the server with the existing defined filter and order. Both use the same endpoint and server-side code, and it works. But the old mark value needs to remain the same for the current [filter, order].

Now, the questing is: how to best structure the front-end React code for fetching this? Right now, my code looks something like this:


const genericGetData = async (ok, fail, canceled, mark?) => {
    getDataFromServer(filter, order, mark).then(result => { /*...*/ }); // you get the idea
}

useEffect(() => {
    let canceled = false;
    genericGetData(() => { /*...*/ }, () => { /*...*/ }, () => canceled);
    return () => {
        canceled = true;
    } 
}, [filter, order]);

useEffect(() => {
    let canceled = false;
    genericGetData(() => { /*...*/ }, () => { /*...*/ }, () => canceled, mark);
    return () => {
        canceled = true;
    } 
}, [triggerLoadMore]);

...

<button onClick={() => setTriggerLoadMore(!triggerLoadMore)} /> // load more button, somewhere

Now, from what I learned 'useEffects' should be used at least as possible. Also, I know react-query or some other libraries / ways of doing this exist, but for now I just want to make it work like this.

Is there a better way of handling this scenario?

QUESTIONS AND CONCERNS:

Is it a bad that I have defined a generic wrapper for retrieving the data from server? I had to do this because I need to update different type of states (mainly loading animation but others too) depending of what type of request is this (retrieve with new filter, order or load more). I use the fail, canceled parameters (passed as functions) to perform specific actions at the end of the request or when an error occurs.

Another reason I made it this way is because - if let's say I get rid of the second useEffect and just wrap all that in a regular function and just pass it inside onClick={...}, I can't properly handle the clean-up scenario (when [filter, order] might update before the load more action is finished, which would lead to data retrieved from server being rendered inconsistently).

What I also tried to do is: get rid of the second useEffect and pass triggeredLoadMore as a dependency in the first useEffect. Well there's a specific problem here which would be resetting the mark in case it's only filter or order being changed, or keeping the same mark if it's just load more. I tried to add a new useEffect for that:

useEffect(() => {
    setMark(undefined);
}, [filter, order]);

So that I can reset the mark if it's an action of this type. Well, I didn't get any good results, and this was only for the mark reset, but would also have to do it for certain other changes (loading animations, etc.). Also the issue with this is overcomplicating the useEffect chain.'

After you read the introduction and understand how the code works - I want you to share your opinion about my questions and concerns - and tell me if this is good enough or I should still change some things.

Upvotes: -4

Views: 27

Answers (0)

Related Questions