Правильний спосіб керування помилками в React-Redux


11

Я хочу зрозуміти, що є більш загальним або правильним способом обробки помилок з React-Redux.

Припустимо, у мене є компонент для реєстрації телефонних номерів.

Цей компонент видає помилку, якщо вхідний номер телефону недійсний

Що було б найкращим способом вирішити цю помилку?

Ідея 1: Створіть компонент, який приймає помилку і розсилає дію щоразу, коли помилка передається їй

ідея 2: Оскільки помилка пов'язана з цим компонентом, передайте цю помилку компоненту (який не підключений до redux, тобто компонент обробника помилок не відправить дію)

Запитання: Чи може хтось керувати мені правильним способом керування помилками в React-Redux для широкомасштабного додатка?


1
Як відбувається перевірка номера телефону, синхронна чи асинхронна, після того, як користувач щось зробить чи негайно? Що ви хочете, щоб сталося, видно користувачеві? Redux призначений для зберігання стану вашої програми, здається, трохи не пов’язаний із вашим запитанням.
RemcoGerlich

Відповіді:


3

Я б сказав, що жодна з ваших початкових ідей не охоплює всю картину. Ідея 1 - це лише зворотний дзвінок. Якщо ви хочете використовувати функцію зворотного виклику: useCallback. Ідея 2 працюватиме і є кращою, якщо вам не потрібно використовувати редукс. Іноді вам краще використовувати редукс. Можливо, ви встановлюєте дійсність форми, перевіряючи, що в жодному полі введення немає помилок чи чогось подібного. Оскільки ми йдемо про тему скорочення, припустимо, що це так.

Зазвичай найкращим підходом до поводження з помилками із скороченням є наявність поля помилки у стані, яке потім передається компоненту помилок.

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

Компонент помилки не повинен просто відображати помилку, він також може мати побічні ефекти useEffect.

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

1. Якщо перевірка справності є чистою функцією, це можна зробити в редукторі.

Потім ви встановите або скасуєте поле помилки у відповідь на дії щодо зміни номера телефону. У редукторі, побудованому із заявою перемикача, це може виглядати приблизно так.

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

Потім редуктор повинен скласти відповідне повідомлення про помилку та встановити його.

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

Два окреслені нами підходи не є взаємовиключними. Ви можете використовувати першу для відображення локально виявлених помилок, а також використовувати другу для відображення помилок на стороні сервера або мережі.


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

1

Я б використав 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>;
};

Виглядає цікаво anerco, Дякую за відповідь :)
anny123

1

Це залежить від того, про який тип помилок ви говорите. Якщо це лише форма перевірки форми, то я не думаю, що для цього вам потрібен 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

Я думаю про це так, якою має бути держава? І що має бути похідне від держави? Держава повинна зберігатися в редукції, а похідні слід обчислювати.

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

Я б використав Reselect для кешування виводів і повернення тих же результатів, коли відповідне стан не було змінено.

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

Потім ви можете використовувати селектор у mapStateToProps у всіх компонентах, які можуть піклуватися про це значення, і ви також можете використовувати його в асинхронних діях. Якщо фокус не змінився або значення поля не змінилося, перерахунок не відбудеться, він поверне замість цього попереднє значення.

Я додаю перевірку вибраного стану лише для того, щоб показати, як кілька фрагментів стану можуть зібратися разом, щоб привести до одного виведення.

Я особисто намагаюся підходити до речей, зберігаючи свій стан якомога меншим. Наприклад, скажімо, що ви хотіли створити свій власний календар. Чи будете ви зберігати кожен день у штаті, чи вам просто потрібно знати пару речей, таких як поточний рік та місяць, які зараз переглядаються. За допомогою цих двох фрагментів стану ви можете обчислити дні для відображення в календарі, і вам не потрібно перераховувати, поки один з них не зміниться, і цей перерахунок відбудеться практично автоматично, не потрібно думати про всі способи, які вони могли б зробити змінити.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.