2017-08-25 1 views
2

Wie ich es verstehe, reagieren alle Reduktoren, wenn eine Aktion aufgerufen wird. Wenn eine Aktion in der Anweisung des Reduzierers vorhanden ist, wird sie ausgeführt. Wenn dies nicht der Fall ist, wird case: default ausgeführt, wodurch der vorhandene Status beibehalten wird.Reducer Verhalten

Wenn die Aktion im Reduzierer vorhanden ist, aber die bestimmte Eigenschaft, die sie zu aktualisieren versucht, nicht existiert, scheint sie sich in Ordnung zu verhalten, da nichts zu aktualisieren ist.

Zum Beispiel habe ich einen Aktionsersteller, der verwendet wird, um die visible Eigenschaft meiner Mods festzulegen. Jedes Modal hat seine eigene Id. Mein Code sieht wie folgt aus:

export default (state = initialState, action) => { 
    case types.SET_MODAL_IS_VISIBLE: 
     return Object.assign({}, state, 
     { modal22: action.value } 
    )} 

ich die SET_MODAL_IS_VISIBLE in mehreren Reduzierungen haben, aber wenn modal22 nicht in einem bestimmten Minderer definiert ist, passiert nichts und keine Fehler.

Jetzt habe ich ein Szenario, das einen Fehler wirft. Ich habe eine allgemeine Datumsauswahl-Komponente, die ich gebaut habe, die als einzelne und unabhängige Datumsauswahl verwendet werden kann, oder sie kann mit einer anderen verknüpft werden. Das zweite Szenario ist nützlich, wenn der Benutzer mir zwei Daten z. Start- und Enddatum

Ich habe auch eine Funktion, wo, wenn die Datumsauswahl mit einer anderen gekoppelt ist, wenn der Benutzer das Datum in der ersten Datumsauswahl setzt, deaktivieren ich alle Daten vor diesem Datum in der zweiten Datumsauswahl, weil ich nicht ' Ich möchte, dass der Benutzer versehentlich ein Enddatum vor dem Startdatum auswählt.

definiere ich meine Datumsauswahl wie unten:

const initialState = { 
    datePickers: { 
     "startDatePicker": { 
      activeDate: "8/25/2017", 
      disabledBefore: "", 
      linkedTo: "endDatePicker" 
     }, 
     "endDatePicker": { 
      activeDate: "", 
      disabledBefore: "8/25/2017" // This date is set when the user sets the active date in startDatePicker 
      linkedTo: "" 
     } 
    } 
} 

Dieses Szenario ein wenig interessant, weil eine Zustandsänderung in einer Eigenschaft in meinem Minderer ist eine Zustandsänderung in einem anderen auslösen. Dies ist nicht schwer zu tun und ich habe eine Art zu kontrollieren, wenn ich das Update mache.

Die Aktion für Behinderte sehen Daten Einstellung wie unten:

