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

时间:2015-10-01 10:04:36

标签: reactjs state

如果我有一个反应组件,其状态设置为其状态:

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

是否可以从"foo"移除Object.keys(this.state)

replaceState方法看起来是一种显而易见的方法,但它已被折旧。

12 个答案:

答案 0 :(得分:19)

您可以将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

您也可以使用delete

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

但这很危险,因为此解决方案直接操作this.state

<强>更新

如果您需要从foo中完全删除密钥,之前的解决方案只会删除key中的值以及state中存在的 state 技能,一个可能的解决方案可以是setState,其中包含一个父 key ,就像这样

&#13;
&#13;
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'))
&#13;
<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>
&#13;
&#13;
&#13;

答案 1 :(得分:14)

以下代码将从var max_fields = 10; // maximum input boxes allowed var wrapper = $(".input_fields_wrap"); var add_button = $(".add_field_button"); var draggableOptions = { grid: [ 5, 5 ], snap: true } $(add_button).click(function(e) { e.preventDefault(); if (wrapper.find('.draggable').length < max_fields) { $('<div class="draggable ui-widget-content added">' + '<p>not draggable anymore, why ?</p>' + '<input type="text" name="mytext[]"/>' + '<a href="#" class="remove_field">x</a>' + '</div>').appendTo(wrapper).draggable(draggableOptions); // < important change here } }); $(wrapper).on("click", ".remove_field", function(e) { e.preventDefault(); $(this).parent('div').remove(); }) $(".draggable").draggable(draggableOptions); 移除foo而不直接改变this.state

this.state

您需要stage 3 preset才能生效。

答案 2 :(得分: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,可以删除商店中不必要的密钥,但现在它是deprecated

答案 3 :(得分:2)

在GitHub上的React源中的ReactCompositeComponent.js中有一个名为_processPendingState的方法,它是实现从调用到组件的合并状态的最终方法.setState;

```   _processPendingState:function(props,context){     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);
    }
  }
}

```

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

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的内部,交易,状态更改批处理以及任何其他恐怖都很好。最好在这里采取一些额外的复杂性,而不是试图反复猜测Reacts内部结构,这些内部结构充满了诸如事务协调之类的恐怖,管理了诸如replaceState之类的弃用功能等等。

答案 4 :(得分:1)

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

这不是一个完美的解决方案。像这样复制整个对象可能会导致性能/内存问题。 Object.assign的浅层副本有助于缓解内存/性能问题,但您还需要了解新对象的哪些部分是副本,哪些部分是对应用程序状态中数据的引用。

在下面的示例中,修改ingredients数组实际上会直接修改应用程序状态。

将不受欢迎的元素的值设置为nullundefined不会将其删除。

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>

答案 5 :(得分:0)

如果删除是在函数中并且键需要是变量,请尝试:

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

this.removekey('thekey');

与史蒂夫的答案几乎相同,但在一个功能中。

答案 6 :(得分:0)

如果您想完全重置状态(删除大量项目),则可以执行以下操作:

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

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

答案 7 :(得分:0)

我认为这是解决问题的好方法=>

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

答案 8 :(得分:0)

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

});

答案 9 :(得分:0)

唯一的方法是创建一个深层副本,然后从深层克隆中删除该属性,然后从setState updater函数返回深层克隆

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

答案 10 :(得分:0)

使用dot-prop-immutable

import dotPropImmutable from "dot-prop-immutable";

onClick() {
    this.setState(
       dotPropImmutable.delete(this.state, 'foo')
    );
}

答案 11 :(得分:0)

当我们使用 undefinednull 删除属性时,我们实际上并没有删除它。因此,对于 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 });
相关问题