-
Notifications
You must be signed in to change notification settings - Fork 47.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
"Composition vs Inheritance" and "Lifting State Up" #7920
Merged
gaearon
merged 11 commits into
facebook:new-docs
from
gaearon:composition-over-inheritance
Oct 11, 2016
Merged
Changes from 7 commits
Commits
Show all changes
11 commits
Select commit
Hold shift + click to select a range
4472e22
Composition vs Inheritance
gaearon 300706d
Small tweaks
gaearon 5b12f44
Moar codepen links
gaearon ac952ba
Make it less aggressive
gaearon 2ffa931
Add Lifting State Up
gaearon 0e7409d
Simplify Lifting State Up
gaearon e124a1c
Remove radix
gaearon 00a43df
s/celsium/celsius
gaearon 4fa2c59
Consistently use classes to make it simpler
gaearon aa6b9ed
Address minor nits
gaearon 4f6d48f
Update to a sensible behavior
gaearon File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
--- | ||
id: composition-vs-inheritance | ||
title: Composition vs Inheritance | ||
permalink: docs/composition-vs-inheritance.html | ||
prev: lifting-state-up.html | ||
--- | ||
|
||
React has a powerful composition model, and we recommend using composition instead of inheritance to reuse code between components. | ||
|
||
In this section, we will consider a few problems where developers new to React often reach for inheritance, and show how we can solve them with composition. | ||
|
||
## Containment | ||
|
||
Some components don't know their children ahead of time. This is especially common for components like `Sidebar` or `Dialog` that represent generic "boxes". | ||
|
||
We recommend that such components include a prop called `children` in their output: | ||
|
||
```js{4} | ||
function FancyBorder(props) { | ||
return ( | ||
<div className={'FancyBorder FancyBorder-' + props.color}> | ||
{props.children} | ||
</div> | ||
); | ||
} | ||
``` | ||
|
||
This lets other components pass arbitrary children to them by nesting the JSX: | ||
|
||
```js{4-9} | ||
function WelcomeDialog() { | ||
return ( | ||
<FancyBorder color="blue"> | ||
<h1 className="Dialog-title"> | ||
Welcome | ||
</h1> | ||
<p className="Dialog-message"> | ||
Thank you for visiting our spacecraft! | ||
</p> | ||
</FancyBorder> | ||
); | ||
} | ||
``` | ||
|
||
[Try it on Codepen.](http://codepen.io/gaearon/pen/ozqNOV?editors=0010) | ||
|
||
Anything inside the `<FancyBorder>` JSX tag gets passed into the `FancyBorder` component as a `children` prop. Since `FancyBorder` renders `{props.children}` inside a `<div>`, the passed elements appear in the final output. | ||
|
||
While this is less common, sometimes you might need multiple "holes" in a component. In such cases you may come up with your own convention instead of using `children`: | ||
|
||
```js{5,8,18,21} | ||
function SplitPane(props) { | ||
return ( | ||
<div className="SplitPane"> | ||
<div className="SplitPane-left"> | ||
{props.left} | ||
</div> | ||
<div className="SplitPane-right"> | ||
{props.right} | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
function App() { | ||
return ( | ||
<SplitPane | ||
left={ | ||
<Contacts /> | ||
} | ||
right={ | ||
<Chat /> | ||
} /> | ||
); | ||
} | ||
``` | ||
|
||
[Try it on Codepen.](http://codepen.io/gaearon/pen/gwZOJp?editors=0010) | ||
|
||
React elements like `<Contacts />` and `<Chat />` are just objects, so you can pass them as props like any other data. | ||
|
||
## Specialization | ||
|
||
Sometimes we think about components as being "special cases" of other components. For example, we might say that a `WelcomeDialog` is a special case of `Dialog`. | ||
|
||
In React, this is also achieved by composition, where a more "specific" component renders a more "generic" one, and configures it with props: | ||
|
||
```js{5,8,16-18} | ||
function Dialog(props) { | ||
return ( | ||
<FancyBorder color="blue"> | ||
<h1 className="Dialog-title"> | ||
{props.title} | ||
</h1> | ||
<p className="Dialog-message"> | ||
{props.message} | ||
</p> | ||
</FancyBorder> | ||
); | ||
} | ||
|
||
function WelcomeDialog() { | ||
return ( | ||
<Dialog | ||
title="Welcome" | ||
message="Thank you for visiting our spacecraft!" /> | ||
); | ||
} | ||
``` | ||
|
||
[Try it on Codepen.](http://codepen.io/gaearon/pen/kkEaOZ?editors=0010) | ||
|
||
Composition works equally well for components defined as classes: | ||
|
||
```js{10,27-31} | ||
function Dialog(props) { | ||
return ( | ||
<FancyBorder color="blue"> | ||
<h1 className="Dialog-title"> | ||
{props.title} | ||
</h1> | ||
<p className="Dialog-message"> | ||
{props.message} | ||
</p> | ||
{props.children} | ||
</FancyBorder> | ||
); | ||
} | ||
|
||
class SignUpDialog extends React.Component { | ||
constructor(props) { | ||
super(props); | ||
this.handleChange = this.handleChange.bind(this); | ||
this.handleSignUp = this.handleSignUp.bind(this); | ||
this.state = {login: ''}; | ||
} | ||
|
||
render() { | ||
return ( | ||
<Dialog title="Mars Exploration Program" | ||
message="How should we refer to you?"> | ||
<input value={this.state.login} | ||
onChange={this.handleChange} /> | ||
<button onClick={this.handleSignUp}> | ||
Sign Me Up! | ||
</button> | ||
</Dialog> | ||
); | ||
} | ||
|
||
handleChange(e) { | ||
this.setState({login: e.target.value}); | ||
} | ||
|
||
handleSignUp() { | ||
alert(`Welcome aboard, ${this.state.login}!`); | ||
} | ||
} | ||
``` | ||
|
||
[Try it on Codepen.](http://codepen.io/gaearon/pen/gwZbYa?editors=0010) | ||
|
||
## So What About Inheritance? | ||
|
||
At Facebook, we use React in thousands of components, and we haven't found any use cases where we would recommend creating component inheritance hierarchies. | ||
|
||
Props and composition give you all the flexibility you need to customize a component's look and behavior in an explicit and safe way. Remember that components may accept arbitrary props, including primitive values, React elements, or functions. | ||
|
||
If you want to reuse non-UI functionality between components, we suggest extracting it into a separate JavaScript module. The components may import it and use that function, object, or a class, without extending it. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this sentence was a bit unclear to me - maybe "We recommend that such components use the special
children
prop to pass children elements directly into their output."