Правильный способ обработки ошибок в React-Redux - PullRequest
8 голосов
/ 07 октября 2019

Я хочу понять, что является более общим или правильным способом обработки ошибок с помощью React-Redux.

Предположим, у меня есть компонент для регистрации номера телефона.

Этот компонент выдает ошибку, например, если введенный номер телефона неверен

Что было бы лучшим способом справиться с этимошибка?

Идея 1: Создание компонента, который принимает ошибку и отправляет действие всякий раз, когда ему передается ошибка

идея 2: Так какошибка связана с этим компонентом, передайте эту ошибку компоненту (который не связан с redux, то есть компонент обработчика ошибок не будет отправлять действие)

Вопрос: Может кто-топодскажите, как правильно обрабатывать ошибки в React-Redux для крупномасштабного приложения?

Ответы [ 4 ]

2 голосов
/ 09 октября 2019

Я бы сказал, что ни одна из ваших первоначальных идей не отражает всю картину. Идея 1 это просто обратный звонок. Если вы хотите использовать обратный вызов: useCallback. Идея 2 будет работать и предпочтительнее, если вам не нужно использовать излишек. Иногда вам лучше использовать редукс. Возможно, вы устанавливаете валидность формы, проверяя, что ни в одном из полей ввода нет ошибок или чего-то подобного. Поскольку мы находимся на теме избыточности, давайте предположим, что это так.

Обычно лучший подход к обработке ошибок с использованием избыточности - это иметь поле ошибки в состоянии, которое затем передается компоненту ошибки.

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

Компонент ошибки не должен просто отображать ошибку, он также может вызывать побочные эффекты при useEffect.

Способ установки / сброса ошибки зависит от вашего приложения. Давайте использовать ваш пример номера телефона.

1. Если проверка достоверности является чистой функцией, ее можно выполнить в редукторе.

Затем вы должны установить или сбросить поле ошибки в ответ на действия по изменению номера телефона. В редукторе, построенном с оператором switch, это может выглядеть так:

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

2. Если бэкэнд сообщает об ошибках, отправьте действия с ошибками.

Допустим, вы отправляете номер телефона бэкенду, который выполняет проверку перед тем, как что-то сделать с номером. Вы не можете знать, действительны ли данные на стороне клиента. Вам просто нужно поверить слову сервера.

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],
);

Затем редуктор должен выдать соответствующее сообщение об ошибке и установить его.

Не забудьтесбросить ошибкуВы можете сбросить ошибку в действии изменения или при выполнении другого запроса в зависимости от приложения.

Два описанных мною подхода не являются взаимоисключающими. Первое можно использовать для отображения локально обнаруживаемых ошибок, а также второе для отображения ошибок на стороне сервера или сети.

1 голос
/ 15 октября 2019

Я думаю об этом, что должно быть состояние? А что следует выводить из состояния? Состояние должно быть сохранено в избыточности, а деривации должны быть рассчитаны.

Номер телефона - это состояние, в каком поле находится фокус, это состояние, но независимо от того, действительно ли оно действительно, которое можно получить из значений в состоянии.

Я бы использовал Reselect для кэширования дериваций и возврата тех же результатов, когда соответствующее состояние не было изменено.

export const showInvalidPhoneNumberMessage = createSelector(
  getPhoneValue,
  getFocusedField,
  (val, focus) => focus !== 'phone' && val.length < 10 // add other validations.
)

Затем можно использовать селектор в mapStateToProps во всех компонентах, которые могут иметь значениеоб этом значении, и вы можете использовать его в асинхронных действиях. Если фокус не изменился или значение поля не изменилось, то пересчет не произойдет, вместо этого будет возвращено предыдущее значение.

Я добавляю выбранную проверку состояния только дляпокажите, как несколько частей состояния могут объединиться, чтобы привести к одной деривации.

Я лично стараюсь приблизиться к вещам, сохраняя свое состояние как можно меньшим. Например, допустим, вы хотите создать свой собственный календарь. Будете ли вы хранить каждый день в состоянии, или вам просто нужно знать пару вещей, таких как текущий год и месяц, который просматривается в данный момент. Имея только эти 2 элемента состояния, вы можете рассчитать дни, отображаемые в календаре, и вам не нужно пересчитывать, пока один из них не изменится, и этот пересчет произойдет практически автоматически, не нужно думать обо всех способах, которыми они могли быизменить.

1 голос
/ 11 октября 2019

Это зависит от того, о какой обработке ошибок вы говорите. Если это только обработка проверки формы, тогда я не думаю, что вам нужен Redux для этого - пожалуйста, прочитайте эту статью . Если ваша ошибка будет «поглощена» только этим компонентом, зачем отправлять ее в redux? Для этого вы можете легко использовать свое локальное состояние.

С другой стороны, если вы хотите показывать пользователю какое-то сообщение об ошибке, указывающее, не произошел ли какой-либо HTTP-вызов на сайте, вы могли бы воспользоваться избыточностью, отправив сообщение об ошибке. из всех частей вашего приложения (или даже в целом вашего промежуточного программного обеспечения)

dispatch({ type: 'SET_ERROR_MESSAGE', error: yourErrorOrMessage });

// simple error message reducer
function errorMessage(state = null, action) {
  const { type, error } = action;

  switch (type) {
      case 'RESET_ERROR_MESSAGE':
          return null;
      case 'SET_ERROR_MESSAGE':
          return error;
  }

  return state
}

Вам необходимо определить, как будет организовано ваше состояние и нужно ли переводить какое-либо состояние в избыточное или просто сохранять его в локальномсостояние вашего компонента. Вы могли бы поместить все в избыточность, но лично я бы сказал, что это излишнее - зачем вам помещать состояние X в компонент Y, если только компонент Y заботится об этом состоянии? Если вы правильно структурируете свой код, у вас не должно возникнуть проблем с перемещением этого состояния из локального в избыточное в дальнейшем, если по какой-то причине другие части вашего приложения начнут зависеть от этого состояния.

1 голос
/ 10 октября 2019

Я бы использовал formik с проверкой yup. тогда для ошибки на стороне сервера я бы использовал что-то вроде этого:

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>;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...