简体   繁体   English

处理 react redux 中的获取错误的最佳方法是什么?

[英]What is the best way to deal with a fetch error in react redux?

I have one reducer for Clients, one other for AppToolbar and some others...我有一个用于客户端的减速器,另一个用于 AppToolbar 和其他一些......

Now lets say that I created a fetch action to delete client, and if it fails I have code in the Clients reducer which should do some stuff, but also I want to display some global error in AppToolbar.现在假设我创建了一个获取操作来删除客户端,如果它失败了,我在 Clients reducer 中有代码应该做一些事情,但我也想在 AppToolbar 中显示一些全局错误。

But the Clients and the AppToolbar reducers do not share the same part of the state and I cannot create a new action in the reducer.但是客户端和 AppToolbar reducers 不共享相同的状态部分,我无法在 reducer 中创建新的操作。

So how am I suppose to show global error?那么我应该如何显示全局错误呢? Thanks谢谢

UPDATE 1:更新 1:

I forget to mention that I use este devstack我忘了说我用的是este devstack

UPDATE 2: I marked Eric's answer as correct, but I have to say that solution which I am using in este is more like combination of Eric and Dan's answer... You just have to find what fits you the best in your code...更新 2:我将埃里克的答案标记为正确,但我不得不说我在埃斯特使用的解决方案更像是埃里克和丹的答案的组合......你只需要在你的代码中找到最适合你的东西...... .

If you want to have the concept of "global errors", you can create an errors reducer, which can listen for addError, removeError, etc... actions.如果你想拥有“全局错误”的概念,你可以创建一个errors reducer,它可以监听 addError、removeError 等操作。 Then, you can hook into your Redux state tree at state.errors and display them wherever appropriate.然后,您可以在state.errors挂钩到您的 Redux 状态树,并在适当的地方显示它们。

There are a number of ways you could approach this, but the general idea is that global errors/messages would merit their own reducer to live completely separate from <Clients /> / <AppToolbar /> .有很多方法可以解决这个问题,但一般的想法是全局错误/消息应该有自己的 reducer 以完全独立于<Clients /> / <AppToolbar /> Of course if either of these components needs access to errors you could pass errors down to them as a prop wherever needed.当然,如果这些组件中的任何一个需要访问errors ,您可以在需要时将errors作为 prop 传递给它们。

Update: Code Example更新:代码示例

Here is one example of what it might look like if you were to pass the "global errors" errors into your top level <App /> and conditionally render it (if there are errors present).这是一个示例,说明如果将“全局错误” errors传递到顶级<App />并有条件地呈现它(如果存在错误),它可能会是什么样子。 Using react-redux's connect to hook up your <App /> component to some data.使用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);

And as far as the action creator is concerned, it would dispatch ( redux-thunk ) success failure according to the response就 action creator 而言,它会根据响应分派 ( redux-thunk ) success failure

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});
      });
  };
}

While your reducer could simply manage an array of errors, adding/removing entries appropriately.虽然您的减速器可以简单地管理一系列错误,适当地添加/删除条目。

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;
  }
}

Erik's answer is correct but I would like to add that you don't have to fire separate actions for adding errors. Erik 的回答是正确的,但我想补充一点,您不必为添加错误而触发单独的操作。 An alternative approach is to have a reducer that handles any action with an error field .另一种方法是使用一个 reducer 来处理带有error字段的任何操作 This is a matter of personal choice and convention.这是个人选择和惯例的问题。

For example, from Redux real-world example that has error handling:例如,来自具有错误处理的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 error
  }

  return state
}

The approach I'm currently taking for a few specific errors (user input validation) is to have my sub-reducers throw an exception, catch it in my root reducer, and attach it to the action object.我目前针对一些特定错误(用户输入验证)采用的方法是让我的子化简器抛出异常,在我的根化简器中捕获它,并将其附加到操作对象。 Then I have a redux-saga that inspects action objects for an error and update the state tree with error data in that case.然后我有一个 redux-saga,它检查动作对象是否有错误,并在这种情况下用错误数据更新状态树。

So:所以:

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));
  }
}

And then adding the error to the state tree is as Erik describes.然后按照 Erik 的描述将错误添加到状态树。

I use it pretty sparingly, but it keeps me from having to duplicate logic which legitimately belongs in the reducer (so it can protect itself from an invalid state).我很少使用它,但它使我不必复制合法属于 reducer 的逻辑(因此它可以保护自己免受无效状态的影响)。

write custom Middleware to handle all the api related error.编写自定义中间件来处理所有与 api 相关的错误。 In this case your code will be more cleaner.在这种情况下,您的代码会更简洁。

   failure/ error actin type ACTION_ERROR

   export default  (state) => (next) => (action) => {

      if(ACTION_ERROR.contains('_ERROR')){

       // fire error action
        store.dispatch(serviceError());

       }
}

what I do is I centralize all error handling in the effect on a per effect basis我所做的是在每个效果的基础上集中处理效果中的所有错误

/**
 * central error handling
 */
@Effect({dispatch: false})
httpErrors$: Observable<any> = this.actions$
    .ofType(
        EHitCountsActions.HitCountsError
    ).map(payload => payload)
    .switchMap(error => {
        return of(confirm(`There was an error accessing the server: ${error}`));
    });

You can use axios HTTP client.您可以使用 axios HTTP 客户端。 It already has implemented Interceptors feature.它已经实现了拦截器功能。 You can intercept requests or responses before they are handled by then or catch.您可以在请求或响应被 then 或 catch 处理之前拦截它们。

https://github.com/mzabriskie/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); });

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM