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.