Каков наилучший способ справиться с ошибкой выборки в react redux?
У меня есть один редуктор для клиентов, один другой для AppToolbar и некоторые другие...
теперь давайте скажем, что я создал действие выборки для удаления клиента, и если это не удается, у меня есть код в редукторе клиентов, который должен делать некоторые вещи, но также я хочу отобразить некоторую глобальную ошибку в AppToolbar.
но клиенты и редукторы AppToolbar не разделяют одну и ту же часть состояния, и я не могу создать новое действие в редукторе.
Так как я предполагаю показать глобальную ошибку? Спасибо
обновление 1:
Я забыл упомянуть, что я использую Эстэ devstack
обновление 2: Я отметил ответ Эрика как правильный, но я должен сказать, что решение, которое я использую в este, больше похоже на комбинацию ответа Эрика и Дэна... Вы просто должны найти то, что подходит вам лучше всего в вашем коде...
6 ответов:
если вы хотите иметь понятие "глобальные ошибки", вы можете создать
errors
редуктор, который может слушать для addError, removeError, etc... действия. Затем вы можете подключиться к дереву состояний Redux по адресуstate.errors
и отображать их там, где это необходимо.есть несколько способов, которыми вы могли бы подойти к этому, но общая идея заключается в том, что глобальные ошибки/сообщения заслуживают того, чтобы их собственный редуктор жил полностью отдельно от
<Clients />
/<AppToolbar />
. Конечно, если любой из них компонентам необходим доступ кerrors
вы могли бы пройтиerrors
им в качестве опоры, где требуется.Обновление: Пример Кода
вот один пример того, как это может выглядеть, если вы должны были передать "глобальные ошибки"
errors
на ваш верхний уровень<App />
и условно визуализировать его (если есть ошибки). Используя реагировать-возвращение подключить<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; } }
Эрика!--5--> правильно, но я хотел бы добавить, что вам не нужно запускать отдельные действия для добавления ошибок. Альтернативный подход - иметь редуктор, который обрабатывает любое действие с
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 action.error } return state }
подход, который я сейчас использую для нескольких конкретных ошибок (проверка ввода пользователем), заключается в том, чтобы мои субредукторы выбрасывали исключение, ловили его в моем корневом редукторе и прикрепляли его к объекту действия. Затем у меня есть redux-saga, который проверяет объекты действия на наличие ошибки и обновляет дерево состояний с данными об ошибках в этом случае.
Так:
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)); } }
а затем добавить ошибку в дерево состояний, как описывает Эрик.
Я использую его довольно редко, но это удерживает меня от необходимости дублировать логику, которая законно принадлежит редуктору (чтобы он мог защитить себя от недопустимого состояния).
напишите пользовательское промежуточное программное обеспечение для обработки всех ошибок, связанных с 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}`)); });
можно использовать HTTP-клиент axios. Он уже реализовал функцию перехватчиков. Вы можете перехватывать запросы или ответы до того, как они будут обработаны then или catch.
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); });