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'}} />
<A style={{background: '#ff8137', color: '#fff'}} />
<A style={{background: '#fcb400', color: '#fff'}} />
</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.
The JavaScript strict mode-only exception "is read-only" occurs when a global variable or object property that was assigned to is a read-only property.
The readOnly property sets or returns whether a text field is read-only, or not. A read-only field cannot be modified. However, a user can tab to it, highlight it, and copy the text from it. Tip: To prevent the user from interacting with the field, use the disabled property instead.
Sample Code: class C { readonly readOnlyProperty: string; constructor(raw: string) { this. process(raw); } process(raw: string) { this. readOnlyProperty = raw; // [ts] Cannot assign to 'readOnlyProperty' because it is a constant or a read-only property. } }
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With