Categories
babeljs reactjs

Uncaught TypeError: Cannot assign to read only property ” of object ‘#’

i don’t know what difference in this code.
class a is component and example is example.js

import React, {Component} from 'react';
const styles = {
border: {
display: 'inline-block',
height: '19px',
padding: '1px 8px 0',
border: '2px solid',
borderRadius: '12px',
lineHeight: '20px',
fontSize: '14px',
verticalAlign: 'top',
},
default: {
display: 'inline-block',
height: '20px',
padding: '1px 10px 0',
borderRadius: '10px',
lineHeight: '21px',
fontSize: '13px',
verticalAlign: 'top',
},
state: {
display: 'inline-block',
width: '14px',
height: '13px',
paddingTop: '1px',
lineHeight: '14px',
fontSize: '11px',
color: '#fff',
letterSpacing: '-0.5px',
textAlign: 'center',
verticalAlign: 'top',
}
};
class A extends Component {
static defaultProps = {
type: 'default',
};
render() {
const {
label,
style,
type,
...other
} = this.props;
switch (type) {
case 'border':
elementStyle = styles.border;
break;
case 'default':
elementStyle = styles.default;
break;
case 'state':
elementStyle = styles.state;
break;
}
return (
<span style={Object.assign(elementStyle, style)} {...other}>{label}</span>
);
}
}
export default A;

and example code is example.js

import A from './A';
export default class Example extends React.Component {
render() {
return (
<div>
<A style={{background: '#fe6969', color: '#fff'}} /> &nbsp;
<A style={{background: '#ff8137', color: '#fff'}} /> &nbsp;
<A style={{background: '#fcb400', color: '#fff'}} /> &nbsp;
</div>
);
}
}

this code error is Uncaught TypeError: Cannot assign to read only property ‘background’ of object ‘#’

i use babel-loader 8, babel7 ,webpack4

if i correct Object.assgin({}, elementStyle, style) is working.
i think this error occur when rerendering A component.
i don’t know why this error…

please help me.

All you need to do is concat/merge two objects like this using spread

{{...elementStyle, ...style}}  or
{Object.assign({}, elementStyle , style) }

You should understand the nature of how Object.assign works. It returns the target object as the return value of its operation.

So, in the first syntax:

Object.assign({}, elementStyle , style)

you are creating a brand new object with the enumerable properties of elementStyle and style.

If you do this:

Object.assign(elementStyle, style)

Then elementStyle itself is the target object, so that will be mutated and that will be what is returned from Object.assign.

Here is an example what I mean.

Example 1 :

// With no new target object
const original = [{id:1}, {id:2}, {id:3}];

const newArray = original.map(elem => {
return Object.assign(elem, {id:2});
});

console.log('Original object has changed');
console.log(original);

//------------------------------

// With a new target object
const original2 = [{id:1}, {id:2}, {id:3}];

const newArray2 = original2.map(elem => {
return Object.assign({}, elem, {id:2});
});

console.log('Original object has not changed');
console.log(original2);

Example 2 :

var styles =  {
circle: {backgroundColor: 'yellow', height: '1005', width: '100%'},
circleA: {backgroundColor: 'blue'},
};

So we need all circle to have default cir some circle style, but we need to change some property,

// background yellow
<div style={styles.circle}></div>
// background blue
<div style={Object.assign(styles.circle, styles.circleA)}></div>
// expeted background yellow, but it's blue. cus styles.circle still have it's merged value
<div style={styles.circle}></div>

The solution is to pass an empty object to Object.assign(). By doing this, you’re telling the method to produce a NEW object with the objects you pass it.

Example 3:

const obj1 = {
name: "J"
}

const obj2 = {
gander: "m"
}

// Here, obj1 is the same after the Object.assign call
console.log(Object.assign({}, obj1, obj2));
console.log(obj1)
console.log(obj2)

console.log("without empty obj passed")

// Note that after this call, obj1 holds both keys. So this will mutate it:
console.log(Object.assign(obj1, obj2));
console.log(obj1) // This is different now
console.log(obj2)

In your case,

`<A propstyle={{background: '#fe6969', color: '#fff'}} />
<A propstyle={{background: '#ff8137', color: '#fff'}} /> `

component A defined twice in Parent, which means that we will get two circles and child component will render twice.

and in Child component you defined like below:

<span style={Object.assign(elementStyle , style) }{...other}>{label}</span>

first render :

Object.assign overwrite properties from right to left props style to elementStyle,here elementStyle itself is the target object,that will be what is returned from Object.assign.

style props : { background: "#fe6969", color: "#fff" }

elementStyle : { background: "#fe6969", borderRadius: "10px", color: "#fff" }

Second render :

Object.assign tries to overwrite properties from right to left, but elementStyle have { background: "#fe6969", borderRadius: "10px", color: "#fff" }

and Object.assign is still in loop (remember example 1 .map())

style props : { background: "#ff8137", color: "#fff" }

error thrown: ‘TypeError: Cannot assign to read only property ‘background’ of object ‘ when {Object.assign(elementStyle , style) } because there’s no new target object.

please find the full code here

Hope it helps. read more