Ich habe einen Reduzierungsbaum, der so aussieht:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: combineReducers({
sets,
boosters
}),
servers: combineReducers({
servers
})
})
});
Jetzt enthält der Schlüssel setup
ein Formular, das zurückgesetzt werden muss, sobald wir es gesendet haben. Ich habe jedoch keine Möglichkeit, auf den gesamten setup
-Baum zuzugreifen, da bei Verwendung von combinReducers die Reduzierer nur die Daten an den Blattknoten des Baums bearbeiten (in diesem Fall sets
und boosters
).
Mein erster Impuls ist, eine Funktion zu erstellen, die den gesamten Setup-Baum wie folgt reduziert:
function setup(state, action){
//If there's an action that affects this whole tree, handle it
switch(action.type){
case "FORM_SUBMIT": //DO STUFF
break;
}
//Otherwise just let the reducers care about their own data
return combineReducers({
sets,
boosters
})(state);
}
Aber das funktioniert nicht und bringt auch die schöne Baumstruktur meines ersten Codebeispiels durcheinander.
Gibt es dafür eine bessere Lösung mit Redux?
2 Antworten
combineReducers
ist ein schönes Muster, da es die Idee erzwingt, dass die Reduzierungen auf nicht überlappende Teilmengen des Geschäfts beschränkt sein sollten, die von der Struktur des Geschäfts selbst entkoppelt sind. Es ist der Meinung, dass Sie die Blätter reduzieren sollten, nicht die Zweige, und es kümmert sich um die Reduzierung der Zweige.
Es kann jedoch gute Gründe geben, ein alternatives Muster zu verwenden. Wie ich in einer leicht verwandten Frage erwähnt habe, Sie können die reine Verwendung von combineReducers
deaktivieren und Ihre Reduzierungen nach Belieben zerlegen.
In Ihrem Fall könnten Sie Ihr inneres combineReducers
dekorieren:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: setupReducer(
combineReducers({
sets,
boosters
})
),
servers: combineReducers({
servers
})
})
});
Hier ist setupReducer
eine Funktion höherer Ordnung. Es kann schwierig sein, darüber nachzudenken, aber so gehe ich vor:
- Wir wissen, dass
setupReducer
einen Reduzierer als Argument verwendet, weil wir das Ergebnis voncombineReducers
an ihn übergeben. - Wir wissen, dass die von
combineReducers
zurückgegebene Signatur des Reduzierers(state, action) => state
lautet. - Wir wissen auch, dass
setupReducer
einen Reduzierer zurückgeben muss, der wiederum eine Funktion der Signatur(state, action) => state
ist.
Mit anderen Worten, es wird ein Reduzierer benötigt und ein Reduzierer zurückgegeben: ((state, action) => state) => ((state, action) => state)
. So könnte es aussehen:
function setupReducer(subReducer) {
return (state, action) => {
//If there's an action that affects this whole tree, handle it
switch(action.type){
case "FORM_SUBMIT":
// ... create newState
return newState;
default:
return subReducer(state, action);
}
}
}
Ich habe Ihren Logikfluss oben beibehalten, aber zur Vorsicht möchten Sie möglicherweise subReducer
bedingungslos aufrufen und dann die Ausgabe ändern. Andernfalls müssen Sie sicherstellen, dass Ihre Zweige, in denen sie nicht aufgerufen werden, immer ein Objekt mit derselben Form erzeugen, was wie ein potenzieller klebriger Kopplungspunkt erscheint.
@ acjays Antwort ist eine großartige Idee! Ich wollte nur die alte Methode reducer(state, action)
verwenden und keine Funktion höherer Ordnung. Also habe ich eine Methode erstellt, die den Reduzierer in einer Master-Slave-Beziehung zusammensetzt.
MasterSlave
export default function masterSlaveReducer(reducerMaster, reducerSlave) {
return (state, action) => {
const newState = reducerMaster(state, action);
if(newState === state){
return reducerSlave(state, action);
}
return newState;
};
}
Miguels Code würde dann folgendermaßen verwendet:
module.exports = combineReducers({
routing: routeReducer,
app: combineReducers({
setup: masterSlaveReducer(
setup, // setup() from Miguel's question
combineReducers({
sets,
boosters
})
),
servers: combineReducers({
servers
})
})
});
Verwandte Fragen
Neue Fragen
reactjs
React ist eine JavaScript-Bibliothek zum Erstellen von Benutzeroberflächen. Es verwendet ein deklaratives, komponentenbasiertes Paradigma und soll sowohl effizient als auch flexibel sein.