2017-01-21 3 views
1

Als ReactJS Identifizierung (und andere Flußmittel Implementierungen, wie redux) empfohlen:Problem mit der minimalen Darstellung Zustand

https://facebook.github.io/react/docs/thinking-in-react.html#step-3-identify-the-minimal-but-complete-representation-of-ui-state

Wir should't einen Zustand zu halten, die aus anderen Zustand berechnet werden kann (wir nennen es abgeleitete Daten), andernfalls müssen wir, wenn wir einen Zustand setzen, einen anderen setzen.

Aber betrachten Sie das folgende Beispiel:

Es gibt 2 Zustände in meiner Seite

  1. Die Farbe der Ampel: Licht = rot/grün
  2. Gibt es Leute kommen auf der anderen seite: people = true (es gibt menschen)/false (menschenleer)

Wie wir wissen, können die Leute nicht über die Straße kommen, wenn die Ampel rot ist.

So, haben wir 3 normale kombinierten Zustände:

  1. Licht = grün und Menschen = true
  2. Licht = grün und Menschen = false
  3. Licht = rot und Menschen = falsch

Der andere Zustand light = red und people = true ist ungültig.

Wir berechnen Menschen = false wenn Licht = red, in diesem Fall Menschen ein abgeleiteten Daten von Licht sind. Aber wenn Licht = grün können wir nicht.

Das Problem ist, wenn ich den Licht Wert gesetzt, ich habe die Menschen Wert zu setzen, sonst wird es zu einem ungültigen Zustand führen kann.

So, wie um dieses Problem zu lösen? Wie gestalte ich meinen Staat?

Gibt es eine Bibliothek, die hilft, sie zu verwalten. Zuerst kann ich die Abhängigkeiten zwischen meinen Zuständen definieren. Die Bibliothek ist eine Antwort auf die Konsistenz von ihnen. Wenn ich einen Statuswert festlege, der im Konflikt mit anderen steht, werden andere auf den richtigen Wert geändert.

Ich habe ein einfaches Beispiel geschrieben, um zu zeigen, was ich will, gibt es eine solche Bibliothek?nur

class ComplexState { 
    constructor(config, initialState){ 
     this.config = config; 
     this.state = initialState; 

     this._checkAll(); 
    } 

    setState(key, value){ 
     var config = this.config[key]; 
     if(config && config.type === ComplexState.Types.Enum){ 
      //Set Enum data type 
      if(Array.isArray(config.definitionField) && config.definitionField.indexOf(value) !== -1 || 
       config.definitionField[value] && typeof config.definitionField[value].checker === 'function' && config.definitionField[value].checker(this.state)){ 
       //Set the value 
       this.state[key] = value; 
       //If there is a conflict, modify other values 
       Object.keys(this.state).forEach(_key => { 
        if(key === _key){//Self 
         return; 
        } 
        var _value = this.state[_key]; 
        var _config = this.config[_key]; 
        if(!Array.isArray(_config.definitionField) && _config.definitionField[_value] && typeof _config.definitionField[_value].checker === 'function' && !_config.definitionField[_value].checker(this.state)){ 
         //Conflict, adapt to correct value 
         this.state[_key] = _config.definitionField[_value].adapter(this.state); 
        } 
       }) 

       //Check for conflicts 
       this._checkAll(); 
      }else{ 
       //Invalid value 
      } 
     } 
    } 

    getState(){ 
     return Object.assign({}, this.state); 
    } 

    //Check for conflicts 
    _checkAll(){ 
     Object.keys(this.state).forEach(_key => { 
      var _value = this.state[_key]; 
      var _config = this.config[_key]; 
      if(!Array.isArray(_config.definitionField) && _config.definitionField[_value] && typeof _config.definitionField[_value].checker === 'function' && !_config.definitionField[_value].checker(this.state)){ 
       //Conflict 
       throw new Error('invalid state' + JSON.stringify(this.state)); 
      } 
     }) 
    } 
} 

ComplexState.Types = { 
    Enum : 0 
} 

es verwenden,

