wake-up-neo.net

Wie kann ich ein Attribut aus dem Statusobjekt einer React-Komponente entfernen?

Wenn ich eine React-Komponente habe, für die eine Eigenschaft festgelegt wurde, gilt Folgendes:

onClick() {
    this.setState({ foo: 'bar' });
}

Kann "foo" hier von Object.keys(this.state) entfernt werden?

Die Methode replaceState sieht aus wie die naheliegendste Methode, die jedoch ausprobiert wurde.

17
Joshua

Sie können foo wie folgt auf undefined setzen 

var Hello = React.createClass({
    getInitialState: function () {
        return {
            foo: 10,
            bar: 10
        }
    },

    handleClick: function () {
        this.setState({ foo: undefined });
    },

    render: function() {
        return (
            <div>
                <div onClick={ this.handleClick.bind(this) }>Remove foo</div>
                <div>Foo { this.state.foo }</div>
                <div>Bar { this.state.bar }</div>
            </div>
        );
    }
});

Example

Sie können auch delete verwenden, 

delete this.state.foo;
this.setState(this.state);

dies ist jedoch gefährlich, da diese Lösung diesen Zustand direkt manipuliert

Update

Die vorherige Lösung entfernt nur den Wert aus foo und die Fertigkeit key ist in state vorhanden. Wenn Sie den Schlüssel vollständig aus state entfernen müssen, kann eine der möglichen Lösungen setState mit einem übergeordneten key sein

var Hello = React.createClass({
  getInitialState: function () {
    return {
      data: {
        foo: 10,
        bar: 10
      }
    }
  },
    	
  handleClick: function () {
    const state = {
      data: _.omit(this.state.data, 'foo')
    };
    
    this.setState(state, () => {
      console.log(this.state);
    });
  },
        
  render: function() {
    return (
      <div>
        <div onClick={ this.handleClick }>Remove foo</div>
        <div>Foo { this.state.data.foo }</div>
        <div>Bar { this.state.data.bar }</div>
      </div>
    );
  }
});

ReactDOM.render(<Hello />, document.getElementById('container'))
<script src="https://cdn.jsdelivr.net/lodash/4.17.4/lodash.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="container"></div>

18
Alexander T.

Der folgende Code entfernt foo von this.state, ohne this.state direkt zu verändern:

const {foo, ...state} = this.state;
this.setState({state});

Sie benötigen die Voreinstellung Stufe 3 , damit dies funktioniert.

12
Distortum

Vorherige Lösung - ist antipattern, weil sie diesen Zustand ändert. Es ist falsch!

Verwenden Sie diesen (alten Weg):

let newState = Object.assign({}, this.state) // Copy state
newState.foo = null // modyfy copyed object, not original state
// newState.foo = undefined // works too
// delete newState.foo // Wrong, do not do this
this.setState(newState) // set new state

Oder verwenden Sie ES6-Zucker:

this.setState({...o, a:undefined})

Ziemlich süß, nicht wahr? ))

In der alten React-Syntax (original, nicht ES6) hat dies this.replaceState, der unnötige Schlüssel im Speicher entfernt, aber jetzt ist deprecated

3
MiF

In ReactCompositeComponent.js in der React-Quelle von GitHub befindet sich eine Methode mit dem Namen _processPendingState. Dies ist die ultimative Methode, die den Zusammenführungszustand von Aufrufen nach component.setState implementiert.

`` ` _processPendingState: Funktion (Requisiten, Kontext) { var inst = this._instance; var queue = this._pendingStateQueue; var replace = this._pendingReplaceState; this._pendingReplaceState = false; this._pendingStateQueue = null;

if (!queue) {
  return inst.state;
}

if (replace && queue.length === 1) {
  return queue[0];
}

var nextState = replace ? queue[0] : inst.state;
var dontMutate = true;
for (var i = replace ? 1 : 0; i < queue.length; i++) {
  var partial = queue[i];
  let partialState = typeof partial === 'function'
    ? partial.call(inst, nextState, props, context)
    : partial;
  if (partialState) {
    if (dontMutate) {
      dontMutate = false;
      nextState = Object.assign({}, nextState, partialState);
    } else {
      Object.assign(nextState, partialState);
    }
  }
}

`` `

In diesem Code können Sie die tatsächliche Zeile sehen, die die Zusammenführung implementiert.

nextState = Object.assign({}, nextState, partialState);

Nirgendwo in dieser Funktion gibt es einen Aufruf von delete oder ähnlichem, was bedeutet, dass es nicht wirklich beabsichtigtes Verhalten ist. Das vollständige Kopieren der Statistik, das Löschen der Eigenschaft und das Aufrufen von setState funktionieren nicht, da setState immer eine Zusammenführung ist. Die gelöschte Eigenschaft wird also einfach ignoriert. 

Beachten Sie auch, dass setState nicht sofort funktioniert, aber Batches geändert werden. Wenn Sie also versuchen, das gesamte Statusobjekt zu klonen und nur eine Eigenschaftsänderung vorzunehmen, können Sie frühere Aufrufe von setState übergehen. Wie das React-Dokument sagt:

React kann mehrere setState () - Aufrufe zur Leistungssteigerung in einem einzigen Update zusammenfassen.

Da this.props und this.state asynchron aktualisiert werden, sollten Sie sich bei der Berechnung des nächsten Status nicht auf deren Werte verlassen.

Was Sie in Betracht ziehen könnten, ist, tatsächlich weitere Informationen hinzuzufügen.

this.setState({ xSet: true, x: 'foo' });
this.setState({ xSet: false, x: undefined });

