Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Replace object in array on react state

This question might fall a little on the side of a "best practice" question, but please bear with me.

Here is a portion of my state:

this.state = {
  typeElements: {
    headers: [
        {
          name: "h1",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }, {
          name: "h2",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }, {
          name: "h3",
          size: 70,
          lineHeight: 1.25,
          kearning: 0,
          marginAfter: 0
        }...

What I need to do is REPLACE the object at a given index on the headers array.

I don't know how to do that with the setState method as in this.setState(headers[1] = {obj}) - but that's obviously invalid. My current method is creating a new array and clobbering the old one like this:

_updateStyle(props) {
  let newState = Object.assign({}, this.state)
  newState.typeElements.headers[props.index] = props
  this.setState(newState)
};

For my small hacky project I guess it's OK but I feel like this is super heavy handed and would quickly lead to performance issues at any kind of scale.

like image 986
motleydev Avatar asked Oct 06 '16 06:10

motleydev


Video Answer


1 Answers

Updated: since this answer still gets upvotes, be aware that the previous answer below is outdated with modern JavaScript and React. The "update" addon is now legacy and "immutability-helper" can be used instead.

The React docs also mention why immutability is important so avoid mutating state. For immutable updates you can use Object.assign() or spread syntax which needs to be done for every level of nesting, like in this example the nested headers object and its array elements. In this particular example we can use the array index as key so it's possible to also use the spread operator to make a shallow clone of the array and assign a new object as value at given index in the cloned array.

_updateStyle (props) {
  const { typeElements } = this.state;
  const updatedHeaders = [...typeElements.headers];
  updatedHeaders[props.index] = props;
  this.setState({
    ...this.state,
    typeElements: {
      ...typeElements,
      headers: updatedHeaders
    }
  ));
}

Another solution which doesn't require the spread syntax and is needed if we are not using the array index to find the object we want to replace, is using array.map to create a new array and returning the new object instead of the old one at given index.

  const updatedHeaders = typeElements.headers.map((obj, index) => {
    return index === props.index ? props : obj;
  });

Similar examples in the Redux docs also explain "immutable update patterns".

React has some immutability helpers for this, which is explained in the docs: https://facebook.github.io/react/docs/update.html

In your case you could use the $splice command to remove one item and add the new one at given index, for example:

_updateStyle (props) {
  this.setState(update(this.state.typeElements, 
    { $splice: [[props.index, 1, props]] }
  ));
}
like image 129
Robin Venneman Avatar answered Sep 28 '22 04:09

Robin Venneman