How to pass nested properties with spread attributes correctly? (JSX)

#1

Hello.
I have the code:

class Component extends React.Component {
    render() {
        this.props.nested.prop = this.props.parse.nested.prop;
        return <div>Component</div>;
    }
    componentDidMount() {
        console.log(this.props.nested.prop);
    }
}
Component.defaultProps = {
    nested: {
        prop: "default",
    },
};

const obj1 = {
    nested: {
        prop: "obj1",
    },
};
const obj2 = {
    nested: {
        prop: "obj2",
    },
};

class Application extends React.Component {
    render() {
        return (
            <div>
                <Component parse={obj1} />
                <Component parse={obj2} />
            </div>
        );
    }
}

React.render(<Application />, document.getElementById("app"));
// console output:
// "obj2"
// "obj2"

Why do I get 1 variable reference for 2 separate components instead of 2 instances of nested.prop for every component?
Why this.props saves only last setted value for all instances of the component after mounting? Is it a normal behavior?
I think the correct behavior is having different property values for different instances.

P.S. I have tested this code here.

#2

jimfb has been answered:
"You are mutating the default prop that was passed in. The line this.props.nested.prop = this.props.parse.nested.prop; is illegal."

My next question:
How to pass nested properties without a manual mutation of props?

For example:

Component.defaultProps = {
    nested: {
        prop1: "default",
        prop2: "default",
    },
};

const props = {
    nested: {
        prop1: "value",
    },
};

let component = <Component {...props} />;

Guide to the code above JSX spread attribute feature just override props.nested and I lose default nested properties. But it is not that I need.
How about to implements a recursive traversing of nested objects in stage of JSX spread attributes parsing?
Or Is there some useful pattern for this case?

Answers:

Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.

Method 1

This is actually a good question!

Short answer: you can’t do deep merge with spread operator – it only does shallow merging.
But you surely can write function that will do objects traversing and implements deep merging.

This actually leaves you 3 options:

1) Just don’t do deep merge. If you have 2 level nested object you can do such simple thing:

const newNested = {...oldProps.nested, ...newProps.nested };
const finalProps = { ...oldProps, nested: newNested };

Shallow merging force you to say explicitly that you will have new value of nested property. Which is a good thing as it makes your code obvious.
You can also try out runnable examples here.

2) You may use a library for immutable structures. F.e. immutable.js. With it your code will look pretty similar.

const oldProps = Immutable.fromJS({
  nested:
  {
    prop1: "OldValue1",
    prop2: "OldValue2",
  }
});

const newProps = Immutable.fromJS({
  nested:
  {
    prop1: "NewValue1",
  }
});

const finalProps = oldProps.updateIn(['nested'], (oldNested)=>
  oldNested.merge(newProps.get('nested'))
)

3) You may use deep merge: find some implementation in npm or write it yourself
and you will have a code like this(again immutable.js as an example):
const finalProps = oldProps.mergeDeep(newProps);

You may want this in some cases, but such code makes update operation implicit and it rises a lot of problems which are listed greatly here


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

0 0 votes
Article Rating
Subscribe
Notify of
guest

0 Comments
Inline Feedbacks
View all comments
0
Would love your thoughts, please comment.x
()
x