最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Local copy of React prop is read-only - Stack Overflow

programmeradmin5浏览0评论

Let's say I have two Components. The parent is passed an Object as a property, which it then copies into local data store. It has a function to update this local store, which gets passed down to a child. Here is my parent Component:

const Parent = ({stuff}) => {
  const store = {
    stuff: Object.assign({}, stuff);
  }

  const updateStuff = (thing, property) => store.stuff[thing].property = thing;

  return <Child stuff={stuff} updateStuff={updateStuff} />
}

The Child Component has a similar structure -- it makes a copy of stuff, and mutates its copy of stuff on an <input>'s onChange. It then passes its own updated copy of stuff to the updateStuff function it received, in order to mutate the Parent's copy of the prop. Here is the Child.

const Child = ({stuff, updateStuff}) => {
  const stuff = {
    thing1: Object.assign({}, stuff.thing1),
    thing2: Object.assign({}, stuff.thing2)
  }

  const setProp = event => {
    const update = event.target.value;

    stuff.thing1.prop = update;
    updateStuff(thing1, stuff.thing1.prop)
  }

  return (
    <div>
      <input id="thing1" onChange={setProp} />
      <input id="thing1" onChange={setProp} />
    </div>
  )
}

Notice, I've used Object.assign to basically clone the stuff prop or its child properties, as the case necessitates. The reason for this: a React prop is read-only, and thus I need to create a clone to make changes on before passing it back to mutate the app's state (not shown here)/

Now, this works on the Child ponent -- setProp mutates the correct property of stuff, confirmed by logging to the console. However, when the method gets to updateTeam, I get an error message : Uncaught TypeError: Cannot assign to read only property 'side' of object '#<Object>'

Yet, both Components use the same principle: I am not mutating the prop, but rather I am mutating a locally-stored clone of the prop. Why does this work for Child, but not for Parent?

Let's say I have two Components. The parent is passed an Object as a property, which it then copies into local data store. It has a function to update this local store, which gets passed down to a child. Here is my parent Component:

const Parent = ({stuff}) => {
  const store = {
    stuff: Object.assign({}, stuff);
  }

  const updateStuff = (thing, property) => store.stuff[thing].property = thing;

  return <Child stuff={stuff} updateStuff={updateStuff} />
}

The Child Component has a similar structure -- it makes a copy of stuff, and mutates its copy of stuff on an <input>'s onChange. It then passes its own updated copy of stuff to the updateStuff function it received, in order to mutate the Parent's copy of the prop. Here is the Child.

const Child = ({stuff, updateStuff}) => {
  const stuff = {
    thing1: Object.assign({}, stuff.thing1),
    thing2: Object.assign({}, stuff.thing2)
  }

  const setProp = event => {
    const update = event.target.value;

    stuff.thing1.prop = update;
    updateStuff(thing1, stuff.thing1.prop)
  }

  return (
    <div>
      <input id="thing1" onChange={setProp} />
      <input id="thing1" onChange={setProp} />
    </div>
  )
}

Notice, I've used Object.assign to basically clone the stuff prop or its child properties, as the case necessitates. The reason for this: a React prop is read-only, and thus I need to create a clone to make changes on before passing it back to mutate the app's state (not shown here)/

Now, this works on the Child ponent -- setProp mutates the correct property of stuff, confirmed by logging to the console. However, when the method gets to updateTeam, I get an error message : Uncaught TypeError: Cannot assign to read only property 'side' of object '#<Object>'

Yet, both Components use the same principle: I am not mutating the prop, but rather I am mutating a locally-stored clone of the prop. Why does this work for Child, but not for Parent?

Share Improve this question asked Jan 11, 2017 at 3:48 Christopher RonningChristopher Ronning 1,8903 gold badges19 silver badges28 bronze badges 5
  • 2 This may be the result of Object.assign only doing a shallow copy. Object.asssign reference. Could you try deep cloning the objects anywhere you do Object.assign(). Something likenewStuff: JSON.parse(JSON.stringify(stuff)). My thought is that the lower level parts of the object are not really a copy. – Special Character Commented Jan 11, 2017 at 4:20
  • This actually solved the problem. If you format this as an answer, I'll gladly accept it as the correct answer. – Christopher Ronning Commented Jan 11, 2017 at 4:24
  • 1 So I guess the properties of stuff in my Parent ponent are actually references to properties of the actual stuff prop. Is that a correct analysis, @BrandonRoberts ? – Christopher Ronning Commented Jan 11, 2017 at 4:25
  • Why, though, is this same thing not applying to my Child ponent? – Christopher Ronning Commented Jan 11, 2017 at 4:28
  • If strict mode is enabled in App.js then may be instead of const use let i.e. const stuff = { thing1 -> to let stuff = { thing1 – Muhammad Shahzad Commented Oct 3, 2020 at 8:52
Add a ment  | 

3 Answers 3

Reset to default 10

Object.assign only does a shallow copy of the prop Object.assign Reference. In order to make a true deep copy of the prop (and get rid of the error) you can do a deep copy with newStuff: JSON.parse(JSON.stringify(stuff)). Glad this helped!

The real reason behind this is given in an example:

let original = {
    name: 'Test',
    nestedObj: {
        (...some properties)
    }
}

In the example above, the original object property 'name' is a new copy but the nested object is still a reference to the original. This way when you try and edit the part of the nested object it references the original and yells that it is immutable.

I stumbled across this question and decided it needs an updated answer. We can use structuredClone(stuff) instead of the older method of JSON.parse(JSON.stringify(stuff))

Try changing const to let for your local copies

发布评论

评论列表(0)

  1. 暂无评论