22

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.

2 Answers 2

27

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

Sign up to request clarification or add additional context in comments.

10 Comments

i use es6 .. i want to know why is not working using Object.assgin(elementStyle, styles).. i want to know this reason..
umm. i understood your answer.. but i don't know why this error... using Object.assgin(elementStyle, style) ==> Cannot assign to read only property 'background' of object '#<Object>'
thank you i understood above exampe 1,2. but i don't know why this error was occured...Cannot assign to read only property 'background' of object '#<Object>' why is problem that merge to merged object?
you mean that in the past merged span tag style have background , and i merged this span tag that have background --> this is problem??
/ here you see this prints 5 times check console '#ff8137', '#fcb400' fails these two throws error because every render you doesn't create new object --> what is new object?? you mean that propstyle is problem??
|
5

Instead of assigning values directly to the object, clone the object first instead of mutating an object that is immutable due to the fact that the object is a props object or because Object.defineproperties was used to set writable to "false", but just clone the object and assign the values to the cloned object and use the cloned object, but assign the values to the cloned object properly as well.

Instead of assigning and mutating directly like:

object.field = value

Do:

let clonedObject = {...object}
clonedObject = {...clonedObject, field: value}

Otherwise using object.defineproperties to set the writable property to "true" might also be another way that would work.

Object.defineProperty(object, 'field1', {
  value: 1,
  writable: true
});

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.