如何从 React 组件的状态对象中删除属性

问题描述 投票:0回答:11

如果我有一个 React 组件,并且在其状态上设置了属性:

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

是否可以从

"foo"
中删除这里的
Object.keys(this.state)

replaceState方法看起来是显而易见的尝试方法,但它已被弃用。

reactjs state
11个回答
41
投票
您可以将

foo

 设置为 
undefined
,就像这样 

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



更新

之前的解决方案只是从

foo

中删除值,
key
技能存在于
state
中,如果您需要从
state
中完全删除密钥,可能的解决方案之一可以是
setState
与一个父母
key
,就像这样

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>


35
投票
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> ); } });
    

7
投票
在 GitHub 上的 React 源代码中的

ReactCompositeComponent.js

中有一个名为 
_processPendingState
 的方法,这是通过调用 component.setState 实现合并状态的终极方法;

``` _processPendingState:函数(道具,上下文){ var inst = this._instance; var 队列 = this._pendingStateQueue; var 替换 = 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); } } }

```

在该代码中,您可以看到实现合并的实际行;

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

此函数中没有任何地方调用

delete

 或类似函数,这意味着这不是真正想要的行为。另外,完全复制 stat、删除属性并调用 setState 将不起作用,因为 setState 始终是合并,因此删除的属性将被忽略。 

另请注意,setState 不会立即起作用,而是批量更改,因此如果您尝试克隆整个状态对象并仅进行一项属性更改,则可能会擦除之前对 setState 的调用。正如 React 文档所说;

React 可能会将多个 setState() 调用批处理为单个更新以提高性能。

因为 this.props 和 this.state 可能会异步更新,所以你不应该依赖它们的值来计算下一个状态。

您实际上可以做的是添加更多信息;

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

这是丑陋的,当然,但它为您提供了区分设置为未定义的值和根本未设置的值所需的额外信息。另外,它可以很好地处理 React 的内部结构、事务、状态更改批处理和任何其他可怕的事情。最好在这里采取一些额外的复杂性,而不是尝试事后猜测 React 的内部结构,其中充满了诸如事务协调、管理诸如替换状态之类的弃用功能等可怕的事情


4
投票
之前的解决方案 - 是反模式,因为它改变了 this.state。错了!

使用这个(旧方法):

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

或者使用ES6糖:

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

很甜蜜,不是吗? ))

在旧的 React 语法(原始语法,不是 ES6)中,它有

this.replaceState

,可以删除存储中不必要的键,但现在它已被 
弃用了


4
投票
当我们使用

undefined

null
 删除属性时,我们实际上并没有删除它。因此,对于 Javascript 对象,我们应该在属性之前使用 
delete
 关键字:

//The original object: const query = { firstName:"Sarah", gender: "female" }; //Print the object: console.log(query); //remove the property from the object: delete query.gender; //Check to see the property is deleted from the object: console.log(query);

但是,在 React Hooks 中,我们使用钩子,上述方法可能会导致一些错误,特别是当我们在状态更改时使用效果来检查某些内容时。为此,我们需要在删除属性后设置状态:

import { useState, useEffect } from "react"; const [query, setQuery] = useState({firstName:"Sarah", gender:"female"}); //In case we do something based on the changes useEffect(() => { console.log(query); }, [query]); //Delete the property: delete query.gender; //After deleting the property we need to set is to the state: setQuery({ ...query });
    

2
投票
您可以使用

Object.assign

 在正确的深度制作应用程序状态的浅表副本,并从副本中删除该元素。然后使用 setState
 将修改后的副本合并回应用程序的状态。

这不是一个完美的解决方案。像这样复制整个对象可能会导致性能/内存问题。

Object.assign

的浅复制有助于减轻内存/性能问题,但您还需要了解新对象的哪些部分是副本以及哪些部分是对应用程序状态中数据的引用。

在下面的示例中,修改

ingredients

 数组实际上会直接修改应用程序状态。

将不需要的元素的值设置为

null

undefined
 不会将其删除。

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>


0
投票
唯一的方法是创建一个深层副本,然后从深层克隆中删除该属性,并从 setState 更新器函数返回深层克隆

this.setState(prevState => { const newState = { formData: { ...prevState.formData, document_details: { ...prevState.formData.document_details, applicant: { ...prevState.formData?.document_details?.applicant keyToBeDeleted: dummVAlue //this is redundant } } } }; delete newState.formData.document_details.applicant.keyToBeDeleted; return newState; });
    

0
投票
使用

dot-prop-immutable

import dotPropImmutable from "dot-prop-immutable"; onClick() { this.setState( dotPropImmutable.delete(this.state, 'foo') ); }
    

-1
投票
如果您想完全重置状态(删除大量项目),可以使用以下方法:

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

使用

setState

 的这种变体允许您在通话期间访问整个状态,而 
this.state
 可能有点过时(由于之前的 
setState
 通话尚未完全处理)。


-1
投票
我认为这是一个很好的方法=>

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

-1
投票
如果删除是在函数中并且键需要是变量,请尝试以下操作:

removekey = (keyname) => { let newState = this.state; delete newState[keyname]; this.setState(newState) // do not wrap the newState in additional curly braces } this.removekey('thekey');

与史蒂夫的答案几乎相同,但是在一个函数中。

© www.soinside.com 2019 - 2024. All rights reserved.