2015-12-21 11 views
55

Mam jeden reduktor Dla klientów, jeden inny na AppToolbar i kilka innych ...Jaki jest najlepszy sposób radzenia sobie z błędem pobierania w reakcji na redukcję?

Teraz pozwala powiedzieć, że stworzyliśmy akcję sprowadzania do usunięcia klienta, a jeśli nie mam kod w reduktor klientów, co powinien robić niektóre rzeczy, ale także chcę wyświetlić jakiś globalny błąd w AppToolbar.

Ale klienci i reduktory AppToolbar nie dzielą tej samej części stanu i nie mogę utworzyć nowej akcji w reduktorze.

Jak więc wyświetlić globalny błąd? Dzięki

UPDATE 1:

I zapomnij wspomnieć, że używam este devstack

UPDATE 2: zaznaczyłem odpowiedź Erica prawidłowe, ale muszę powiedzieć, że rozwiązanie, które jestem użycie w este jest bardziej jak połączenie odpowiedzi Erica i Dana ... Po prostu musisz znaleźć to, co najlepsze w twoim kodzie ...

+1

Otrzymujesz coraz więcej głosów, a to pewnie dlatego, że nie podajesz całego mnóstwa przykładowego kodu. Twoje pytanie i odpowiedzi, które otrzymasz, będą bardziej pomocne dla innych osób, jeśli problem zostanie zarysowany jaśniej. – acjay

+0

Muszę się zgodzić z/@acjay, że tego pytania brakuje w kontekście. Odpowiedziałem poniżej (z przykładami kodu) na ogólne rozwiązanie, ale Twoje pytanie może zawierać pewne udoskonalenia. Wygląda na to, że możesz mieć kilka osobnych problemów. 1) Obsługa asynchronicznych akcji/błędów. 2) Rozdzielanie stanu odpowiednio w drzewie stanu redux. 3) Dostarczenie swoim komponentom danych, których potrzebują. – ErikTheDeveloper

+0

@ErikTheDeveloper dzięki, twoja odpowiedź wygląda świetnie. Ale masz rację, zapomniałem wspomnieć o kontekście. Zmieniłem moje pytanie, używam este devstack i wygląda na to, że twoja odpowiedź nie ma tam zastosowania, tak jak jest ... –

Odpowiedz

72

Jeśli chcesz mieć co z "globalnymi błędami", możesz stworzyć reduktor errors, który może nasłuchiwać działań addError, removeError, etc ... Następnie możesz podłączyć się do drzewa stanu Redux pod numerem state.errors i wyświetlić je w odpowiednim miejscu.

Istnieje wiele sposobów, w jakie można się do tego podejść, ale ogólna idea mówi, że globalne błędy/komunikaty zasługują na to, aby ich własny reduktor żył całkowicie oddzielnie od <Clients />/<AppToolbar />. Oczywiście, jeśli któryś z tych składników wymaga dostępu do errors, możesz przekazać im errors jako prop, gdziekolwiek jest to potrzebne.

Aktualizacja: Kod Przykład

Oto jeden z przykładów, co to może wyglądać, jeśli były do ​​przekazania „globalnej błędy” errors na swoim najwyższym poziomie <App /> i warunkowo czynią go (jeśli istnieją błędy obecne). Używanie react-redux's connect do podłączania komponentu <App /> do niektórych danych.

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

I o ile twórca skarga dotyczy, to wysyłka (redux-thunk) brak sukcesu w zależności od odpowiedzi

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

Podczas gdy reduktor może po prostu zarządzać szereg błędów, dodawanie/usuwanie wpisy odpowiednio.

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, mam coś podobnego do tego, co tu zasugerowałeś, ale zaskakująco nigdy nie uda mi się uzyskać funkcji "catch" wywołany, jeśli 'someHttpClient.get ('/ resources')' lub 'fetch ('/ resources')' których używam w moim kodzie zwracają '500 Server Error'. Czy masz jakieś myśli ze szczytu głowy, gdzie mógłbym się pomylić? Zasadniczo, to, co robię, polega na tym, że 'fetch' wysyła zapytanie, które kończy się moimi' trasami ', w których nazywam metodę na moim modelu 'mongoose' dla zrobienia czegoś bardzo prostego, jak dodanie tekstu lub usunięcie tekstu z DB. –

+1

Hej, przyszedłem tutaj z wyszukiwarki Google - chciałem tylko podziękować za wspaniały przykład. Walczyłem z tymi samymi problemami, a to jest genialne. Oczywiście rozwiązaniem jest zintegrowanie błędów ze sklepem. Dlaczego o tym nie pomyślałem ... Pozdrawiam – Spock

69

Erik’s answer jest poprawna, ale chciałbym dodać, że nie masz na ogień odrębnych działań dodawania błędów. Alternatywnym podejściem jest posiadanie reduktora, który obsługuje dowolną akcję z polem error. Jest to kwestia osobistego wyboru i konwencji.

Na przykład, od Redux real-world example że posiada obsługę błędów:

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

Czy oznacza to, że na każde żądanie powodzenia powinniśmy przekazać typ RESET_ERROR_MESSAGE do reduktora errorMessage? –

+1

@DimitriMikadze nie, nie. Ta funkcja jest po prostu reduktorem dla stanu błędu. Przekazanie RESET_ERROR_MESSAGE spowoduje wyczyszczenie wszystkich komunikatów o błędach. Jeśli nie przejdziesz i nie pojawi się pole błędu, po prostu wróci stan niezmieniony, więc jeśli wystąpiły błędy z poprzednich działań, nadal będą one działać po pomyślnym działaniu .... –

+0

Preferuję to podejście, ponieważ pozwala na bardziej naturalna odpowiedź liniowa, ponieważ konsument dołącza "błąd" do ładunku działania. Dzięki Dan! –

1

Podejście Jestem obecnie biorąc na kilka konkretnych błędów (walidacji wejścia użytkownika) ma mieć moje sub-reduktory wyjątek, catch w moim reduktorze korzenia i przymocuj go do obiektu akcji. Następnie mam sagę redux, która sprawdza obiekty akcji w poszukiwaniu błędu i aktualizuje drzewo stanu z danymi o błędach w tym przypadku.

Więc:

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

a następnie dodanie do drzewa błąd państwowego jest tak opisuje Erik.

Używam go dość oszczędnie, ale nie pozwala mi na kopiowanie logiki, która legalnie należy do reduktora (dzięki czemu może chronić się przed nieważnym stanem).

-6

Można użyć klienta HTTP axios. Ma już zaimplementowaną funkcję Interceptors. Możesz przechwytywać żądania lub odpowiedzi, zanim zostaną do tego czasu przetworzone lub złapane.

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

Tak, ale nie wysyłacie niczego do redux? –

0

napisać niestandardowy Middleware obsłużyć cały błąd api powiązane. W takim przypadku twój kod będzie bardziej przejrzysty.

failure/ error actin type ACTION_ERROR 

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

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

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

     } 
} 
Powiązane problemy