var myStates = new ComplexState({ 
    light : { 
     type : ComplexState.Types.Enum, 
     definitionField : ['red', 'green'] 
    }, 
    people : { 
     type : ComplexState.Types.Enum, 
     definitionField : { 
      'false' : null, 
      'true' : { 
       checker : function(state){ 
        return state.light !== 'red'; 
       }, 
       adapter : function(state){ 
        if(state.light === 'red'){ 
         return 'false'; 
        } 
        return state.people; 
       } 
      } 
     } 
    } 
}, { 
    light : 'Green', 
    people : 'false' 
}) 
console.log(myStates.getState());//{light: "Green", people: "false"} 
myStates.setState('people', 'true'); 
console.log(myStates.getState());//{light: "Green", people: "true"} 

//when I set light value to red, the people value is automatically set to false 
myStates.setState('light', 'red'); 
console.log(myStates.getState());//{light: "red", people: "false"} 
+0

Licht zu einem Bool, wo wahr ist grün und rot ist falsch, sollte dies zu lösen. Wenn Sie immer (Licht && Menschen) bewerten, dann ist der einzige wahre Wert, wenn das Licht grün ist und es Menschen gibt. – Chase

+0

Ich glaube, du hast missverstanden, was ich meine. Bewerten (Licht && Menschen) ist bedeutungslos, es ist kein Ausdruck. Sie sind nur zwei Zustände auf meiner Seite und können unabhängig voneinander eingestellt werden. Ich habe meine Beschreibung bearbeitet, um das Symbol & zu entfernen. – junhan

+0

Ich verstehe, aber was Sie suchen, ist, gibt es Menschen in der Kreuzung. Was möchten Sie tun, um jeden Wert unabhängig voneinander korrigieren zu können? 'sind da Leute in der Kreuzung 'sind die abgeleiteten Daten, die immer von (light && people) ausgewertet werden können. Jeder schützt den anderen, sodass Sie diese beiden Werte unabhängig voneinander in Ihrer App ändern können. Die einzigen zwei Statuswerte, die du brauchst, sind Licht und Menschen, solange du immer "Menschen in der Kreuzung" von dem Ausdruck (Licht && Menschen) ableitet. – Chase

Antwort

0

Wenn Sie seta Wert benötigen, wenn Sie ein anderes Stück Zustand versetzt Sie so etwas tun kann:

this.setState({ 
    light: someNewColor, 
    people: someNewColor === red ? false : this.state.people 
}); 

Wenn someNewColor ist rot, Leute werden automatisch auf falsch gesetzt. Ansonsten bleibt es der vorher eingestellte Wert.

edit:

Wenn Sie diese Reiniger machen wollen, würden Sie Menschen und Licht machen müssen völlig unabhängig. Bsp .:

this.setState({ 
    light: someNewColor 
}) 

Dies funktioniert derzeit nicht, weil Sie die Leute mit nur dem Licht nicht berechnen können.

+0

Das ist was ich vermeiden möchte, es ist nur so, als ob man 2 Zustände behalten würde: ein Array und seine Länge auf der Seite. 'this.setState ({ Liste: listOfArray, length: listOfArray.length });' Es kann einen inkonsistenten Zustand erzeugen, daher ein Fehler in meiner Seite führen. – junhan

+0

Das Problem ist, dass Leute es nicht völlig unabhängig ist. Es hat unabhängige Teile (wenn das Licht grün ist), ist aber auch abhängig von Licht (wenn es rot ist). Es gibt keine Möglichkeit, die Leute basierend auf dem Licht zu berechnen, also musst du beides behalten. Das ist bei diesem Setup kein Problem. In Ihrem Beispiel mit dem Array hängt die Länge vollständig vom Array ab, sodass Sie beide nicht benötigen. –

+0

Ich möchte eine Bibliothek suchen, um sie zu verwalten. Zuerst kann ich die Abhängigkeiten zwischen meinen Zuständen definieren. Die Bibliothek ist eine Antwort auf die Konsistenz meiner Zustände. Wenn ich einen Statuswert festlege, der im Konflikt mit anderen steht, werden andere auf den richtigen Wert geändert. Ich denke, es ist möglich, in der Theorie zu implementieren. – junhan

Verwandte Themen