... 
case types.SET_DISABLED_DATES: 
    return Object.assign({}, state, 
     datePickers: Object.assign({}, state.datePickers, { 
      datePickers[action.datePickerId]: Object.assign({}, state.datePickers[action.datePickerId], { 
      disabledBefore: action.value 
      }) 
    }) 

Bitte denken Sie daran, dass ich kann und soll disabledBefore einstellen kann, auch wenn die Datumsauswahl als unabhängiger eines verwendet wird. Also, ich brauche meine SET_DISABLED_DATES in jedem Reducer.

Das Problem, das ich renne ist, dass, wenn ich SET_DISABLED_DATES aufrufen, bekomme ich Fehler in Reduzierungen, wo die Datumsauswahl als einzelne/unabhängige verwendet wird, da die Datumsauswahl-ID für das Paar nicht in der Reduzierung definiert ist.

Zum Beispiel, in projectsReducer kann ich die Datumsauswahl als Teil eines Paares so startDatePicker und endDatePicker sind definiert und alles funktioniert gut.

Aber ich kann eine einzelne Instanz Datumsauswahl in der tasksReducer verwenden, die auch auf den SET_DISABLED_DATES Aufruf reagiert, aber es schlägt fehl, weil es die endDatePicker nicht finden kann. In diesem Szenario reagiert die tasksReducer auf den Aufruf, den ich gemacht habe, um die disabledDates-Eigenschaft von endDatePicker in projectsReducer festzulegen.

ich diese beiden Fragen zu bereits gebucht haben und die einzige wirkliche Lösung, die ich hier bin zu sehen ist, dass ich einen Zustand, in meinem Minderer haben müssen, die wie folgt aussieht:

... 
case types.SET_DISABLED_DATES: 
    if(typeof state.datePickers[action.datePickerId] !== "undefined") { // Making sure that what I'm trying to update exists in the reducer 
     return Object.assign({}, state, 
     datePickers: Object.assign({}, state.datePickers, { 
      datePickers[action.datePickerId]: Object.assign({}, state.datePickers[action.datePickerId], { 
      disabledBefore: action.value 
      }) 
    }) 
    } else { 
     return state; 
    } 

Zugegeben, das sieht ein bisschen wie ein Klotz, aber ich konnte hier keine andere Lösung finden.

Auch hier ist das Problem, dass solange alle Reduzierungen auf SET_DISABLED_DATES reagieren, es garantiert ist, dass eine bestimmte Datumsauswahl nicht vorhanden ist und die Object.assign() einen Fehler auslöst.

Irgendwelche Vorschläge? Ist die einfache Bedingung im Reducer der Weg dorthin? Ist es ein Klotz?

P.S. Ich habe diesen Code ausprobiert und es funktioniert gut und behebt das Problem. Auf der einen Seite empfinde ich das als ein Anti-Pattern, aber auf der anderen Seite scheint es nur eine gute Idee zu sein, sicherzustellen, dass die Property, die ich in meinem Reducer aktualisieren möchte, existiert, bevor ich versuche, sie zu aktualisieren. Ich würde mich über Ihr Feedback freuen. Vielen Dank.

Antwort

0

Sie führen gerade eine grundlegende Validierung im Reduzierer durch, bevor Sie den Status setzen. Das ist völlig in Ordnung. Ich denke nicht, dass es eine gute Methode sein wird, das Geschäft im Aktionsersteller zu überprüfen, um zu verhindern, dass Aktionen auf Objekte, die sich nicht im Geschäft befinden, ausgeführt werden (wie würden Sie das sowieso machen!).

Was ich nicht verstehe ist, wie kann ein Datepicker mit einem anderen Datepicker verknüpft werden, der nicht im Laden ist? Vielleicht senden Sie eine create and teardown Aktion auf die didMount und willUnmount Komponente?

Ich kenne Ihre vollständigen Anforderungen nicht, aber ich denke, wir können es viel einfacher machen. Ich würde so etwas tun:

Shop:

{ 
    datePickers: { 
    id1: { 
     value: '', 
     minValue: '', 
     maxValue: '', 
    }, 
    id2: { 
     value: '', 
     minValue: '', 
     maxValue: '', 
    } 
    } 
} 

Nun, es sei denn, Sie irgendeine Art von gekoppelten Komponenten picker machen, die immer paarweise verhalten werden, glaube ich, der sauberste Ansatz wäre, gesetzt Der deaktivierte Wert im verknüpften Datumsauswahlpunkt in der mapDispactchToProps-Funktion in Ihrer übergeordneten Komponente.

Hier würden Sie id s auf die Komponenten setzen, und Sie wissen genau, welche Komponente vor einer anderen deaktiviert werden sollte.

Etwas wie:

dispatch => ({ 
    setArrivalDate(value) { 
    dispatch(datePickerActions.setValue(arrivalDateId, value); 
    dispatch(datePickerActions.setMaxValue(depatureDateId, value); 
    }, 
    setDepatureDate(value) { 
    dispatch(datePickerActions.setValue(depatureDateId, value); 
    dispatch(datePickerActions.setMinValue(arrivalDateId, value); 
    } 
}) 

Dies kann nicht abstrakt genug sein, aber es ist sauber.

Sie könnten das gleiche tun, wenn Sie eine gepaarte Komponente haben, aber Sie müssen immer noch wissen, welches Datum vor dem anderen steht. Es wäre mühsam, eine generische Abstraktion zu machen.

+0

Nicht 100 % klar über das, was du meinst "setze den deaktivierten Wert in der ** liniked date picker **, aber wenn ich dich richtig verstehe, mache ich das sowieso. Jede Datumsauswahl muss die Daten enthalten, die dazu gehören. Deaktivierte Daten gehören in den "endDatePicker", also sind sie dort gespeichert. Key hier ist se Wenn Sie das Datum in "startDatePicker" eingeben, wird das deaktivierte Datum in "endDatePicker" gesetzt. Ich kontrolliere das gut in meiner Handler-Funktion. Ich überprüfe einfach, ob es einen Wert in der Eigenschaft 'linkedTo' von 'startDatePicker' gibt. Wenn ja, rufe ich meinen Aktions-Ersteller auf, um deaktivierte Daten in 'endDatePicker' zu setzen. – Sam

+0

Jede Datumsauswahl erhält ihre eigene eindeutige ID in einem Reduzierstück. Wenn Sie sich meinen Code ansehen, enthält das Objekt "datePickers" alle Datumsauswahlelemente, die in diesem speziellen Reduzierer definiert sind. 'startDatePicker' und' endDatePicker' sind die Id's. Dort könnte es sogar noch mehr Date Pickers geben. Der Teil, mit dem du zu kämpfen hast, ist folgender: Der Code, den ich in meinen Beitrag geschrieben habe, ist für "reduzierer1", in dem ich sowohl "startDatePicker" als auch "endDatePicker" gepaart habe. In 'reduzierer2' kann ich 'reservationDatePicker' haben, das NICHT gepaart ist. Ich habe immer noch die "SET_DISABLED_DATES" in "Reducer2", so reagiert es und gibt Fehler. – Sam

+0

Es ist auf der Suche nach 'endDatePicker' zu aktualisieren, weil das ist, was in 'action.datePickerId' ist, aber 'endDatePicker' ist nicht definiert in 'reducer2'. Die einzige Datumsauswahl in 'reduzierer2' ist' reservationDatePicker'. Da kommt der Fehler. – Sam

0

den fett gedruckten Teil im Code unten

... 
    case types.SET_DISABLED_DATES: 
     if(typeof state.datePickers[action.datePickerId] !== "undefined") { // Making sure that what I'm trying to update exists in the reducer 
      return Object.assign({}, state, 
      datePickers: Object.assign({}, state.datePickers, { 
       datePickers[action.datePickerId]: Object.assign({}, state.datePickers[action.datePickerId], { 
       disabledBefore: action.value 
       }) 
     }) 
     } else { 
      return state; 
     }

Auch ein wenig es6 Spread und ein Helfer Schaltschrankbau Funktion macht viel dieser Code lesbarer entfernen.

const newReducer = (state = defaultState, action) => switchcase({ 
    [types.SET_DISABLED_DATES]: 
    state.datePickers[action.datePickerId] === undefined 
     ? state 
     : ({ ...state, 
     datePickers: { ...state.datePickers, 
      [action.datePickerId]: { ...state.datePickers[action.datePickerId], 
      disabledBefore: action.value, 
      }, 
     }, 
     }), 
})(state)(action.type); 

Mit lodash/fp/set, der Code

const reducerWithLodash = (state = defaultState, action) => 
switchcase({ 
    [types.SET_DISABLED_DATES]: 
    state.datePickers[action.datePickerId] === undefined 
     ? state 
     : set({...state}, `datePickers.${action.datePickerId}.disabledBefore`, action.value) 
})(state)(action.type) 

wird ich nicht die lodash Version getestet haben, so nehmen Sie bitte, dass mit einem Körnchen Salz (Dan Abramov scheint approve)

+0

Sie machen immer noch die grundlegende Überprüfung, um sicherzustellen, dass die Eigenschaft, die ich versuche zu aktualisieren, in dem Reducer ist, was meine Frage ist. Ich denke, Sie bieten nur einige Verbesserungen der Lesbarkeit. – Sam

+0

Ah, ich verstehe es jetzt. lodash/fp/set erstellt den Pfad, wenn er nicht existiert. Vielleicht können Sie die Implementierung ändern, um nicht existierende Pfade zu ignorieren. – jaihindhreddy

+0

Ich habe in letzter Zeit mit Redux gearbeitet, und ich fand, dass es besser funktioniert, wenn Ihre Zustandsform statisch ist und Ihr Render nur auf dem Statusinhalt basiert, und nicht in der Form ändert. Zum Beispiel können Sie, anstatt basierend auf einer vorhandenen Eigenschaft zu rendern, immer ein leeres Objekt und eine andere boolesche Eigenschaft angeben, die angibt, ob das Objekt gerendert werden soll. – jaihindhreddy