Подтвердить что ты не робот

Каков наилучший способ справиться с ошибкой выборки в реакции редукции?

У меня есть один редуктор для клиентов, еще один для AppToolbar и некоторых других...

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

Но клиенты и адаптеры AppToolbar не разделяют одну и ту же часть состояния, и я не могу создать новое действие в редукторе.

Итак, как я могу представить глобальную ошибку? Благодаря

ОБНОВЛЕНИЕ 1:

Я забыл упомянуть, что использую este devstack

ОБНОВЛЕНИЕ 2: Я заметил, что Эрик ответил правильно, но я должен сказать, что решение, которое я использую в este, больше похоже на сочетание ответов Эрика и Дэна... Вам просто нужно найти то, что вам подходит лучше всего в вашем коде...

4b9b3361

Ответ 1

Если вы хотите иметь концепцию "глобальных ошибок", вы можете создать редуктор errors, который может прослушивать действия addError, removeError и т.д. Затем вы можете подключиться к дереву состояний Redux в state.errors и отображать их там, где это необходимо.

Существует несколько способов, с помощью которых вы могли бы приблизиться к этому, но общая идея состоит в том, что глобальные ошибки/сообщения заслуживают собственного редуктора, чтобы жить полностью отдельно от <Clients />/<AppToolbar />. Конечно, если любой из этих компонентов нуждается в доступе к errors, вы можете передать errors вниз к ним в качестве прокрутки там, где это необходимо.

Обновление: пример кода

Вот один пример того, как это могло бы выглядеть, если бы вы передали "глобальные ошибки" errors на ваш верхний уровень <App /> и условно визуализировали его (если есть ошибки). Используя react-redux connect, подключите ваш компонент <App /> к некоторым данным.

// App.js
// Display "global errors" when they are present
function App({errors}) {
  return (
    <div>
      {errors && 
        <UserErrors errors={errors} />
      }
      <AppToolbar />
      <Clients />
    </div>
  )
}

// Hook up App to be a container (react-redux)
export default connect(
  state => ({
    errors: state.errors,
  })
)(App);

И что касается создателя действия, он отправит (redux-thunk) неудачу успеха в соответствии с ответом

export function fetchSomeResources() {
  return dispatch => {
    // Async action is starting...
    dispatch({type: FETCH_RESOURCES});

    someHttpClient.get('/resources')

      // Async action succeeded...
      .then(res => {
        dispatch({type: FETCH_RESOURCES_SUCCESS, data: res.body});
      })

      // Async action failed...
      .catch(err => {
        // Dispatch specific "some resources failed" if needed...
        dispatch({type: FETCH_RESOURCES_FAIL});

        // Dispatch the generic "global errors" action
        // This is what makes its way into state.errors
        dispatch({type: ADD_ERROR, error: err});
      });
  };
}

В то время как ваш редуктор может просто управлять массивом ошибок, добавление/удаление записей соответствующим образом.

function errors(state = [], action) {
  switch (action.type) {

    case ADD_ERROR:
      return state.concat([action.error]);

    case REMOVE_ERROR:
      return state.filter((error, i) => i !== action.index);

    default:
      return state;
  }
}

Ответ 2

Ответ Eriks является правильным, но я хотел бы добавить, что вам не нужно запускать отдельные действия для добавления ошибок. Альтернативный подход состоит в том, чтобы иметь редуктор, который обрабатывает любое действие с полем error. Это вопрос личного выбора и соглашения.

Например, из Redux real-world пример, который имеет обработку ошибок:

// Updates error message to notify about the failed fetches.
function errorMessage(state = null, action) {
  const { type, error } = action

  if (type === ActionTypes.RESET_ERROR_MESSAGE) {
    return null
  } else if (error) {
    return action.error
  }

  return state
}

Ответ 3

Подход, который я использую в настоящее время для нескольких конкретных ошибок (проверка правильности ввода), заключается в том, чтобы мои вспомогательные редукторы генерировали исключение, улавливали его в моем корневом редукторе и привязывали его к объекту действия. Затем у меня есть сага о сокращении, которая проверяет объекты действия для ошибки и обновляет дерево состояний с данными об ошибках в этом случае.

Итак:

function rootReducer(state, action) {
  try {
    // sub-reducer(s)
    state = someOtherReducer(state,action);
  } catch (e) {
    action.error = e;
  }
  return state;
}

// and then in the saga, registered to take every action:
function *errorHandler(action) {
  if (action.error) {
     yield put(errorActionCreator(error));
  }
}

И затем добавление ошибки в дерево состояний, как описывает Эрик.

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

Ответ 4

Вы можете использовать HTTP-клиент axios. Он уже реализовал функцию Interceptors. Вы можете перехватывать запросы или ответы до того, как они будут обработаны тогда или поймать.

https://github.com/mzabriskie/axios#interceptors

// Add a request interceptor
axios.interceptors.request.use(function (config) {
    // Do something before request is sent
    return config;
  }, function (error) {
    // Do something with request error
    return Promise.reject(error);
  });

// Add a response interceptor
axios.interceptors.response.use(function (response) {
    // Do something with response data
    return response;
  }, function (error) {
    // Do something with response error
    return Promise.reject(error);
  });