React redux에서 가져 오기 오류를 처리하는 가장 좋은 방법은 무엇입니까?


105

클라이언트 용 감속기가 하나 있고 AppToolbar 용 감속기가 하나 있고 다른 감속기가 있습니다.

이제 클라이언트를 삭제하기위한 가져 오기 작업을 생성했다고 가정 해 보겠습니다. 실패하면 Clients reducer에 몇 가지 작업을 수행해야하는 코드가 있지만 AppToolbar에 일부 전역 오류를 표시하고 싶습니다.

그러나 Clients와 AppToolbar 감속기는 상태의 동일한 부분을 공유하지 않으며 감속기에서 새 작업을 만들 수 없습니다.

그렇다면 전역 오류를 어떻게 표시한다고 가정합니까? 감사

업데이트 1 :

este devstack을 사용한다는 것을 언급하는 것을 잊었습니다.

업데이트 2 : 나는 Eric의 대답을 올바른 것으로 표시했지만 este에서 사용하는 솔루션은 Eric과 Dan의 대답의 조합과 비슷하다고 말해야합니다 ... 코드에서 가장 적합한 것을 찾아야합니다 .. .


2
당신은 가까운 투표를 받고 있으며 아마도 많은 예제 코드를 제공하지 않았기 때문일 것입니다. 귀하의 질문과 귀하가받는 답변은 문제가 더 명확하게 설명되면 다른 사람들에게 더 도움이 될 것입니다.
— acjay

이 질문이 맥락에서 부족하다는 @acjay와 동의해야합니다. 일반적인 솔루션으로 (코드 예제와 함께) 아래에 대답했지만 귀하의 질문에는 약간의 수정이 필요할 수 있습니다. 몇 가지 별도의 문제가있는 것 같습니다. 1) 비동기 작업 / 오류 처리. 2) redux 상태 트리에서 상태를 적절하게 분할합니다. 3) 구성 요소가 필요한 데이터를 가져옵니다.
— Erik Aybar

@ErikTheDeveloper 감사합니다. 귀하의 답변은 훌륭해 보입니다. 그러나 당신이 옳습니다. 나는 문맥을 언급하는 것을 잊었습니다. 내 질문을 편집, 난 에스테 devstack을 사용하고 당신의 대답이 적용되지 않는 것 같습니다 거기는 그대로 ...
— 두산 Plavak

답변:


116

"전역 오류"라는 개념을 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;
  }
}

1
Erik, 나는 당신이 여기에서 제안한 것과 비슷한 것을 가지고 있지만 놀랍게도 나는 내 코드에서 사용하는 catchif someHttpClient.get('/resources')또는 fetch('/resources')내가 사용하는 함수 를 결코 얻지 못했습니다 500 Server Error. 내가 실수 할 수있는 생각이 머릿속에서 떠오르나요? 기본적으로 내가하는 일은 내 모델에서 텍스트를 추가하거나 DB에서 텍스트를 제거하는 것과 같은 매우 간단한 작업을 수행 하는 메서드를 호출 fetch하는 요청을 보내는 것입니다. routesmongoose
— Kevin Ghaboosi

2
안녕하세요, 저는 Google 검색을 통해 여기에 왔습니다. 훌륭한 예를 들어 주셔서 감사합니다. 같은 문제로 어려움을 겪고 있습니다. 이것은 훌륭합니다. 물론 해결책은 오류를 매장에 통합하는 것입니다. 내가 왜 그 ... 환호 생각하지 않았다
— 스팍

2
오류가 발생하면 함수를 어떻게 실행합니까? 예를 들어 I UI에서 건배 / 경고를 표시해야합니다, 부모 구성 요소의 소품 업데이트하여 경고 구성 요소를 렌더링하지
— 프랑코 P.을

111

Erik의 대답 은 정확하지만 오류를 추가하기 위해 별도의 작업을 수행 할 필요가 없다는 점을 추가하고 싶습니다. 다른 방법은 필드 와 함께 모든 작업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 error
  }

  return state
}

모든 성공 요청에서 RESET_ERROR_MESSAGE 유형을 errorMessage 감속기에 전달해야 함을 의미합니까?
— Dimi Mikadze

2
@DimitriMikadze 아니에요. 이 함수는 오류 상태에 대한 감소 기입니다. RESET_ERROR_MESSAGE를 전달하면 모든 오류 메시지가 지워집니다. 당신이 통과하지 않고 오류 필드가없는 경우 이전 작업에서 일부 오류가, 그들은 여전히 성공 조치 후있을 것이 있다면, 그냥 .... 너무 변경되지 않은 상태로 반환
— 두산 Plavak

소비자가 error작업 페이로드 에을 첨부 할 때보다 자연스러운 인라인 응답을 허용하기 때문에이 방법을 선호합니다 . 고마워 댄!
— Mike Perrenoud

1
나는 이것이 어떻게 작동하는지에 대해 내 머리를 잘 이해할 수 없습니다. 실제 사례를 제외하고이를 설명하는 격리 된 문서 / 비디오가 있습니까? 대부분의 프로젝트에서 매우 핵심적인 요구 사항이며 주제에 대한 문서를 이해하기가 쉽지 않습니다. 감사.
— Matt Saunders

6
@MattSaunders 그것을 이해하려고 노력하는 동안 Dan 자신 (실제로 Redux를 만든 응답자)이 Redux 과정을 보았습니다. 이 답변과 실제 예제와 함께 오류 메시지 표시 섹션 이 있습니다. 나를. 행운을 빕니다.
— Agustín Lado

2

현재 몇 가지 특정 오류 (사용자 입력 유효성 검사)에 대해 취하고있는 접근 방식은 내 하위 감소 기가 예외를 발생시키고 루트 감속기에서이를 포착하여 작업 객체에 연결하도록하는 것입니다. 그런 다음 오류에 대한 작업 개체를 검사하고이 경우 오류 데이터로 상태 트리를 업데이트하는 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));
  }
}

그리고 상태 트리에 오류를 추가하는 것은 Erik이 설명하는 것과 같습니다.

나는 그것을 매우 드물게 사용하지만 합법적으로 감속기에 속하는 논리를 복제하지 않아도됩니다 (잘못된 상태로부터 스스로를 보호 할 수 있습니다).


1

모든 API 관련 오류를 처리하기 위해 사용자 정의 미들웨어를 작성하십시오. 이 경우 코드가 더 깔끔해집니다.

   failure/ error actin type ACTION_ERROR

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

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

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

       }
}

1
또한 IMHO 디버깅을 더 어렵게 만듭니다
— chrisjlee

2
당신은이 미들웨어가 필요하지 않습니다, 당신은 동일한 쓸 수 if감속기에
— 후안 CAMPA

50 개 이상의 API가있는 경우 모든 곳에 작성해야합니다. 대신 사용자 지정 미들웨어를 작성하여 오류를 확인할 수 있습니다.
— Shrawan

0

내가하는 일은 효과별로 모든 오류 처리를 효과에 집중시키는 것입니다.

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

-8

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


예, 그러나 redux에 아무것도 보내지 않습니까?
— Eino Mäkitalo

이 접근 방식은 나쁘지 않습니다. 일반적으로 redux에 저장은 싱글 톤이며 axios 인터셉터 파일로 스토어를 가져오고 store.dispatch ()를 사용하여 모든 작업을 트리거 할 수 있습니다. 이것은 시스템의 모든 API 오류를 한 곳에서 처리하는 단일 접근 방식입니다
— Wedmich
당사 사이트를 사용함과 동시에 당사의 쿠키 정책과 개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.