Reputation: 413
I'm new to React and from the limited tutorials etc. that I've done I've seen that the application state lives at a level that may be different than the component that's rendering it, for the component to be able to edit the state a function is passed in as a property and used that way. This is all fine but at what point is it ridiculous to be passing a function into a nested component? For example, I have
<App>
<Container>
<Item>
<ItemChangeMenu/>
</Item>
</Container>
</App>
App
has the state and the function changeItem
, should the Container
, Item
, and ItemChangeMenu
all have an onItemChanged
property that passes it along?
Upvotes: 1
Views: 58
Reputation: 31024
There are 2 main approaches to pass props
down to the children:
Explicit - passing the props as individuals on each level:
const Container = (props) => (
<Item
onItemChange={props.onItemChange}
value={props.value} />
);
const Item = (props) => (
<ItemChangeMenu
onItemChange={props.onItemChange}
value={props.value} />
);
const ItemChangeMenu = (props) => (
<input
onChange={props.onItemChange}
value={props.value} />
);
class App extends React.Component {
state = { value: 'Hello World...' }
onItemChange = ({ target }) => {
this.setState(state => ({ value: target.value }))
}
render() {
const { value } = this.state;
return (
<Container
onItemChange={this.onItemChange}
value={value} />
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
Implicit - passing the entire props
object but spreading it (new
ES2018 feature):
const Container = (props) => <Item {...props} />;
const Item = (props) => <ItemChangeMenu {...props} />;
const ItemChangeMenu = (props) => (
<input
onChange={props.onItemChange}
value={props.value} />
);
class App extends React.Component {
state = { value: 'Hello World...' }
onItemChange = ({ target }) => {
this.setState(state => ({ value: target.value }))
}
render() {
const { value } = this.state;
return (
<Container
onItemChange={this.onItemChange}
value={value} />
);
}
}
ReactDOM.render(<App />, document.getElementById('root'));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>
There are pros and cons for each pattern of course.
With the explicit pattern, you get a clear view of which props are being passed down, and you can manually decide what props you want to pass.
The main caveat with this approach though, it is tedious and quite hard to refactor.
With the implicit pattern, you just pass an object and forget about it, you need to pass a new prop? it will already go down the chimney. If you ever need to refactor, change names of props or re-order the components hierarchy, then no need to change the props names.
However, the main caveat with this approach, is that you will probably pass more props then you need to. this can lead to unnecessary calls for componentWillReceiveProps
.
Of course you can use destructure to minimize it:
const {someProp, someOtherProp, ...rest} = this.props;
// ...
<Child {...rest} />
But this is almost the same thing as taking the explicit approach.
There is a 3rd option though it is not related to the props
API.
It called context. With the context API you can "skip" levels and grab objects
directly from the grand parents.
Sounds great, but if you will look at the DOCS:
Why Not To Use Context
The vast majority of applications do not need to use context.
If you want your application to be stable, don’t use context. It is an experimental API and it is likely to break in future releases of React.
As said in the docs, this is an "experimental API and it is likely to break" and that day has come, a new context API is on it's way and will might change the way we work with props
or react all together.
The context
feature is not something that no one use by the way, important libraries like react-redux
, react-router
, react-mobx
are using and dependent on it.
Upvotes: 2