#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?
Advertisement
Answer
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