Cách tốt nhất để giải quyết lỗi tìm nạp trong react redux là gì?


105

Tôi có một công cụ giảm bớt cho Khách hàng, một công cụ khác cho AppToolbar và một số công cụ khác ...

Bây giờ, hãy nói rằng tôi đã tạo một hành động tìm nạp để xóa ứng dụng khách và nếu nó không thành công, tôi có mã trong trình giảm bớt Khách hàng sẽ thực hiện một số công việc, nhưng tôi cũng muốn hiển thị một số lỗi chung trong Thanh AppToolbar.

Nhưng trình giảm bớt Khách hàng và Thanh công cụ ứng dụng không chia sẻ cùng một phần của trạng thái và tôi không thể tạo hành động mới trong trình giảm bớt.

Vì vậy, làm thế nào tôi giả sử để hiển thị lỗi toàn cầu? Cảm ơn

CẬP NHẬT 1:

Tôi quên đề cập rằng tôi sử dụng este devstack

CẬP NHẬT 2: Tôi đã đánh dấu câu trả lời của Eric là đúng, nhưng tôi phải nói rằng giải pháp mà tôi đang sử dụng trong este giống với sự kết hợp giữa câu trả lời của Eric và Dan hơn ... Bạn chỉ cần tìm những gì phù hợp với bạn nhất trong mã của bạn .. .


2
Bạn đang nhận được phiếu bầu sát sao và có thể là do bạn không cung cấp nhiều mã ví dụ. Câu hỏi của bạn và câu trả lời bạn nhận được sẽ hữu ích hơn cho người khác nếu vấn đề được nêu rõ ràng hơn.
acjay

Tôi phải đồng ý với w / @acjay rằng câu hỏi này thiếu ngữ cảnh. Tôi đã trả lời bên dưới (với các ví dụ về mã) với một giải pháp chung, nhưng câu hỏi của bạn có thể sử dụng một số sàng lọc. Có vẻ như bạn có thể gặp một số vấn đề riêng biệt. 1) Xử lý các hành động / lỗi không đồng bộ. 2) Tách trạng thái một cách thích hợp trong cây trạng thái redux của bạn. 3) Nhận các thành phần của bạn dữ liệu mà chúng cần.
Erik Aybar

@ErikTheDeveloper cảm ơn, câu trả lời của bạn trông rất tuyệt. Nhưng bạn nói đúng, tôi quên đề cập đến bối cảnh. Tôi thay đổi nội dung câu hỏi của tôi, tôi đang sử dụng este devstack và có vẻ như câu trả lời của bạn là không được áp dụng có vì nó là ...
Dusan Plavak

Câu trả lời:


116

Nếu bạn muốn có khái niệm về "lỗi toàn cục", bạn có thể tạo một trình errorsgiảm thiểu, có thể lắng nghe các hành động addError, removeError, v.v. Sau đó, bạn có thể kết nối vào cây trạng thái Redux của mình tại state.errorsvà hiển thị chúng ở bất kỳ nơi nào thích hợp.

Có một số cách bạn có thể tiếp cận vấn đề này, nhưng ý tưởng chung là các lỗi / thông báo toàn cục sẽ có ích cho việc giảm thiểu của riêng chúng để hoàn toàn tách biệt với <Clients />/ <AppToolbar />. Tất nhiên nếu một trong hai thành phần này cần quyền truy cập, errorsbạn có thể chuyển errorscho chúng như một chỗ dựa bất cứ khi nào cần thiết.

Cập nhật: Ví dụ về mã

Dưới đây là một ví dụ về nó có thể trông như thế nào nếu bạn chuyển "lỗi chung" errorsvào cấp cao nhất của mình <App />và hiển thị nó có điều kiện (nếu có lỗi). Sử dụng react-reduxconnect để kết nối <App />thành phần của bạn với một số dữ liệu.

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

Và theo như người tạo hành động có liên quan, nó sẽ gửi ( redux-thunk ) thất bại thành công theo phản hồi

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

Mặc dù trình giảm thiểu của bạn có thể đơn giản quản lý một loạt lỗi, thêm / bớt các mục nhập một cách thích hợp.

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, tôi có một cái gì đó tương tự như những gì bạn đã đề xuất ở đây nhưng đáng ngạc nhiên là tôi không bao giờ quản lý để nhận các catchhàm được gọi nếu someHttpClient.get('/resources')hoặc fetch('/resources')cái mà tôi sử dụng trong trả về mã của mình 500 Server Error. Bạn có suy nghĩ gì về việc tôi có thể mắc lỗi không? Về cơ bản, những gì tôi làm là fetchgửi một yêu cầu kết thúc bằng cách tôi routesgọi một phương thức trên mongoosemô hình của mình để thực hiện một điều gì đó rất đơn giản, như thêm văn bản hoặc xóa văn bản khỏi DB.
Kevin Ghaboosi

2
Này, tôi đến đây từ một tìm kiếm của Google - chỉ muốn cảm ơn bạn vì một ví dụ tuyệt vời .. Tôi đã phải vật lộn với những vấn đề tương tự, và điều này thật tuyệt vời. Tất nhiên giải pháp là tích hợp lỗi vào cửa hàng. Tại sao tôi không nghĩ về điều đó ... chúc mừng
Spock

