Skip to content

Commit 5f552b5

Browse files
committed
move code to example: composition vs inheritance
1 parent db71d03 commit 5f552b5

9 files changed

+223
-120
lines changed

content/docs/composition-vs-inheritance.md

Lines changed: 9 additions & 120 deletions
Original file line numberDiff line numberDiff line change
@@ -17,67 +17,21 @@ Some components don't know their children ahead of time. This is especially comm
1717

1818
We recommend that such components use the special `children` prop to pass children elements directly into their output:
1919

20-
```js{4}
21-
function FancyBorder(props) {
22-
return (
23-
<div className={'FancyBorder FancyBorder-' + props.color}>
24-
{props.children}
25-
</div>
26-
);
27-
}
28-
```
20+
`embed:composition-vs-inheritance/fancy-border-example.js`
2921

3022
This lets other components pass arbitrary children to them by nesting the JSX:
3123

32-
```js{4-9}
33-
function WelcomeDialog() {
34-
return (
35-
<FancyBorder color="blue">
36-
<h1 className="Dialog-title">
37-
Welcome
38-
</h1>
39-
<p className="Dialog-message">
40-
Thank you for visiting our spacecraft!
41-
</p>
42-
</FancyBorder>
43-
);
44-
}
45-
```
46-
47-
[Try it on CodePen.](https://codepen.io/gaearon/pen/ozqNOV?editors=0010)
24+
`embed:composition-vs-inheritance/welcome-dialog-example.js`
25+
26+
[Try it on CodeSandbox.](codesandbox://composition-vs-inheritance/fancyborder-welcome-dialog-example)
4827

4928
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.
5029

5130
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`:
5231

53-
```js{5,8,18,21}
54-
function SplitPane(props) {
55-
return (
56-
<div className="SplitPane">
57-
<div className="SplitPane-left">
58-
{props.left}
59-
</div>
60-
<div className="SplitPane-right">
61-
{props.right}
62-
</div>
63-
</div>
64-
);
65-
}
66-
67-
function App() {
68-
return (
69-
<SplitPane
70-
left={
71-
<Contacts />
72-
}
73-
right={
74-
<Chat />
75-
} />
76-
);
77-
}
78-
```
79-
80-
[Try it on CodePen.](https://codepen.io/gaearon/pen/gwZOJp?editors=0010)
32+
`embed:composition-vs-inheritance/split-pane-example.js`
33+
34+
[Try it on CodeSandbox.](codesandbox://composition-vs-inheritance/split-pane-codesandbox-example.js,composition-vs-inheritance/split-pane-codesandbox-example.css)
8135

8236
React elements like `<Contacts />` and `<Chat />` are just objects, so you can pass them as props like any other data. This approach may remind you of "slots" in other libraries but there are no limitations on what you can pass as props in React.
8337

@@ -87,78 +41,13 @@ Sometimes we think about components as being "special cases" of other components
8741

8842
In React, this is also achieved by composition, where a more "specific" component renders a more "generic" one and configures it with props:
8943

90-
```js{5,8,16-18}
91-
function Dialog(props) {
92-
return (
93-
<FancyBorder color="blue">
94-
<h1 className="Dialog-title">
95-
{props.title}
96-
</h1>
97-
<p className="Dialog-message">
98-
{props.message}
99-
</p>
100-
</FancyBorder>
101-
);
102-
}
103-
104-
function WelcomeDialog() {
105-
return (
106-
<Dialog
107-
title="Welcome"
108-
message="Thank you for visiting our spacecraft!" />
109-
);
110-
}
111-
```
44+
`embed:composition-vs-inheritance/specific-dialog-example.js`
11245

11346
[Try it on CodePen.](https://codepen.io/gaearon/pen/kkEaOZ?editors=0010)
11447

11548
Composition works equally well for components defined as classes:
11649

117-
```js{10,27-31}
118-
function Dialog(props) {
119-
return (
120-
<FancyBorder color="blue">
121-
<h1 className="Dialog-title">
122-
{props.title}
123-
</h1>
124-
<p className="Dialog-message">
125-
{props.message}
126-
</p>
127-
{props.children}
128-
</FancyBorder>
129-
);
130-
}
131-
132-
class SignUpDialog extends React.Component {
133-
constructor(props) {
134-
super(props);
135-
this.handleChange = this.handleChange.bind(this);
136-
this.handleSignUp = this.handleSignUp.bind(this);
137-
this.state = {login: ''};
138-
}
139-
140-
render() {
141-
return (
142-
<Dialog title="Mars Exploration Program"
143-
message="How should we refer to you?">
144-
<input value={this.state.login}
145-
onChange={this.handleChange} />
146-
<button onClick={this.handleSignUp}>
147-
Sign Me Up!
148-
</button>
149-
</Dialog>
150-
);
151-
}
152-
153-
handleChange(e) {
154-
this.setState({login: e.target.value});
155-
}
156-
157-
handleSignUp() {
158-
alert(`Welcome aboard, ${this.state.login}!`);
159-
}
160-
}
161-
```
50+
`embed:composition-vs-inheritance/signup-dialog-example.js`
16251

16352
[Try it on CodePen.](https://codepen.io/gaearon/pen/gwZbYa?editors=0010)
16453

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function FancyBorder(props) {
2+
return (
3+
<div className={'FancyBorder FancyBorder-' + props.color}>
4+
{/* highlight-next-line */}
5+
{props.children}
6+
</div>
7+
);
8+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
4+
function FancyBorder(props) {
5+
return (
6+
<div className={'FancyBorder FancyBorder-' + props.color}>
7+
{props.children}
8+
</div>
9+
);
10+
}
11+
12+
function WelcomeDialog() {
13+
return (
14+
<FancyBorder color="blue">
15+
<h1 className="Dialog-title">
16+
Welcome
17+
</h1>
18+
<p className="Dialog-message">
19+
Thank you for visiting our spacecraft!
20+
</p>
21+
</FancyBorder>
22+
);
23+
}
24+
25+
ReactDOM.render(<WelcomeDialog />, document.getElementById('root'));
26+
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// highlight-range{10,27-31}
2+
function Dialog(props) {
3+
return (
4+
<FancyBorder color="blue">
5+
<h1 className="Dialog-title">
6+
{props.title}
7+
</h1>
8+
<p className="Dialog-message">
9+
{props.message}
10+
</p>
11+
{props.children}
12+
</FancyBorder>
13+
);
14+
}
15+
16+
class SignUpDialog extends React.Component {
17+
constructor(props) {
18+
super(props);
19+
this.handleChange = this.handleChange.bind(this);
20+
this.handleSignUp = this.handleSignUp.bind(this);
21+
this.state = {login: ''};
22+
}
23+
24+
render() {
25+
return (
26+
<Dialog title="Mars Exploration Program"
27+
message="How should we refer to you?">
28+
<input value={this.state.login}
29+
onChange={this.handleChange} />
30+
<button onClick={this.handleSignUp}>
31+
Sign Me Up!
32+
</button>
33+
</Dialog>
34+
);
35+
}
36+
37+
handleChange(e) {
38+
this.setState({login: e.target.value});
39+
}
40+
41+
handleSignUp() {
42+
alert(`Welcome aboard, ${this.state.login}!`);
43+
}
44+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// highlight-range{5,8,16-18}
2+
function Dialog(props) {
3+
return (
4+
<FancyBorder color="blue">
5+
<h1 className="Dialog-title">
6+
{props.title}
7+
</h1>
8+
<p className="Dialog-message">
9+
{props.message}
10+
</p>
11+
</FancyBorder>
12+
);
13+
}
14+
15+
function WelcomeDialog() {
16+
return (
17+
<Dialog
18+
title="Welcome"
19+
message="Thank you for visiting our spacecraft!" />
20+
);
21+
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
html, body, #root {
2+
width: 100%;
3+
height: 100%;
4+
}
5+
6+
.SplitPane {
7+
width: 100%;
8+
height: 100%;
9+
}
10+
11+
.SplitPane-left {
12+
float: left;
13+
width: 30%;
14+
height: 100%;
15+
}
16+
17+
.SplitPane-right {
18+
float: left;
19+
width: 70%;
20+
height: 100%;
21+
}
22+
23+
.Contacts {
24+
width: 100%;
25+
height: 100%;
26+
background: lightblue;
27+
}
28+
29+
.Chat {
30+
width: 100%;
31+
height: 100%;
32+
background: pink;
33+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import React from 'react';
2+
import ReactDOM from 'react-dom';
3+
4+
import './split-pane-codesandbox-example.css';
5+
6+
function Contacts() {
7+
return <div className="Contacts" />;
8+
}
9+
10+
function Chat() {
11+
return <div className="Chat" />;
12+
}
13+
14+
function SplitPane(props) {
15+
return (
16+
<div className="SplitPane">
17+
<div className="SplitPane-left">
18+
{props.left}
19+
</div>
20+
<div className="SplitPane-right">
21+
{props.right}
22+
</div>
23+
</div>
24+
);
25+
}
26+
27+
function App() {
28+
return (
29+
<SplitPane
30+
left={
31+
<Contacts />
32+
}
33+
right={
34+
<Chat />
35+
} />
36+
);
37+
}
38+
39+
ReactDOM.render(
40+
<App />,
41+
document.getElementById('root')
42+
);
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
function SplitPane(props) {
2+
return (
3+
<div className="SplitPane">
4+
<div className="SplitPane-left">
5+
{/* highlight-next-line */}
6+
{props.left}
7+
</div>
8+
<div className="SplitPane-right">
9+
{/* highlight-next-line */}
10+
{props.right}
11+
</div>
12+
</div>
13+
);
14+
}
15+
16+
function App() {
17+
{/* highlight-range{4,7} */}
18+
return (
19+
<SplitPane
20+
left={
21+
<Contacts />
22+
}
23+
right={
24+
<Chat />
25+
} />
26+
);
27+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function WelcomeDialog() {
2+
// highlight-range{3-8}
3+
return (
4+
<FancyBorder color="blue">
5+
<h1 className="Dialog-title">
6+
Welcome
7+
</h1>
8+
<p className="Dialog-message">
9+
Thank you for visiting our spacecraft!
10+
</p>
11+
</FancyBorder>
12+
);
13+
}

0 commit comments

Comments
 (0)