2015-12-21 34 views
55

我有一個客戶端減速器,另外一個用於AppToolbar和其他一些人...處理反應堆中的提取錯誤的最佳方法是什麼?

現在讓我們說,我創建了一個獲取操作刪除客戶端,如果失敗,我在客戶端減速器代碼應該做的一些東西,但我也想在AppToolbar中顯示一些全局錯誤。

但客戶端和AppToolbar減速器不共享狀態的相同部分,我無法在減速器中創建新的操作。

那麼我想如何顯示全局錯誤?由於

更新1:

我忘了提,我使用este devstack

更新2: 標誌着我Eric的回答是正確的,但我不得不說,解決方案,我在este中使用更像是Eric和Dan的答案的組合... 您只需要找到適合您的代碼中的最佳代碼即可...

+1

您的選票越來越近,可能是因爲您沒有提供大量的示例代碼。如果問題更清晰,你的問題和你得到的答案將會對其他人更有幫助。 – acjay

+0

我必須同意w/@acjay這個問題缺乏上下文。我已經用一個通用的解決方案回答了下面的問題(帶有代碼示例),但是您的問題可以使用一些改進。看起來你可能有幾個單獨的問題。 1)處理異步動作/錯誤。 2)在你的redux狀態樹中適當地分割狀態。 3)讓你的組件獲得他們需要的數據。 – ErikTheDeveloper

+0

@ErikTheDeveloper謝謝你,你的回答看起來不錯。但是你是對的,我忘了提及背景。我編輯了我的問題,我使用este devstack,它看起來像你的答案是不適用的,因爲它是... –

回答

72

如果您想要共享除了「全局錯誤」,你可以創建一個減速器,它可以監聽addError,removeError等等動作。然後,您可以在state.errors處掛接到您的Redux狀態樹,並在適當的位置顯示它們。

有很多方法可以解決這個問題,但總體思路是,全局錯誤/消息將有利於他們自己的reducer與<Clients />/<AppToolbar />完全分離。當然,如果這些組件中的任何一個都需要訪問errors,則可以將errors傳遞給它們作爲任何需要的支柱。

更新:代碼示例

這裏是它可能是什麼樣子,如果你是到「全局錯誤」 errors傳遞到您的頂級<App />和有條件地呈現它一個例子(如果存在錯誤)。使用react-redux's 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,我有類似於你在這裏建議的東西,但令人驚訝的是,我從來沒有設法獲得'catch'功能如果我在代碼中使用'someHttpClient.get('/ resources')'或'fetch('/ resources')',則返回'500 Server Error'。你有沒有想過我會犯錯誤的頭腦?本質上,我所做的是'fetch'確實發送了一個以我的'routes'結尾的請求,其中我在我的'mongoose'模型上調用一個方法來做一些非常簡單的事情,比如添加文本或從DB中刪除文本。 –

+1

嘿,我是通過Google搜索來到這裏的 - 只是想感謝你一個很好的例子。我一直在努力解決同樣的問題,這真是太棒了。當然,解決方案是將錯誤集成到商店中。爲什麼我沒有想到......歡呼聲 – Spock

69

Erik’s answer是正確的,但我想補充一點,你不必火單獨的操作添加錯誤。另一種方法是使用處理error字段的減速器。這是個人選擇和慣例的問題。

例如,從Redux real-world example有錯誤處理:

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

這是否意味着在每次成功請求時,我們都應該將RESET_ERROR_MESSAGE類型傳遞給errorMessage reducer? –

+1

@DimitriMikadze不,它不。這個功能只是減速器的錯誤狀態。如果您通過RESET_ERROR_MESSAGE,它將清除所有錯誤消息。如果你沒有通過,並且沒有錯誤字段,它只是返回不變的狀態,所以如果以前的行動有一些錯誤,他們仍然會在成功後採取行動.... –

+0

我更喜歡這種方法,因爲它允許隨着消費者將「錯誤」附加到動作有效載荷上,更自然的內聯響應。謝謝丹! –

1

我目前正在幾個特定的​​錯誤(用戶輸入驗證)的方法是讓我的子減速器拋出一個異常,捕獲它在我的根減速器中,並將其附加到操作對象。然後我有一個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)); 
    } 
} 

,然後加入錯誤的州樹是埃裏克描述。

我非常謹慎地使用它,但它使我無需複製合法屬於reducer的邏輯(因此它可以保護自己免受無效狀態的影響)。

-6

您可以使用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); 
 
    });

+0

是的,但你沒有調度任何東西來減少? –

0

寫定製的中間件來處理所有的API相關的錯誤。在這種情況下,您的代碼將會更清晰。

failure/ error actin type ACTION_ERROR 

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

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

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

     } 
} 
相關問題