2016-02-27 6 views
7

Ich erstelle App mit Redux und React. Ich stoße auf ein Problem, bei dem ich den Komponenteneigenschaften keinen Status zuordnen kann, da der Status eine Eigenschaft hat, die mit dem Namen des verwendeten Reduzierers übereinstimmt.Zustand in redux/react App hat eine Eigenschaft mit dem Namen des Reduzierers

Das verringert sich mit combineReducers Methode

const rootReducer = combineReducers({ 
    appReducer 
}) 

Der Anfangszustand ist

const initialState = { 
    sources: [], 
    left: {}, 
    right: {}, 
    diff: {} 
} 

jedoch in der Komponente Funktion mapStateToProps erstellt wird:

function mapStateToProps(state) { 
    return { 
    sources: state.sources 
    } 
} 

Die state.sources ist undefined weil der Wert von state Parameter ist

{ 
    appReducer: { 
    sources: [], 
    left: {}, 
    right: {}, 
    diff: {} 
    } 
} 

Ist das ein Merkmal von Redux? Also, wenn ich mehr Reduzierungen verwende, werden alle neue Eigenschaft zu state Variable hinzufügen? Oder ist etwas auf meiner Seite falsch (ich habe dieses Verhalten in redux Tutorials nie bemerkt). Eigentlich

Dank

+1

Ihr Code ist korrekt 'state.appReducer. Sources' Sie brauchen den Reducer Name –

+3

Stellen Sie sich vor, Sie haben 2,3 Reduzierungen jeder Reducer hat 'sources' Eigenschaft –

+1

Sie können spezifische' sources' durch 'state.appReducer bekommen. sources' und 'state.appReducer.2 sources' –

Antwort

17

Wenn Sie nur ein einziges Minderer haben, müssen Sie combineReducers() nicht brauchen. direkt verwenden Sie es einfach:

const initialState = { 
    sources: [], 
    left: {}, 
    right: {} 
} 
function app(state = initialState, action) { 
    switch (action.type) { 
    case 'ADD_SOURCE': 
    return Object.assign({}, state, { 
     sources: [...state.sources, action.newSource] 
    }) 
    case 'ADD_SOURCE_TO_LEFT': 
    return Object.assign({}, state, { 
     left: Object.assign({}, state.left, { 
     [action.sourceId]: true 
     }) 
    }) 
    case 'ADD_SOURCE_TO_RIGHT': 
    return Object.assign({}, state, { 
     right: Object.assign({}, state.right, { 
     [action.sourceId]: true 
     }) 
    }) 
    default: 
    return state 
    } 
} 

Jetzt haben Sie ein Geschäft mit diesem Minderer erstellen:

import { createStore } from 'redux' 
const store = createStore(app) 

und eine Komponente mit ihm verbinden:

const mapStateToProps = (state) => ({ 
    sources: state.sources 
}) 

jedoch Ihre Minderer schwer zu lesen weil es viele verschiedene Dinge auf einmal aktualisiert. Nun diese ist der Moment, den Sie es in mehrere unabhängige Reduzierungen teilen möchten:

function sources(state = [], action) { 
    switch (action.type) { 
    case 'ADD_SOURCE': 
    return [...state.sources, action.newSource] 
    default: 
    return state 
    } 
} 

function left(state = {}, action) { 
    switch (action.type) { 
    case 'ADD_SOURCE_TO_LEFT': 
    return Object.assign({}, state, { 
     [action.sourceId]: true 
    }) 
    default: 
    return state 
    }  
} 

function right(state = {}, action) { 
    switch (action.type) { 
    case 'ADD_SOURCE_TO_RIGHT': 
    return Object.assign({}, state, { 
     [action.sourceId]: true 
    }) 
    default: 
    return state 
    }  
} 

function app(state = {}, action) { 
    return { 
    sources: sources(state.sources, action), 
    left: left(state.left, action), 
    right: right(state.right, action), 
    } 
} 

Dies ist leichter zu pflegen und zu verstehen, und es macht es auch leichter, sie zu ändern und Test Reduzierungen unabhängig.

schließlich als letzten Schritt können wir combineReducers() verwenden, um die Wurzel app Minderer, anstatt sie von Hand schreiben zu generieren:

// function app(state = {}, action) { 
// return { 
//  sources: sources(state.sources, action), 
//  left: left(state.left, action), 
//  right: right(state.right, action), 
// } 
// } 

import { combineReducers } from 'redux' 
const app = combineReducers({ 
    sources, 
    left, 
    right 
}) 

Es gibt keine große Vorteil ist, combineReducers() zu verwenden anstelle des Schreibens der Wurzel Minderer durch Hand, außer dass es etwas effizienter ist und Ihnen wahrscheinlich ein paar Tippfehler ersparen wird. Sie können dieses Muster auch mehrfach in Ihrer App anwenden: Es ist in Ordnung, nicht zusammenhängende Reduzierungen mehrere Male in einem einzigen Reduzierer verschachtelt zu kombinieren.

Dieses Refactoring hätte keine Auswirkungen auf die Komponenten.

Ich würde vorschlagen, dass Sie meine free Egghead course on Redux zu sehen, die dieses Muster der Minderer Zusammensetzung umfasst und zeigt, wie combineReducers() umgesetzt wird.

+0

Danke Dan für Erklärung und den Link zu diesen Videos –

+0

Ich liebe immer deine Erklärung, einfach und genau. –

5

, ich glaube, Ihr Anfangszustand wäre:

{ 
    appReducer: { 
    sources: [], 
    left: {}, 
    right: {}, 
    diff: {} 
    } 
} 

Dies liegt daran, combineReducers Werke den Namen des Untersetzungsgetriebes nehmen, und Abbilden dessen Inhalts auf diesen Namen.

Auch nur eine Anmerkung, aber wenn Sie mehr als 1 Reducer verwenden, sollten die Namen Ihrer Reducer spezifischer als appReducer sein, und (nur meine persönliche Meinung) sie brauchen nicht das Wort reducer . Eine typische Anwendung könnte wie folgt aussehen:

combineReducers({ 
    user: userReducer, 
    messages: messagesReducer, 
    notifications: notificationsReducer 
}); 

Dann Ihr Zustand wie zugegriffen werden konnte:

state.user.email 
state.messages[0] 
+0

haben Sie richtig.Sollte ich dann die 'initialState' ändern Objekt entsprechend? –

+1

Die Idee ist, dass jeder Zweig des Reduzierers für seinen eigenen "initialState" verantwortlich ist. Dein Root Reducer sollte keinen initialState haben, und jeder Reducer sollte nur seine Sachen beinhalten. Also wäre dein 'appReducer' ein Objekt mit Schlüsseln für Quellen, links, rechts, etc. –