在反应还原过程中处理读取错误的最佳方法是什么?

我有一个用于客户端的减速器,另一个用于 AppToolbar 和其他一些..。

现在假设我创建了一个提取操作来删除客户端,如果失败了,我在 Clients reduce 中有一些代码,这些代码应该可以完成一些工作,但是我也想在 AppToolbar 中显示一些全局错误。

但是 Clients 和 AppToolbar 减少器不共享状态的相同部分,因此无法在减少器中创建新操作。

那么我该如何显示全局错误呢? 谢谢

UPDATE 1:

我忘了说我使用的是 这里 devstack

更新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... 你只需要找到最适合你的代码。

90998 次浏览

如果您想要有“全局错误”的概念,您可以创建一个 errors减速器,它可以侦听 addError、 RemoveError 等。.行动。然后,您可以在 state.errors连接到您的 Redux 状态树,并在适当的地方显示它们。

有很多方法可以解决这个问题,但是总的想法是,全局错误/消息应该有自己的减少器,以完全独立于 <Clients />/<AppToolbar />。当然,如果这些组件中的任何一个需要访问 errors,您可以将 errors作为一个道具传递给它们。

更新: 代码示例

下面是一个例子,说明如果将“全局错误”errors传递到顶级 <App />并有条件地呈现它(如果存在错误) ,那么它可能是什么样子。使用 还原反应是 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);

对于动作创建者而言,它将根据响应分派(再来一次)成功失败

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

Erik 的回答 是正确的,但我想补充的是,您不必为添加错误而触发单独的操作。另一种方法是使用一个处理 任何带有 error字段的操作的减速器。这是个人选择和习俗的问题。

例如,来自具有错误处理的 返回的 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
}

我目前对于一些特定错误(用户输入验证)采用的方法是让我的子减少器抛出一个异常,在根减少器中捕获它,并将它附加到 action 对象。然后我有一个 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.

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).

您可以使用 Axios HTTP 客户端。它已经实现了拦截器特性。您可以在处理请求或响应之前拦截它们或捕获它们。

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

编写自定义中间件来处理所有与 api 相关的错误。

   failure/ error actin type ACTION_ERROR


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


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


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


}
}

我所做的就是集中所有的错误处理在每个效果的基础上

/**
* 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}`));
});