Search code examples
reactjsreduxecmascript-6react-hooks

Lessen Duplication of Dispatching in React/Redux


I have a action called saveThing. In it, I have parameters, thingNoErrors and thingWithErrors . I have an if statement that if thingNoErrors has a value, then you only call the API. My problem is I don't want to repeat the dispatch of constants.SUCCESSFUL and the callback just to lessen the code and avoid repetition. Is there a way to better way to revise it?

export const saveThing =
  ({ thingNoErrors = [], thingWithErrors = [], callback = () => {} }) =>
  async (dispatch) => {
    try {
      dispatch({
        type: constants.REQUESTING,
      });

      if (thingNoErrors?.length > 0) {
        let formData = new FormData();

        Object.keys(thingNoErrors).forEach((fieldName) => {
          formData.append(
            thingNoErrors[fieldName]?.name,
            thingNoErrors[fieldName]?.file
          );
        });

        const response = await axios.post(`${API_URL}/sample/api`, formData);

        dispatch({
          type: constants.SUCCESSFUL,
          payload: {
            data: [...response.data, ...thingWithErrors],
          },
        });

        callback('success')
      }

      dispatch({
        type: constants.SUCCESSFUL,
        payload: {
          data: thingWithErrors,
        },
      });

      callback('success')
    } catch (error) {
      dispatch({
        type: constants.ERROR,
      });
    }
  };

Solution

  • You could factor out/declare the "response" variable to be outside the if-conditional block, and shallow merge it into the data array to allow for the single successful action dispatch.

    export const saveThing = ({
      thingNoErrors = [],
      thingWithErrors = [],
      callback = () => {},
    }) => async (dispatch) => {
      try {
        dispatch({ type: constants.REQUESTING });
    
        let response;
    
        if (thingNoErrors?.length) {
          let formData = new FormData();
    
          Object.keys(thingNoErrors).forEach((fieldName) => {
            formData.append(
              thingNoErrors[fieldName]?.name,
              thingNoErrors[fieldName]?.file
            );
          });
    
          response = await axios.post(`${API_URL}/sample/api`, formData);
        }
    
        dispatch({
          type: constants.SUCCESSFUL,
          payload: {
            data: [...(response?.data || []), ...thingWithErrors],
          },
        });
    
        callback('success');
      } catch (error) {
        dispatch({ type: constants.ERROR });
      }
    };