webentwicklung-frage-antwort-db.com.de

Sauberere/kürzere Möglichkeit, den geschachtelten Zustand in Redux zu aktualisieren?

Manchmal werden Reduktionen etwas chaotisch:

const initialState = {
    notificationBar: {
        open: false,
    },
};

export default function (state = initialState, action) {
  switch (action.type) {
    case actions.LAYOUT_NOTIFICATIONBAR_OPEN:
      return Object.assign({}, state, {
        // TODO: Find a cleaner way to do this!
        notificationBar: Object.assign({}, state.notificationBar, {
          open: true,
        }),
      });
    default:
      return state;
  }
}

Gibt es einen knapperen Weg, dies zu tun?

28
ffxsam

UPD: Es ist jetzt Teil der ES2018

Es könnte durch eine nicht standardisierte etwas verbessert werden, aber die Eigenschaften verbreiten die Syntax :

return {
    ...state,
    notificationBar: {
        ...state.notificationBar,
        open: true,
    },
};
39
zerkms

Obwohl Sie den Spread-Operator verwenden können, gibt es viele andere Möglichkeiten, um dasselbe Ergebnis zu erzielen, ohne einen zukünftigen JS-Compiler für ein nicht standardisiertes Feature zu benötigen. Hier sind einige andere Optionen in keiner bestimmten Reihenfolge.

Geben Sie ein Literal zurück

Wenn Sie sicher sind, dass Ihr Status nicht wächst, können Sie den gesamten neuen Status einfach als Literal zurückgeben.

return {
  notificationBar: {
    open: true
  }
}

Dies ist jedoch oft nicht angemessen, da es unwahrscheinlich ist, dass Ihr Zustand so einfach ist.


Reduziergetriebe kombinieren

