2016-07-07 11 views
0

Ich habe dieses Protected HOC. Sein Zweck besteht darin, nur WrappedComponent zu rendern, wenn der Benutzer authentifiziert ist. Ansonsten sollte die AuthenticateComponent gerendert werden (normalerweise eine Login-Komponente).Wrapped-Komponente rendert immer noch, wenn Redux-Zustand sagt, sollte es nicht

import React from "react" 

const PROPTYPES = { 
    authenticated: React.PropTypes.bool.isRequired, 
} 
export default (WrappedComponent, AuthenticateComponent) => { 
    let Protected = (props) => (
    props.authenticated 
    ? <WrappedComponent {...props}/> 
    : <AuthenticateComponent {...props}/> 
) 
    Protected.propTypes = PROPTYPES 
    return Protected 
} 

Die Stützen für die Komponente von einer angeschlossenen redux Container Komponente

kamen
const AccountContainer = ({ children }) => (
    <div>{children}</div> 
) 
const select = state => state.account 
export default connect(select, { refreshUser, logout })(Protected(AccountContainer, LoginContainer)) 

meine account Minderer wie folgt aussehen:

function authenticated(state = false, action) { 
    switch (action.type) { 
    case actions.START_SIGNUP_SUCCESS: 
    case actions.LOGIN_SUCCESS: 
     return true 
    case actions.LOGIN_ERROR: 
    case actions.START_SIGNUP_ERROR: 
    case actions.LOGOUT_SUCCESS: 
     return false 
    default: 
     return state 
    } 
} 

... 

export default combineReducers({ 
    authenticated, 
    access_token, 
    loggingIn, 
    user, 
    error, 
}) 

Es kommt nun, dass, wenn die LOGOUT Aktion gesetzt Die state.account.authenticated-Eigenschaft wird auf "false" festgelegt, und dennoch wird WrappedComponent weiterhin gerendert. Es greift auf verschiedene andere Eigenschaften von account zu und sie wurden alle auch schon gelöscht, was die Komponente nicht prüft und erwartet. Die WrappedComponent geht davon aus, dass der account-Zustand immer noch authenticated ist und daher gültig ist.

Ich frage mich, welche Art von Race-Bedingung könnte das sein?

Antwort

1

Ich kann nicht wissen, ohne den Code zu sehen, aber es sieht aus wie Ihr Reducer den Zustand mutiert. Ein Reduzierer sollte den Zustand niemals mutieren. Es sollte stattdessen einen neuen Zustand mit den richtigen Eigenschaften erstellen.

Der springende Punkt ist, Rennen und andere Anomalien zu verhindern.

React Redux wurde sehr sorgfältig entworfen, um die Arten von Problemen zu verhindern, die Sie hier sehen. Es erfordert jedoch, dass Sie sich an die Redux-Regeln halten. Die wichtigste ist, dass die reducer pure Funktionen sein müssen.

Wenn Ihr Reducer den alten Zustand ändert und stattdessen zurückgibt, hat Redux keine einfache Möglichkeit zu sehen, dass Sie Änderungen am Status vorgenommen haben. Tatsächlich wird angenommen, dass keine Änderungen vorgenommen wurden. Daher wird nichts neu gerendert werden.

Edit:

Ihr Minderer sieht gut aus, obwohl ich nicht sehen kann, wie die account Minderer an anderer Stelle verwendet wird, ich nehme an, es auch in Ordnung.

Was ich glaube, das Problem ist, dass Ihre Komponente in der Tat nicht gerendert wird, aber die Render-Methode immer noch auf LOGOUT aufgerufen wird. Was passiert, ist, dass React gerne eine Unterkomponente rendert, wenn diese Unterkomponente nach einem solchen Rendervorgang fragt. Und seit connect Haken in die store Updates, um dies zu tun, ist das, was vor sich geht.

Wenn Ihr Zustand ändert, connect die props von WrappedComponent von mapStateToProps aufrufen und es wird feststellen, dass diese Requisiten verändert haben (wegen nicht länger zu werden angemeldet, und diese Daten somit zwar anders, als es vorher war) neu bewerten . Connect weist dann React an, das WrappedComponent erneut zu rendern. Reagieren wird das tun. Ihre render Methode wiederum hat wahrscheinlich Probleme mit den Daten, die übergeben werden, da es ungültige Daten sind, die nur verwendet werden sollen, wenn ein Benutzer angemeldet ist.

Die Lösung besteht darin, den Render einfach mit einem Dummy zu beenden <div/>.Dieses Div, ein virtuelles DOM-Element, wird es tatsächlich niemals in das DOM schaffen. React speichert Elemente und Batch-DOM-Aktualisierungen zwischen. React wird daher die gesamte WrappedComponent vor dem Zusammenführen in das DOM und leider, nachdem es die neue Version bereits gerendert hat, abschneiden.

Beachten Sie, dass es Redux in Kombination mit Connect ist, die hier wirklich verantwortlich sind, weil Redux keine Ahnung von Komponenten hat und daher nicht berücksichtigen kann, während Connect den Speicher in der Reihenfolge abonniert, in der er erstellt wird Das Geschäft benachrichtigt dann die Komponenten in der Reihenfolge, in der sie abonniert wurden.

Die endgültige Reihenfolge hängt von der Renderreihenfolge und der Montagereihenfolge ab, und viele Komponenten spielen eine Rolle bei der Entscheidung für diese Reihenfolge. Es ist einfach nicht stabil und sollte daher nicht berücksichtigt werden.

Wenn Sie eine angeschlossene Komponente bauen, stellen Sie sicher, dass Ihre mapStateToProps nehmen jede gültigen Zustand zu schreiben und gültig Requisiten von denen für die Zielkomponente kompilieren. Ob Sie Dummy-Werte hinzufügen oder die Komponente selbst ändern, um alles, was Sie übergeben, gültig zu machen, ist es wichtig, alle gültigen Zustände auf gültige Requisiten aufzulösen, selbst wenn die Komponente, für die diese Requisiten gedacht sind, niemals angezeigt werden soll. Auf diese Weise verhindern Sie Fehler aufgrund ungültiger Requisiten, die sich tatsächlich aus einem gültigen Zustand ergeben (Ausloggen ist ein gültiger Status).

Natürlich ist es nicht notwendig, mit ungültigen Zustand umzugehen, wie es nie auftreten sollte, nicht einmal für einen Augenblick.

+0

Ich habe meine Frage mit meinem Reducer-Code bearbeitet. Sieht für dich ok aus? – philk