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.
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>
);
}
});
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>
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.
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
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
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}
>×</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>
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.
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>
);
}
});
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 });
}
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).