score:36

Accepted answer

You can set foo to undefined, like so

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

Update

The previous solution just remove value from foo and key skill exists in state, if you need completely remove key from state, one of possible solution can be setState with one parent key, like so

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>

score:-1

If the removal is in a function and the key needs to be a variable, try this :

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

this.removekey('thekey');

Almost the same as steve's answer, but in a function.

score:-1

If you want to completely reset the state (removing a large number of items), something like this works:

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

Using this variant of setState allows you to access the whole state during the call, whereas this.state could be a little out of date (due to prior setState calls not yet having been fully processed).

score:-1

I think this is a nice way to go about it =>

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

score:0

Only way is to create a deep copy and then delete that property from the deep clone and return the deep clone from the setState updater function

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

score:0

Use dot-prop-immutable

import dotPropImmutable from "dot-prop-immutable";

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

score:2

You can use Object.assign to make a shallow copy of your application's state at the correct depth and delete the element from your copy. Then use setState to merge your modified copy back into the application's state.

This isn't a perfect solution. Copying an entire object like this could lead to performance / memory problems. Object.assign's shallow copy helps to alleviate the memory / performance concerns, but you also need to be aware of which parts of your new object are copies and which parts are references to data in the application state.

In the example below, modifying the ingredients array would actually modify the application state directly.

Setting the value of the undesired element to null or undefined doesn't remove it.

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>

score:2

When we use undefined or null to remove a property, we actually do not remove it. Thus, for a Javascript object we should use the delete keyword before the property:

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

However, in React Hooks we use hooks and the above method might cause some bugs especially when we use effects to check something when the state changes. For this, we need to set the state after removing a property:

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

score:3

Previous solution - is antipattern, because it change this.state. It is wrong!

Use this (old way):

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

Or use ES6 sugar:

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

Pretty sweet, don't you? ))

In old React syntax (original, not ES6), this has this.replaceState, that remove unnecessary keys in store, but now it is deprecated

score:6

In ReactCompositeComponent.js in the React source on GitHub is a method called _processPendingState, which is the ultimate method which implements merging state from calls to component.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);
    }
  }
}

```

In that code you can see the actual line that implements the merge;

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

Nowhere in this function is there a call to delete or similar, which means it's not really intended behaviour. Also, completely copying the stat, deleting the property, and calling setState won't work because setState is always a merge, so the deleted property will just be ignored.

Note also that setState does not work immediately, but batches changes, so if you try to clone the entire state object and only make a one-property change, you may wipe over previous calls to setState. As the React document says;

React may batch multiple setState() calls into a single update for performance.

Because this.props and this.state may be updated asynchronously, you should not rely on their values for calculating the next state.

What you could look to do is actually add more info;

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

This is ugly, granted, but it gives you the extra piece of info you need to differentiate between a value set to undefined, and a value not set at all. Plus it plays nice with React's internals, transactions, state change batching, and any other horror. Better to take a bit of extra complexity here than try to second-guess Reacts internals, which are full of horrors like transaction reconciliation, managing deprecated features like replaceState, etc

score:30

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

});


Related Query

More Query from same tag