2015-12-21 18 views
55

Ho un riduttore per i clienti, un altro per AppToolbar e alcuni altri ...Qual è il modo migliore per gestire un errore di recupero in caso di risposta rapida?

Ora lascia dire che ho creato un'azione di recupero per eliminare cliente, e se non riesce Ho codice nel riduttore Clienti che dovrebbe fare alcune cose, ma voglio anche mostrare qualche errore globale in AppToolbar.

Ma i riduttori Client e AppToolbar non condividono la stessa parte dello stato e non riesco a creare una nuova azione nel riduttore.

Quindi, come suppongo di mostrare un errore globale? Grazie

UPDATE 1:

ho dimenticato di dire che io uso este devstack

UPDATE 2: ho segnato la risposta di Eric come corretto, ma devo dire che la soluzione cui sono usare in este è più come la combinazione della risposta di Eric e Dan ... Devi solo trovare quello che fa per te il meglio del tuo codice ...

+1

Stai ottenendo voti ravvicinati, ed è probabilmente perché non stai fornendo un sacco di codice di esempio. La tua domanda e le risposte che otterrai saranno più utili ad altre persone se il problema è delineato in modo più chiaro. – acjay

+0

Devo concordare con @acjay che questa domanda è carente nel contesto. Ho risposto di seguito (con esempi di codice) con una soluzione generale, ma la tua domanda potrebbe usare un po 'di raffinatezza. Sembra che tu possa avere alcuni problemi separati. 1) Gestione di azioni/errori asincroni. 2) Suddividere in modo appropriato lo stato dell'albero di Redux. 3) Ottenere i componenti i dati di cui hanno bisogno. – ErikTheDeveloper

+0

@ErikTheDeveloper grazie, la tua risposta sembra grandiosa. Ma hai ragione, dimentico di menzionare il contesto. Ho modificato la mia domanda, sto usando este devstack e sembra che la tua risposta non sia applicabile lì così com'è ... –

risposta

72

Se vuoi avere il co ncept of "global errors", puoi creare un riduttore errors, che può ascoltare le azioni addError, removeError, etc .... Quindi, è possibile collegarsi all'albero di stato di Redux allo state.errors e visualizzarli laddove appropriato.

Ci sono molti modi per approcciarlo, ma l'idea generale è che gli errori/messaggi globali meriterebbero il proprio riduttore di vivere completamente separati da <Clients />/<AppToolbar />. Naturalmente se uno di questi componenti necessita dell'accesso a errors, è possibile passare a errors come oggetto di scena, laddove necessario.

Aggiornamento: Esempio di codice

Ecco un esempio di quello che potrebbe apparire come se si dovesse passare gli "errori globali" errors nel vostro livello superiore <App /> e condizionalmente renderlo (se ci sono errori presenti). Utilizzando react-redux's connect per collegare il tuo componente <App /> ad alcuni dati.

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

E per quanto riguarda il creatore azione è interessato, sarebbe inviare (redux-thunk) mancato successo in base alla risposta

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

Mentre il riduttore potrebbe semplicemente gestire una serie di errori, aggiunta/rimozione voci in modo appropriato.

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, ho qualcosa di simile a quello che hai suggerito qui, ma sorprendentemente non riesco mai a ottenere funzioni 'catch' chiamato se 'someHttpClient.get ('/ resources')' o 'fetch ('/ resources')' che uso nel mio codice restituisce '500 Server Error'. Hai qualche pensiero in cima alla tua testa dove potrei sbagliare? Essenzialmente, quello che faccio è 'fetch' ha inviato una richiesta che finisce con il mio' routes' in cui chiamo un metodo sul mio modello 'mongoose' per fare qualcosa di molto semplice, come aggiungere un testo o rimuovere un testo dal DB. –

+1

Ehi, sono venuto qui da una ricerca su Google - volevo solo ringraziarvi per un grande esempio .. Ho lottato con gli stessi problemi, e questo è geniale. Ovviamente la soluzione è integrare gli errori nel negozio. Perché non ci ho pensato ... evviva – Spock

69

Erik’s answer è corretto ma vorrei aggiungere che non c'è bisogno di sparare azioni separate per l'aggiunta di errori. Un approccio alternativo consiste nell'avere un riduttore che gestisca l'azione con un campo error. Questa è una questione di scelta personale e di convenzione.

Ad esempio, dal Redux real-world example che ha la gestione degli errori:

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

Significa che su ogni richiesta di successo dovremmo passare il tipo RESET_ERROR_MESSAGE a errorMessage reducer? –

+1

@DimitriMikadze no no. Questa funzione è solo riduttore per stato di errore. Se passi RESET_ERROR_MESSAGE, cancellerà tutti i messaggi di errore. Se non passi e non c'è campo di errore, restituisce semplicemente lo stato invariato, quindi se ci sono stati errori da azioni precedenti, saranno comunque lì dopo l'azione di successo .... –

+0

Preferisco questo approccio perché consente di risposta in linea più naturale in quanto il consumatore attribuisce l'errore al carico utile dell'azione. Grazie Dan! –

1

L'approccio che sto attualmente in corso per un paio di errori specifici (validazione dell'input utente) è quello di avere il mio sub-riduttori generano un'eccezione, fermo nel mio riduttore di radici e collegalo all'oggetto azione. Quindi ho una saga di redux che ispeziona gli oggetti azione per un errore e aggiorna la struttura ad albero con i dati di errore in quel caso.

Quindi:

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

e quindi aggiungendo l'errore per l'albero dello stato è come descrive Erik.

Lo uso con parsimonia, ma mi impedisce di dover duplicare la logica che appartiene legittimamente al riduttore (in modo che possa proteggersi da uno stato non valido).

-6

È possibile utilizzare il client HTTP di axios. Ha già implementato la funzionalità Interceptors. Puoi intercettare richieste o risposte prima che vengano gestite da allora o catturate.

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

Sì, ma non stai inviando nulla da ridire? –

0

scrittura personalizzato Middleware per gestire tutti gli errori relativi api. In questo caso il tuo codice sarà più pulito.

failure/ error actin type ACTION_ERROR 

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

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

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

     } 
} 
Problemi correlati