'Is there a best practice for managing isLoading state?

I'm sorry for my English skills in advance.

Let's say I want to fetch data from server and render it on page load...the logic is something like this:

  1. Page is loading and Preloader is shown (at this moment I send get request).
  2. Data is fetched and sent to State.
  3. Preloader disappears and data from state is rendered on a page.

My initial state looks like this:

const state = {
        data: [],
        isLoading: false
      }

I'm doing following (the code is about logic):

  function fetchData() {
    try {
      fetch(URL)
      dispatch({...state, isLoading: true})

          setTimeout(() => {
            dispatch({...state, data: data.payload, isLoading: false})
          }, 500);
        } catch (err) {
          dispatch({...state, isLoading: false})
        }
      }

Is that correct logic? I'm not sure if this is the best practice....maybe I should do it this way:

  function fetchData() {
    try {
      fetch(URL)
      dispatch({...state, isLoading: true})

      setTimeout(() => {
        dispatch({...state, data: data.payload})
      }, 500);
    } catch (err) {
      dispatch({...state, isLoading: false})
    } finally {
      dispatch({...state, isLoading: false})
    }
}

So what is the best way to change isLoading state?

The third option which I'm thinking about is to create a separate state isLoading...I mean I will have to states:

  const state = {
    data: [],
  }

  const isLoadingState = {
    isLoading: false,
  }


Solution 1:[1]

You should set isLoading: true right before fetching.

The finally-block will always execute after the try-block and catch-block(s) have finished executing. It always executes, regardless of whether an exception was thrown or caught.

So it depends on logic of your application, but it would be completely ok to avoid isLoading: false in try and catch blocks, and set it false just in the finally block.

 async function fetchData() {
    try {
      dispatch({...state, isLoading: true})
      const data = await fetch(URL)  

      dispatch({...state, data: data.payload})
    } catch (err) {
      console.error(err);
    } finally {
      dispatch({...state, isLoading: false})
    }

Solution 2:[2]

It would be good to have your loading indicator update in your finally block:

function fetchData() {
    try {
      dispatch({...state, isLoading: true})
      fetch(URL)
      dispatch({...state})

      setTimeout(() => {
        dispatch({...state, data: data.payload})
      }, 500);
    } finally {
      dispatch({...state, isLoading: false})
    }
}

It's always going to finally block when your request is finished, so you don't need to repeatedly set it in your success or catch block.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 marc_s
Solution 2 marc_s