Redux bietet Ihnen eine nützliche Methode zum Kombinieren mehrerer Reduzierungen, die für verschiedene Teile des Statusobjekts verwendet werden. In diesem Fall würden Sie ein notificationBar-Reduzierstück erstellen, das dieses Objekt alleine behandelt.

 createStore(combineReducers({
   notificationBar: function(state=initialNBarState, action) {
     switch (action.type) {
       case actions.LAYOUT_NOTIFICATIONBAR_OPEN:
         return Object.assign({}, state, { open: true });
   }
 });

Dies verhindert, dass Sie sich um die oberste Ebene der Eigenschaften kümmern müssen, um das Verschachteln von Aufrufen in Object.assign zu vermeiden.

Wenn sich Ihr Staat logisch in klar definierte Abschnitte aufteilen lässt, ist dies wahrscheinlich der idiomatischste Weg, um dieses Problem zu lösen.


Verwenden Sie unveränderliche Daten

Sie können eine persistente Datenstrukturbibliothek verwenden, um Datenstrukturen zu erstellen, die geändert werden können, um eine Kopie zurückzugeben.

Mori

Mori ist das Ergebnis der Kompilierung der Datenstrukturen und der funktionalen API von Clojure in JS.

import { hashMap, updateIn } from 'mori';

const initialState = hashMap(
  "notificationBar", hashMap(
    "open", false
  )
);

// ...

return updateIn(state, ['notificationBar', 'open'], true);

ImmutableJS

ImmutableJS ist ein zwingenderer Ansatz, um die Semantik von Hash Array Mapped Tries aus Clojures persistenten Datenstrukturen auf Javascript zu bringen.

import { Map } from 'immutable';

const initialState = Map({
  notificationBar: Map({
    open: true
  });
});

// ...

return state.setIn(['notificationBar', 'open'], true);

Alias ​​Object.assign

Sie können eine freundlichere Version von Object.assign erstellen, um Terser-Versionen des obigen Codes zu schreiben. Tatsächlich kann es fast so knapp sein wie der ...-Operator.

function $set(...objects) {
  return Object.assign({}, ...objects);
}

return $set(state, {
  notificationBar: $set(state.notificationBar, {
    open: true,
  })
});

Verwenden Sie unveränderliche Helfer

Es gibt eine Reihe von Bibliotheken, die auch Anpassungshilfen anbieten, um Änderungen an regulierbaren veränderlichen Objekten vorzunehmen.

reagieren-addons-update

React hat seit langem eine Reihe von unabänderlichen Helfern. Sie verwenden eine ähnliche Syntax wie MongoDB-Abfragen.

import update from 'react-addons-update';

return update(state, {
  notificationBar: {
    open: { $set: true }
  }
});

dot-Prop-unveränderlich

Mit dieser Bibliothek können Sie vertraute Punktpfade verwenden, um Aktualisierungen für (verschachtelte) Eigenschaften anzugeben.

import dotProp from 'dot-prop-immutable';

return dotProp.set(state, 'notificationBar.open', true);

update-In

Diese Bibliothek ist ein Wrapper um react-addons-update und bietet eine funktionalere Syntax zum Aktualisieren (verschachtelter) Eigenschaften.

Anstatt einen neuen Wert zu übergeben, übergeben Sie eine Funktion, die den alten Wert übernimmt und einen neuen zurückgibt.

import updateIn from 'update-in';

return updateIn(state, ['notificationBar', 'open'], () => true);

unveränderlicher Pfad

Für die Aktualisierung von Eigenschaften ist diese Bibliothek eine Kreuzung zwischen dot-prop-immutable und update-in.

import path from 'immutable-path';

return path.map(state, 'notificationBar.open', () => true);
45
Dan Prince

Sie können Linsen verwenden.

import { set, makeLenses } from '@DrBoolean/lenses'

const L = makeLenses(['notificationBar', 'open']);
const notificationBarOpen = compose(L.notificationBar, L.open)
const setNotificationBarOpenTrue = set(notificationBarOpen, true)

const a = { notificationBar: { open: false } }
const b = setNotificationBarOpenTrue(a) 
// `a` is left unchanged and `b` is `{ notificationBar: { open: true } }`

Sie können sich Objektive als Zugriff/Update von kompositorischen Eigenschaften vorstellen.

Einige gute Ressourcen zu Objektiven:

Wenn Sie mit dem Lesen von lisps zufrieden sind, würde ich Ihnen auch empfehlen, sich diese hervorragende Einführung in Linsen von Racket-Dokumente anzusehen. Wenn Sie tiefer gehen möchten und mit dem Lesen von haskell zufrieden sind, können Sie Folgendes beobachten: Objektive - kompositioneller Datenzugriff und -bearbeitung .

6
Safareli

Wenn Sie Immutable.js verwenden, können Sie unter Nested Structures - Thema einige Funktionen anzeigen, die Ihnen helfen können. Ich verwende persönlich mergeDeep:

prevState.mergeDeep({ userInfo: {
  username: action.payload.username,
} }),
1
Ricardo Mutti

Alle Ratschläge hier sind großartig und gültig, aber ich möchte eine andere Lösung anbieten. Das Problem, das hier auftritt, ist definitiv ein allgemeines Muster. Ich denke, es ist viel besser, nur ein eigenes Interface für solche Aktualisierungen zu schreiben und in Reduzierern zu bleiben und eine einzige Funktion zu verwenden, um tief in allen Reduzierern zu aktualisieren.

Zum Beispiel Ich habe eine Bibliothek erstellt , in der ich versucht habe, dieses Problem auf die nächste Weise anzugehen: Ich bekomme den Typ des Moduls (so genannte "Kacheln"), Funktion zum Ausführen von Operationen (sowohl asynchron als auch synchron) und gewünschte Verschachtelung basierend auf übergebenen Parametern. Für Ihren Fall wird es also so aussehen:

import { createSyncTile } from 'redux-tiles';
const uiTile = createSyncTile({
  type: ['ui', 'elements'],
  fn: ({ params }) => params,
  // type will be `notificationBar`
  nesting: ({ type }) => [type],
});

Und das ist es - es wird ein korrektes Schachteln durchgeführt. Tile stellt auch Selektoren zur Verfügung, damit Sie sich nicht persönlich Sorgen machen müssen, wo genau sich Daten befinden. Sie können sie einfach verwenden .. So möchte ich nicht sagen, dass es die beste Lösung ist, aber die Idee ist hübsch einfach - scheuen Sie sich nicht, Ihre eigene Implementierung zu schreiben, und verwenden Sie dann factory, um dieses Problem zu lösen.

0
Bloomca

Zusätzlich zu dem zuvor Gesagten gibt es hier einen funktionalen Weg mit Ramda :

import { assocPath } from 'ramda';

const o1 = { a: { b: { c: 1 }, bb: { cc: 22 } } };
const o2 = assocPath(['a', 'b', 'c'])(42)(o1);
console.log(o1 !== o2, o1.a !== o2.a); // new copies of "changed" objects
console.log(o1.a.bb === o2.a.bb); // deep unchanged properties are copied by reference
0
aeldar