Dies ist zwar hässlich, aber es gibt Ihnen die zusätzlichen Informationen, die Sie zur Unterscheidung zwischen einem undefinierten Wert und einem überhaupt nicht festgelegten Wert benötigen. Außerdem spielt es Nice mit Reacts Interna, Transaktionen, Batching von Statusänderungen und anderem Horror. Es ist besser, etwas mehr Komplexität in Kauf zu nehmen, als zu versuchen, Reacts-Interna zu überdenken, die voll von Horror wie Transaktionsabgleich, verwalteter Funktionen wie "replaceState" usw. sind

2
Steve Cooper

Sie können Object.assign verwenden, um eine flache Kopie des Status Ihrer Anwendung in der richtigen Tiefe zu erstellen und das Element aus Ihrer Kopie zu löschen. Verwenden Sie dann setState , um Ihre geänderte Kopie wieder in den Status der Anwendung einzubinden.

Dies ist keine perfekte Lösung. Das Kopieren eines gesamten Objekts wie dieses kann zu Leistungs-/Speicherproblemen führen. Die flache Kopie von Object.assign hilft, die Bedenken hinsichtlich Arbeitsspeicher und Leistung zu verringern, Sie müssen jedoch auch wissen, welche Teile Ihres neuen Objekts Kopien sind und welche Teile Verweise auf Daten im Anwendungsstatus sind.

In dem folgenden Beispiel würde das Ändern des Arrays ingredients tatsächlich den Anwendungsstatus direkt ändern.

Wenn Sie den Wert des unerwünschten Elements auf null oder undefined setzen, wird es nicht entfernt.

const Component = React.Component;

class App extends Component {
  constructor(props) {
    super(props);
    this.state = {
      "recipes": {
        "1": {
          "id": 1,
          "name": "Pumpkin Pie",
          "ingredients": [
            "Pumpkin Puree",
            "Sweetened Condensed Milk",
            "Eggs",
            "Pumpkin Pie Spice",
            "Pie Crust"
          ]
        },
        "2": {
          "id": 2,
          "name": "Spaghetti",
          "ingredients": [
            "Noodles",
            "Tomato Sauce",
            "(Optional) Meatballs"
          ]
        },
        "3": {
          "id": 3,
          "name": "Onion Pie",
          "ingredients": [
            "Onion",
            "Pie Crust",
            "Chicken Soup Stock"
          ]
        },
        "4": {
          "id": 4,
          "name": "Chicken Noodle Soup",
          "ingredients": [
            "Chicken",
            "Noodles",
            "Chicken Stock"
          ]
        }
      },
      "activeRecipe": "4",
      "warningAction": {
        "name": "Delete Chicken Noodle Soup",
        "description": "delete the recipe for Chicken Noodle Soup"
      }
    };
    
    this.renderRecipes = this.renderRecipes.bind(this);
    this.deleteRecipe = this.deleteRecipe.bind(this);
  }
  
  deleteRecipe(e) {
    const recipes = Object.assign({}, this.state.recipes);
    const id = e.currentTarget.dataset.id;
    delete recipes[id];
    this.setState({ recipes });
  }
  
  renderRecipes() {
    const recipes = [];
    for (const id in this.state.recipes) {
      recipes.Push((
        <tr>
          <td>
            <button type="button" data-id={id} onClick={this.deleteRecipe}
            >&times;</button>
          </td>
          <td>{this.state.recipes[id].name}</td>
        </tr>
      ));
    }
    return recipes;
  }
                
  render() {
    return (
      <table>
        {this.renderRecipes()}
      </table>
    );
  }
}

ReactDOM.render(<App />, document.getElementById('app'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<main id="app"></main>

1
Vince

Wenn sich das Entfernen in einer Funktion befindet und der Schlüssel eine Variable sein muss, versuchen Sie Folgendes:

removekey = (keyname) => {
    let newState = this.state;
    delete newState[keyname];
    this.setState({ newState })
}

this.removekey('thekey');

Fast das gleiche wie die Antwort von Steve, aber in einer Funktion.

0
Taj Virani
var Hello = React.createClass({
getInitialState: function () {
    return {
        foo: 10,
        bar: 10
    }
},

handleClick: function () {
    let state = {...this.state};
    delete state.foo;
    this.setState(state);
},

render: function() {
    return (
        <div>
            <div onClick={ this.handleClick.bind(this) }>Remove foo</div>
            <div>Foo { this.state.foo }</div>
            <div>Bar { this.state.bar }</div>
        </div>
    );
}

});

0
GAURAV

Ich denke, das ist ein schöner Weg, um darüber zu gehen =>

//in constructor
let state = { 
   sampleObject: {0: a, 1: b, 2: c }
}

//method
removeObjectFromState = (objectKey) => {
   let reducedObject = {}
   Object.keys(this.state.sampleObject).map((key) => {
      if(key !== objectKey) reducedObject[key] = this.state.sampleObject[key];
   })
   this.setState({ sampleObject: reducedObject });
}
0
Robi Moller

Wenn Sie den Status vollständig zurücksetzen möchten (eine große Anzahl von Elementen entfernen), funktioniert Folgendes:

this.setState(prevState => {
    let newState = {};
    Object.keys(prevState).forEach(k => {
        newState[k] = undefined;
    });
    return newState;
});

Wenn Sie diese Variante von setState verwenden, können Sie während des Anrufs auf den gesamten Status zugreifen, während this.state etwas veraltet sein könnte (weil setState-Aufrufe der vorherigen Version noch nicht vollständig verarbeitet wurden).

0
Malvineous