skip to Main Content

I’m running into an issue with setState where it is being called again while it is currently finishing up the previous setState batch.

I have an object that is structured like this
[{ id: 0, loading: false }]

Now, on the page I have a toggle button for different id’s and I want each toggle to show a loading overlay when it is being called. When I press the toggle button I am calling a function (shorted down for simplicity) that does the following:

const updateRequestAccess = (requestId, checked, user) => {
    updateUserAccessLoadingState(requestId, true); // Set loading to current id
    someApi.put(requestId, user, checked).then((response) => {
      if (response && !response.error) {
        updateUserAccessLoadingState(requestId, false); // Set loading to false
      } else {
        updateUserAccessLoadingState(requestId, false); // Set loading to false
      }
    });
  };

The function called before and after the Api call is:

  const updateUserAccessLoadingState = (id, loading) => {
    if (
      isUpdatingUserAccess.filter((el) => el.requestTypeId === id).length > 0
    ) {
      const newState = [...isUpdatingUserAccess];
      const indx = newState.findIndex((el) => el.requestTypeId === id);
      const selected = newState[indx];
      selected.loading = loading;
      setIsUpdatingUserAccess(newState);
    } else {
      setIsUpdatingUserAccess([
        ...isUpdatingUserAccess,
        { requestTypeId: id, loading },
      ]);
    }
  };

What this does it that it makes sure that there is never the same id twice in the state array and the loading boolean is only changed.

The problem currently is that I noticed when I try to toggle multiple buttons at once, which calls the updateRequestAccess many times, is that the first state modification does not finish running before the next one starts running right away. This results in some strange behaviour in the state.

How could this be done differently in order to circumvent this issue where the first set state is not finished before the next one starts running?

2

Answers


  1. Try to use

    setIsUpdatingUserAccess(oldState => [... oldState, { requestTypeId: id, loading }])

    Login or Signup to reply.
  2. when I try to toggle multiple buttons at once, which calls the updateRequestAccess many times, is that the first state modification does not finish running before the next one starts running right away.

    Not exactly, They both run, they both complete and they run in the correct order, but the second call does not make its changes based on the previous state (the one that was produced by the previous call) and so it basically overwrites the first call.

    And that’s why you should use an update function when you want to make changes based on the previous state.

    const updateUserAccessLoadingState = (requestTypeId, loading) => {
      setIsUpdatingUserAccess(prevState => {
        const newState = prevState.filter(elm => elm.requestTypeId !== requestTypeId);
        newState.push({ requestTypeId, loading });
        return newState;
      });
    };
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search