2

So I'm new to React. I'm trying to use the function map to give an id to an array of objects in the state of a Component. But when I iterate over the objects in the function, the resulting array's elements are all equal to each other, which are equal to the last one iterated. I'm using the uuid module to add the unique ids. This is what I have inside the Component, with a better explanation inside comments:

constructor() {
  super()
  this.state = {
    classes: Array(5).fill({
      id: null,
      name: null
    }),
  }
}

componentWillMount() {

  // This console.log, strangely, logs the state of the Component as if
  // this componentWillMount function had already been executed, showing the
  // classes with their ids (still the wrong ones). Would appreciate it if
  // someone explained that
  console.log(this.state.classes)

  let classThings = this.state.classes.map(classObject => {
    let obj = classObject
    obj.id = uuid.v4()
    // This logs the object correctly. The console shows, thanks to this,
    // five different objects with five different ids
    console.log(obj)
    return obj
  })

  this.setState({
    classes: classThings
  })

  // But, for some reason, this one logs the array and all the elements
  // inside are equal to te last one logged by the previous console.log 
  // that is inside the map function, when it should log an array with the
  // five different elements
  console.log(classThings)
}

Any help would be greatly appreciated. Thanks.

2
  • Array#fill is setting all of the elements in the array to the same object, so the most recent change will be what the object contains. Commented Dec 28, 2017 at 18:37
  • @4castle thanks for the response. But I'm only using it once in the constructor, it would affect even if I'm using setState precisely for all of them not to be equal? Commented Dec 28, 2017 at 18:43

2 Answers 2

1

Every element in your array classes point to the same object (because Array.fill just sets every element in the array to the single object you passed it), so when you make a change to any object in classes, you're changing every object in classes. You can use map to create a new object for each element instead:

Replace

Array(5).fill({
   id: null,
   name: null
})

With

Array(5).fill(null).map(() => ({
   id: null,
   name: null
}))

With this change, you could also give each object in classes a unique id when you create it instead of in componentWillMount:

Array(5).fill(null).map(() => ({
   id: uuid.v4(),
   name: null
}))
Sign up to request clarification or add additional context in comments.

Comments

0

All elements are same in this.state.classes. That means

this.state.classes[0] === this.state.classes[1] // true

And since you are mutating the object of array inside map, that change is being reflected to all the elements of array because they all point to the same object eventually. That meanse is all iteration

let classThings = this.state.classes.map(classObject => {
    let obj = classObject
    obj.id = uuid.v4()
    console.log(this.state.classes[0].id === this.state.classes[1].id) // true
    return obj
  })

You should avoid mutating the object and create new object everytime to get desired result

let classThings = this.state.classes.map(classObject => {
    let obj = Object.assign({}, classObject)
    obj.id = uuid.v4()
    console.log(this.state.classes[0].id === this.state.classes[1].id) // true
    return obj
  })

Comments

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.