Why do we have both state
and props
? Why don't we just have one source of data? I'd like to update a component's props
and have it re-render itself and all of its children. Seems simple but I can't figure out how to let a component update its own or its parent's props.
Thanks for any help.
A component cannot update its own props unless they are arrays or objects (having a component update its own props even if possible is an anti-pattern), but can update its state and the props of its children.
State updates in React are asynchronous; when an update is requested, there is no guarantee that the updates will be made immediately. The updater functions enqueue changes to the component state, but React may delay the changes, updating several components in a single pass.
“Props” is a special keyword in React, which stands for properties and is being used for passing data from one component to another. Furthermore, props data is read-only, which means that data coming from the parent should not be changed by child components.
The React philosophy is that props should be immutable and top-down. This means that a parent can send whatever prop values it likes to a child, but the child cannot modify its own props. What you do is react to the incoming props and then, if you want to, modify your child's state based on incoming props.
So you don't ever update your own props, or a parent's props. Ever. You only ever update your own state, and react to prop values you are given by parent.
If you want to have an action occur on a child which modifies something on the state, then what you do is pass a callback to the child which it can execute upon the given action. This callback can then modify the parent's state, which in turns can then send different props to the child on re-render.
In React, props flow downward, from parent to child.
This means that when we call ReactDOM.render
, React can render the root node, pass down any props, and then forget about that node. It's done with. It's already rendered.
This happens at each component, we render it, then move on down the tree, depth-first.
If a component could mutate its props, we would be changing an object that is accessible to the parent node, even after the parent node had already rendered. This could cause all sorts of strange behaviour, for example, a user.name
might have one value in one part of the app, and a different value in a different part, and it might update itself the next time a render is triggered.
// App renders a user.name and a profile const App = (props) => React.createElement('div', null, [ props.user.name, React.createElement(Profile, props) ]) // Profile changes the user.name and renders it // Now App has the wrong DOM. const Profile = ({user}) => { user.name = "Voldemort" // Uh oh! return React.createElement('div', null, user.name); } // Render the App and give it props ReactDOM.render( React.createElement(App, {user: {name: "Hermione"}}), document.getElementById('app')) );
We render app. It outputs "Hermione" to the Shadow DOM. We render the Profile, it outputs "Voldemort". The App is now wrong. It should say "Voldemort" because user.name
is "Voldemort", but we already output "Hermione", and it's too late to change it.
The value will be different in different parts of the app.
Mutating props would be a form of two-way binding. We would be modifying values that might be relied on by another component higher up the tree.
Angular 1 had this, you could change any data anytime from wherever you were. In order to work, it needed a cyclical $digest. Basically, it would loop around and around, re-rendering the DOM, until all the data had finished propagating. This was part of the reason why Angular 1 was so slow.
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