Skip to content

Commit b7a548c

Browse files
sebmarkbagezpao
authored andcommitted
Replace transferPropsTo with transferring props patterns
1 parent 9b1ee4d commit b7a548c

17 files changed

+162
-30
lines changed

docs/docs/02.2-jsx-spread.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,4 +68,4 @@ Merging two objects can be expressed as:
6868

6969
> Note:
7070
>
71-
> Activate experimental syntax by using the [JSX command-line tool](http://npmjs.org/package/react-tools) with the `--harmony` flag.
71+
> Use the [JSX command-line tool](http://npmjs.org/package/react-tools) with the `--harmony` flag to activate the experimental ES7 syntax.

docs/docs/05-reusable-components.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ id: reusable-components
33
title: Reusable Components
44
permalink: reusable-components.html
55
prev: multiple-components.html
6-
next: forms.html
6+
next: transferring-props.html
77
---
88

99
When designing interfaces, break down the common design elements (buttons, form fields, layout components, etc) into reusable components with well-defined interfaces. That way, the next time you need to build some UI you can write much less code, which means faster development time, fewer bugs, and fewer bytes down the wire.

docs/docs/06-transferring-props.md

Lines changed: 159 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
---
2+
id: transferring-props
3+
title: Transferring Props
4+
permalink: transferring-props.html
5+
prev: reusable-components.html
6+
next: forms.html
7+
---
8+
9+
It's a common pattern in React to wrap a component in an abstraction. The outer component exposes a simple property to do something that might have more complex implementation details.
10+
11+
You can use [JSX spread attributes](/react/docs/jsx-spread.html) to merge the old props with additional values:
12+
13+
```javascript
14+
return <Component {...this.props} more="values" />;
15+
```
16+
17+
If you don't use JSX, you can use any object helper such as ES6 `Object.assign` or Underscore `_.extend`:
18+
19+
```javascript
20+
return Component(Object.assign({}, this.props, { more: 'values' }));
21+
```
22+
23+
The rest of this tutorial explains best practices. It uses JSX and experimental ES7 syntax.
24+
25+
## Manual Transfer
26+
27+
Most of the time you should explicitly pass the properties down. That ensures that you only exposes a subset of the inner API, one that you know will work.
28+
29+
```javascript
30+
var FancyCheckbox = React.createClass({
31+
render: function() {
32+
var fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
33+
return (
34+
<div className={fancyClass} onClick={this.props.onClick}>
35+
{this.props.children}
36+
</div>
37+
);
38+
}
39+
});
40+
React.renderComponent(
41+
<FancyCheckbox checked={true} onClick={console.log}>
42+
Hello world!
43+
</FancyCheckbox>,
44+
document.body
45+
);
46+
```
47+
48+
But what about the `name` prop? Or the `title` prop? Or `onMouseOver`?
49+
50+
## Transferring with `...` in JSX
51+
52+
Sometimes it's fragile and tedious to pass every property along. In that case you can use [destructuring assignment](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment) with rest properties to extract a set of unknown properties.
53+
54+
List out all the properties that you would like to consume, followed by `...other`.
55+
56+
```javascript
57+
var { checked, ...other } = this.props;
58+
```
59+
60+
This ensures that you pass down all the props EXCEPT the ones you're consuming yourself.
61+
62+
```javascript
63+
var FancyCheckbox = React.createClass({
64+
render: function() {
65+
var { checked, ...other } = this.props;
66+
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
67+
// `other` contains { onClick: console.log } but not the checked property
68+
return (
69+
<div {...other} className={fancyClass} />
70+
);
71+
}
72+
});
73+
React.renderComponent(
74+
<FancyCheckbox checked={true} onClick={console.log}>
75+
Hello world!
76+
</FancyCheckbox>,
77+
document.body
78+
);
79+
```
80+
81+
> NOTE:
82+
>
83+
> In the example above, the `checked` prop is also a valid DOM attribute. If you didn't use destructuring in this way you might inadvertently pass it along.
84+
85+
Always use the destructuring pattern when transferring unknown `other` props.
86+
87+
```javascript
88+
var FancyCheckbox = React.createClass({
89+
render: function() {
90+
var fancyClass = this.props.checked ? 'FancyChecked' : 'FancyUnchecked';
91+
// ANTI-PATTERN: `checked` would be passed down to the inner component
92+
return (
93+
<div {...this.props} className={fancyClass} />
94+
);
95+
}
96+
});
97+
```
98+
99+
## Consuming and Transferring the Same Prop
100+
101+
If your component wants to consume a property but also pass it along, you can repass it explicitly `checked={checked}`. This is preferable to passing the full `this.props` object since it's easier to refactor and lint.
102+
103+
```javascript
104+
var FancyCheckbox = React.createClass({
105+
render: function() {
106+
var { checked, title, ...other } = this.props;
107+
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
108+
var fancyTitle = checked ? 'X ' + title : 'O ' + title;
109+
return (
110+
<label>
111+
<input {...other}
112+
checked={checked}
113+
className={fancyClass}
114+
type="checkbox"
115+
/>
116+
{fancyTitle}
117+
</label>
118+
);
119+
}
120+
});
121+
```
122+
123+
> NOTE:
124+
>
125+
> Order matters. By putting the `{...other}` before your JSX props you ensure that the consumer of your component can't override them. In the example above we have guaranteed that the input will be of type `"checkbox"`.
126+
127+
## Rest and Spread Properties `...`
128+
129+
Rest properties allow you to extract the remaining properties from an object into a new object. It excludes every other property listed in the destructuring pattern.
130+
131+
This is an experimental implementation of an [ES7 proposal](https://github.com/sebmarkbage/ecmascript-rest-spread).
132+
133+
```javascript
134+
var { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 };
135+
x; // 1
136+
y; // 2
137+
z; // { a: 3, b: 4 }
138+
```
139+
140+
> Note:
141+
>
142+
> Use the [JSX command-line tool](http://npmjs.org/package/react-tools) with the `--harmony` flag to activate the experimental ES7 syntax.
143+
144+
## Transferring with Underscore
145+
146+
If you don't use JSX, you can use a library to achieve the same pattern. Underscore supports `_.omit` to filter out properties and `_.extend` to copy properties onto a new object.
147+
148+
```javascript
149+
var FancyCheckbox = React.createClass({
150+
render: function() {
151+
var checked = this.props.checked;
152+
var other = _.omit(this.props, 'checked');
153+
var fancyClass = checked ? 'FancyChecked' : 'FancyUnchecked';
154+
return (
155+
React.DOM.div(_.extend({}, other, { className: fancyClass }))
156+
);
157+
}
158+
});
159+
```

docs/docs/06-forms.md renamed to docs/docs/07-forms.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
id: forms
33
title: Forms
44
permalink: forms.html
5-
prev: reusable-components.html
5+
prev: transferring-props.html
66
next: working-with-the-browser.html
77
---
88

File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.

0 commit comments

Comments
 (0)