Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Correct way of error handling in React-Redux

Tags:

reactjs

redux

I want to understand what is more general or correct way of error handling with React-Redux.

Suppose, I have phone number sign up component.

That Component throws an error say if the input phone number is invalid

What would be a best way to handle that error?

Idea 1: Create a component, which takes an error and dispatches an action whenever an error is passed to it

idea 2: Since the error is related to that component, pass that error to a component (which isn't connected to redux i.e the error handler component won't dispatch the action)

Question: Can someone guide me on proper-way of error handling in React-Redux for large-scale app?

like image 891
anny123 Avatar asked Oct 07 '19 09:10

anny123


2 Answers

I would say that neither of your initial ideas capture the whole picture. Idea 1 is just a callback. If you want to use a callback: useCallback. Idea 2 will work and is preferable if you don't need to use redux. Sometimes you're better off using redux. Maybe you're setting form validity by checking none of the input fields have errors or something similar. Since we're on the topic of redux, let's assume that's the case.

Usually the best approach to error handling with redux is to have an error field in state that is then passed to an error component.

const ExampleErrorComponent= () => {
  const error = useSelector(selectError);
  if (!error) return null;
  return <div className="error-message">{error}</div>;
}

The error component doesn't have to just display an error, it could also do side effects with useEffect.

How the error is set/unset depends on your application. Let's use your phone number example.

1. If the validity check is a pure function, it can be done in the reducer.

You would then set or unset the error field in response to phone number change actions. In a reducer built with a switch statement it could look like this.

case 'PHONE_NUMBER_CHANGE':
  return {
    ...state,
    phoneNumber: action.phoneNumber,
    error: isValidPhoneNumber(action.phoneNumber) ? undefined : 'Invalid phone number',
  };

2. If errors are reported by the backend, dispatch error actions.

Let's say you're sending the phone number to a backend that does validation before it does something with the number. You can't know if the data is valid on the client side. You'll just have to take the server's word for it.

const handleSubmit = useCallback(
  () => sendPhoneNumber(phoneNumber)
    .then(response => dispatch({
      type: 'PHONE_NUMBER_SUBMISSION_SUCCESS',
      response,
    }))
    .catch(error => dispatch({
      type: 'PHONE_NUMBER_SUBMISSION_FAILURE',
      error,
    })),
  [dispatch, phoneNumber],
);

The reducer should then come up with an appropriate message for the error and set it.

Don't forget to unset the error. You can unset the error on a change action or when making another request depending on the application.

The two approaches I outlined are not mutually exclusive. You can use the first to display locally detectable errors and also use the second to display server side or network errors.

like image 86
Jemi Salo Avatar answered Sep 29 '22 13:09

Jemi Salo


I would use a formik with yup validation. then, for server-side error i would use something like this:

import React, { useEffect } from "react";
import { useDispatch, useSelector } from "react-redux";
import { Spinner } from "@blueprintjs/core";

export default ({ action, selector, component, errorComponent }) => {
  const dispatch = useDispatch();

  useEffect(() => {
    dispatch(action());
  }, [dispatch, action]);

  const DispatchFetch = () => {
    const { data, isRequesting, error } = useSelector(selector());
    if (!isRequesting && data) {
      const Comp = component;
      return <Comp data={data}></Comp>;
    } else if (error) {
      if (errorComponent) {
        const ErrorComp = errorComponent;
        return <ErrorComp error={error}></ErrorComp>;
      }
      return <div>{error}</div>;
    }
    return <Spinner></Spinner>;
  };

  return <DispatchFetch></DispatchFetch>;
};
like image 29
anerco Avatar answered Sep 29 '22 14:09

anerco