DEV Community

Discussion on: React race condition bug

 
tbroyer profile image
Thomas Broyer

Hmm, did you try it? codesandbox.io/s/new-e6gpr

Here's the diff:

  useEffect(() => {
-   if (pets.selectedPet) {
+   let selectedPet = pets.selectedPet;
+   if (selectedPet) {
      dispatch({ type: "FETCH_PET" });
-     getPet(pets.selectedPet).then(data => {
-       dispatch({ type: "FETCH_PET_SUCCESS", payload: data });
+     getPet(selectedPet).then(data => {
+       dispatch({ type: "FETCH_PET_SUCCESS", payload: data, selectedPet });
      });
    } else {
      dispatch({ type: "RESET" });
    }
  }, [pets.selectedPet])

and

    case "FETCH_PET_SUCCESS": {
+     if (state.selectedPet != action.selectedPet) {
+       // out-of-order event, ignore.
+       return state;
+     }
      return {
        ...state,
        loading: false,
        petData: action.payload
      };
    }
Thread Thread
 
sag1v profile image
Sagiv ben giat

Aw you kept the onChange handler. I thought you meant to omit it and instead "listen" to the "FETCH_PET_SUCCESS" in order to update the drop-down.

Thread Thread
 
tbroyer profile image
Thomas Broyer

Fwiw, to me, this feels cleaner than somehow duplicating the selectedPet state into a useRef.

Also, while the local selectedPet variable I used is not actually needed, I feel it reads better, but YMMV, using pets.selectedPet everywhere would work just as well. First diff would be reduced to:

  useEffect(() => {
    if (pets.selectedPet) {
      dispatch({ type: "FETCH_PET" });
      getPet(pets.selectedPet).then(data => {
-       dispatch({ type: "FETCH_PET_SUCCESS", payload: data });
+       dispatch({ type: "FETCH_PET_SUCCESS", payload: data, selectedPet: pets.selectedPet });
      });
    } else {
      dispatch({ type: "RESET" });
    }
  }, [pets.selectedPet])