2
Làm thế nào một người sẽ thực thi một hàm khi xảy ra lỗi? ví dụ: tôi cần hiển thị bánh mì nướng / cảnh báo trong giao diện người dùng, không hiển thị thành phần Cảnh báo bằng cách cập nhật các đạo cụ của thành phần mẹ
Gianfranco P.

111

Câu trả lời của Erik là đúng nhưng tôi muốn nói thêm rằng bạn không cần phải thực hiện các hành động riêng biệt để thêm lỗi. Một cách tiếp cận khác là có một bộ giảm tốc xử lý bất kỳ hành động nào với một errortrường . Đây là vấn đề của sự lựa chọn và quy ước cá nhân.

Ví dụ: từ ví dụ Reduxreal-world có xử lý lỗi:

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

Có nghĩa là đối với mọi yêu cầu thành công, chúng ta phải chuyển loại RESET_ERROR_MESSAGE sang trình giảm thiểu errorMessage?
Dimi Mikadze,

2
@DimitriMikadze không nó không. Chức năng này chỉ là công cụ giảm thiểu trạng thái lỗi. Nếu bạn vượt qua RESET_ERROR_MESSAGE, nó sẽ xóa tất cả các thông báo lỗi. Nếu bạn không vượt qua và không có lĩnh vực báo lỗi, nó chỉ trở lại trạng thái không thay đổi, vì vậy nếu có một số sai sót từ những hành động trước đó, họ vẫn sẽ ở đó sau khi hành động thành công ....
Dusan Plavak

Tôi thích cách tiếp cận này hơn vì nó cho phép phản hồi nội tuyến tự nhiên hơn khi người tiêu dùng gắn nó errorvào trọng tải hành động. Cảm ơn Dan!
Mike Perrenoud

1
Tôi không thể hiểu được cách hoạt động của nó. Ngoài ví dụ trong thế giới thực, bạn có tài liệu / video nào giải thích điều này không? Đó là một yêu cầu khá cốt lõi của hầu hết các dự án và tôi đã tìm thấy rất ít tài liệu dễ hiểu về chủ đề này. Cảm ơn.
Matt Saunders,

6
@MattSaunders Trong khi cố gắng hiểu nó, tôi đã xem qua một khóa học Redux của chính Dan (người trả lời, người thực sự là người tạo ra Redux), với phần Hiển thị thông báo lỗi cùng với những câu trả lời này và ví dụ trong thế giới thực đã đưa nó về nhà tôi. Chúc may mắn.
Agustín Lado

2

Cách tiếp cận mà tôi hiện đang thực hiện đối với một số lỗi cụ thể (xác thực đầu vào của người dùng) là yêu cầu các bộ giảm phụ của tôi ném một ngoại lệ, bắt nó trong bộ giảm gốc của tôi và gắn nó vào đối tượng hành động. Sau đó, tôi có một redux-saga kiểm tra các đối tượng hành động để tìm lỗi và cập nhật cây trạng thái với dữ liệu lỗi trong trường hợp đó.

Vì thế:

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

Và sau đó thêm lỗi vào cây trạng thái như Erik mô tả.

Tôi sử dụng nó khá ít, nhưng nó giúp tôi không phải lặp lại logic mà hợp pháp thuộc về trình giảm bớt (vì vậy nó có thể tự bảo vệ khỏi trạng thái không hợp lệ).


1

viết phần mềm trung gian tùy chỉnh để xử lý tất cả các lỗi liên quan đến api. Trong trường hợp này, mã của bạn sẽ sạch hơn.

   failure/ error actin type ACTION_ERROR

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

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

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

       }
}

1
Cũng làm cho việc gỡ lỗi IMHO khó hơn
chrisjlee

2
Bạn không cần trung gian cho việc này, bạn có thể viết chính xác cùng iftrong một giảm
Juan Campa

Nếu có hơn 50 api thì bạn cần phải viết ở mọi nơi. Thay vào đó, bạn có thể viết phần mềm trung gian tùy chỉnh để kiểm tra lỗi.
Shrawan

0

những gì tôi làm là tôi tập trung tất cả việc xử lý lỗi trên cơ sở từng hiệu ứng

/**
 * 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

Bạn có thể sử dụng ứng dụng khách axios HTTP. Nó đã triển khai tính năng Đánh chặn. Bạn có thể chặn các yêu cầu hoặc phản hồi trước khi chúng được xử lý vào lúc đó hoặc bắt.

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


Có nhưng bạn không gửi bất cứ điều gì đến redux?
Eino Mäkitalo

Cách làm này không tệ. Thông thường store trong redux là một singleton và bạn có thể nhập store trong tệp interceptors axios và sử dụng store.dispatch () để kích hoạt bất kỳ hành động nào. Đây là cách tiếp cận đơn nhất để xử lý tất cả các lỗi api trong hệ thống tại một nơi
Wedmich
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.