0

class Example extends React.Component{
    constructor(props){
        super(props);
        this.state = {
          array: [{n: 0}, {n: 1}, {n: 2}]
        }
    }
    
    selectObjectFromArray = index => {
      this.setState({
        array: //???
      })
    }

We only know the index, where we want to edit the object in the array. We can't do like this.state.array[1] = ..., and we can't do setState({array[1]:.... I was considered about spread like: array: [...this.state.array,, but in this situation, we can't set, where we want to edit. So what can we do in this situation?

3
  • Why do you feel that you can't insert by index? If it's a mutable issue, make a copy of the array first using [...array] or array.slice(0) Commented Jun 13, 2018 at 15:17
  • Why don't you add an answer with an example? Commented Jun 13, 2018 at 15:23
  • I was on the train at the time :P. Was going to answer it later, but OP has been given an adequate solution. Not how I would have done it, but it gets the job done. Commented Jun 13, 2018 at 16:43

2 Answers 2

1

We only know the index, where we want to edit the object in the array

Given a knownIndex

this.setState({
  array:
    [ ...this.state.array.slice (0, knownIndex)  // <-- items up to the index
    , someUpdate(this.state.array[knownIndex]))  // <-- updated object
    , ...this.state.array.slice (knownIndex + 1) // <-- items after the index
    ]
})

Another way you could do it is using the Array .map function. Let's also make it a generic function

const updateAtIndex = (xs, i, f) =>
  xs .map ((x, j) => i === j ? f (x) : x)

In your component, you can use it like this

this.setState ({
  array: updateAtIndex (this.state.array, knownIndex, f)
})

Where f is some function to update the object, for example

// returns a new object with the n property doubled
const f = obj =>
  ({ n: obj.n * 2 })

When writing generic functions, I like to make them a little more robust. If you use this technique in your program, I would recommend a few changes to the functions above. These changes communicate the parameter types more effectively and allow the reader to better infer the functions return type.

const identity = x =>
  x

const updateAtIndex = (xs = [], i = 0, f = identity) =>
  xs .map ((x, j) => i === j ? f (x) : x)

const f = ({ n = 0 }) =>
  ({ n: n * 2 })
Sign up to request clarification or add additional context in comments.

Comments

1

To update a state-array, you have to create a copy of it, update some entries and push the new array back to the state.

Here's a simple example where the button updates the last item:

import React from "react";
import ReactDOM from "react-dom";

class Example extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      array: [{ n: 0 }, { n: 1 }, { n: 2 }]
    }
  }

  render() {
    return <div>

    <ul> {
      this.state.array.map((item,key) => {
        return <li key={key} >{item.n} </li>
      })
    }
    </ul>


    <button onClick={this.updateLast}>update first</button>
    </div>
  }

  updateLast = () => {
    this.selectObjectFromArray(this.state.array.length -1 )
  }

  selectObjectFromArray = index => {
    // create a copy of the array        
    let newArr = this.state.array;

    // the item variable is optional but hope clarifies how this works
    let item = newArr[index];    
    item = {
      n: item.n * 2
    }

    newArr[index] = item;

    // update the state with the new data
    this.setState({
      array: newArr
      })
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<Example />, rootElement);

This working example can also be found here: https://codesandbox.io/s/o4x6mpnozq

1 Comment

let newArr = this.state.array; does not make a copy of the array

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.