This question is somewhat related to How to pass props to {this.props.children}.
That may sound like a dumb question which has been answered a million times, but I can't figure it out what is true and what is not from what I've read so far. I can't find detailed information about this topic on either react or react native documentation.
So, does anyone knows how props are handled (under the hood) in react native? I'm asking this because I've read in several places either one of:
- props are immutable
- components themselves are immutable
- props/components are not immutable, but changing them will have no effect on rendering
I also thought that react native was handling props exactly like react (ie., react native was directly using react and therefore they would both behave the same way).
I wanted to check which one of these 3 statements were true, so I tried to break all of them, one by one, to see which ones stand. All test cases I'll describe here are implemented in this snack.
Props are immutable?
Let's consider this simple example:
const style = {height: 10, width: 10, backgroundColor: "red"};
const firstItem = <View style={style} />;
firstItem.props.style = {...style, height: 100};
console.log(firstItem.props.style.height);
If firstItem.props
was immutable, this should print 10
since firstItem.props.style = {...style, height: 100};
would have no effect whatsoever. But this instead prints 100
, therefore I must conclude that component's props
properties are not immutable in react native.
Components themselves are immutable?
Same as before, let's have a simple test case for this:
const secondItem = <View style={style} />;
secondItem.props = {style: {...style, height: 200}};
console.log(secondItem.props.style.height);
Again, this should print 10
if secondItem
was immutable, but it prints 200
. Therefore components are not immutable in react native.
Changing props will have no effect on rendering?
This time I don't need to modify the code, I just need to render these two items and see if they are tall rectangles or a small squares. And as you might have already guessed, this renders two tall rectangles, meaning that changing that mutating component/props does have an effect on the components' rendering.
export default class App extends React.PureComponent {
render() {
return (
<View style={{ margin: 20, padding: 20, flexDirection: "row" }}>
{firstItem}
{secondItem}
</View>
);
}
}
Shows the following:
My questions
Is there a flaw in my test cases? Is there a difference between react and react native on how props are handled?
Finally and (maybe) most importantly, even if react native doesn't enforce props immutability, why should it be considered "dangerous" or simply bad practice to mutate it (harder to predict/debug)? In other words, why does react provide a React.cloneElement
instead of having immutable props
. Does it mean that they suggest to not mutate props, but they don't want to impose that constraint, or did I just missed something.
And ultimately, the application to a concrete use case, why is it suggested in the original question I linked to use this form:
React.cloneElement(child, { doSomething: this.doSomething })
Instead of (for example) mutating the component:
child.props = {...child.props, doSomething: this.doSomething }