-
Notifications
You must be signed in to change notification settings - Fork 47.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #362 from mcsheffrey/feat-documentation-cookbook
React Tips documentation
- Loading branch information
Showing
18 changed files
with
475 additions
and
0 deletions.
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
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
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,25 @@ | ||
--- | ||
layout: default | ||
sectionid: tips | ||
--- | ||
|
||
<section class="content wrap documentationContent"> | ||
{% include nav_docs.html %} | ||
|
||
<div class="inner-content"> | ||
<h1>{{ page.title }}</h1> | ||
<div class="subHeader">{{ page.description }}</div> | ||
{{ content }} | ||
|
||
<div class="docs-prevnext"> | ||
{% if page.prev %} | ||
<a class="docs-prev" href="/react/tips/{{ page.prev }}">← Prev</a> | ||
{% endif %} | ||
{% if page.next %} | ||
<a class="docs-next" href="/react/tips/{{ page.next }}">Next →</a> | ||
{% endif %} | ||
</div> | ||
|
||
<div class="fb-comments" data-width="650" data-num-posts="10" data-href="{{ site.url }}{{ site.baseurl }}{{ page.url }}"></div> | ||
</div> | ||
</section> |
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,13 @@ | ||
--- | ||
id: introduction | ||
title: Introduction | ||
layout: tips | ||
permalink: introduction.html | ||
next: inline-styles.html | ||
--- | ||
|
||
The React tips section provides bite-sized information that can answer lots of questions you might have and warn you against common pitfalls. | ||
|
||
## Contributing | ||
|
||
Submit a pull request to the [React repository](https://github.com/facebook/react) following the [current tips](https://github.com/facebook/react/tree/master/docs) entries' style. If you have a recipe that needs review prior to submitting a PR you can find help in the [#reactjs channel on freenode](irc://chat.freenode.net/reactjs) or the [reactjs Google group](http://groups.google.com/group/reactjs). Also, check the [Tips Wiki](https://github.com/facebook/react/wiki/Tips-(Previously-Cookbook)) for entries in-progress and general guidelines on writing React tips. |
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,24 @@ | ||
--- | ||
id: inline-styles | ||
title: Inline Styles | ||
layout: tips | ||
permalink: inline-styles.html | ||
next: if-else-in-JSX.html | ||
prev: introduction.html | ||
--- | ||
|
||
In React, inline styles are not specified as a string. Instead they are specified with an object whose key is the camelCased version of the style name, and whose value is the style's value, usually a string ([more on that later](/react/tips/style-props-value-px.html)): | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var divStyle = { | ||
color: 'white', | ||
backgroundImage: 'url(' + imgUrl + ')', | ||
WebkitTransition: 'all' // note the capital 'W' here | ||
}; | ||
|
||
React.renderComponent(<div style={divStyle}>Hello World!</div>, mountNode); | ||
``` | ||
|
||
Style keys are camelCased in order to be consistent with accessing the properties on DOM nodes from JS (e.g. `node.style.backgroundImage`). Vendor prefixes should begin with a capital letter. This is why `WebkitTransition` has an uppercase "W". |
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,42 @@ | ||
--- | ||
id: if-else-in-JSX | ||
title: If-Else in JSX | ||
layout: tips | ||
permalink: if-else-in-JSX.html | ||
prev: inline-styles.html | ||
next: self-closing-tag.html | ||
--- | ||
|
||
`if-else` statements don't work inside JSX. This is because JSX is just syntactic sugar for function calls and object construction. Take this basic example: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
// This JSX: | ||
React.renderComponent(<div id="msg">Hello World!</div>, mountNode); | ||
|
||
// Is transformed to this JS: | ||
React.renderComponent(React.DOM.div({id:"msg"}, "Hello World!"), mountNode); | ||
``` | ||
|
||
This means that `if` statements don't fit in. Take this example: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
// This JSX: | ||
<div id={if (condition) { 'msg' }}>Hello World!</div> | ||
|
||
// Is transformed to this JS: | ||
React.DOM.div({id: if (condition) { 'msg' }}, "Hello World!"); | ||
``` | ||
|
||
That's not valid JS. You probably want to make use of a ternary expression: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
React.renderComponent(<div id={condition ? 'msg' : ''}>Hello World!</div>, mountNode); | ||
``` | ||
|
||
Try using it today with the [JSX compiler](/react/jsx-compiler.html). |
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,14 @@ | ||
--- | ||
id: self-closing-tag | ||
title: Self-Closing Tag | ||
layout: tips | ||
permalink: self-closing-tag.html | ||
prev: if-else-in-JSX.html | ||
next: maximum-number-of-jsx-root-nodes.html | ||
--- | ||
|
||
In JSX, `<MyComponent />` alone is valid while `<MyComponent>` isn't. All tags must be closed, either with the self-closing format or with a corresponding closing tag (`</MyComponent>`). | ||
|
||
> Note: | ||
> | ||
> Every React component can be self-closing: `<div />`. `<div></div>` is also an equivalent. |
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,12 @@ | ||
--- | ||
id: maximum-number-of-jsx-root-nodes | ||
title: Maximum Number of JSX Root Nodes | ||
layout: tips | ||
permalink: maximum-number-of-jsx-root-nodes.html | ||
prev: self-closing-tag.html | ||
next: style-props-value-px.html | ||
--- | ||
|
||
Currently, in a component's `render`, you can only return one node; if you have, say, a list of `div`s to return, you must wrap your components within a `div`, `span` or any other component. | ||
|
||
Don't forget that JSX compiles into regular js; returning two functions doesn't really make syntactic sense. Likewise, don't put more than one child in a ternary. |
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,29 @@ | ||
--- | ||
id: style-props-value-px | ||
title: Shorthand for Specifying Pixel Values in style props | ||
layout: tips | ||
permalink: style-props-value-px.html | ||
prev: maximum-number-of-jsx-root-nodes.html | ||
next: children-props-type.html | ||
--- | ||
|
||
When specifying a pixel value for your inline `style` prop, React automatically appends the string "px" for you after your number value, so this works: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var divStyle = {height: 10}; // rendered as "height:10px" | ||
React.renderComponent(<div style={divStyle}>Hello World!</div>, mountNode); | ||
``` | ||
|
||
See [Inline Styles](/react/tips/inline-styles.html) for more info. | ||
|
||
Sometimes you _do_ want to keep the CSS properties unitless. Here's a list of properties that won't get the automatic "px" suffix: | ||
|
||
- `fillOpacity` | ||
- `fontWeight` | ||
- `lineHeight` | ||
- `opacity` | ||
- `orphans` | ||
- `zIndex` | ||
- `zoom` |
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,49 @@ | ||
--- | ||
id: children-props-type | ||
title: Type of the Children props | ||
layout: tips | ||
permalink: children-props-type.html | ||
prev: style-props-value-px.html | ||
next: controlled-input-null-value.html | ||
--- | ||
|
||
Usually, a component's children (`this.props.children`) is an array of components: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var GenericWrapper = React.createClass({ | ||
componentDidMount: function() { | ||
console.log(Array.isArray(this.props.children)); // => true | ||
}, | ||
render: function() { | ||
return <div />; | ||
} | ||
}); | ||
|
||
React.renderComponent( | ||
<GenericWrapper><span/><span/><span/></GenericWrapper>, | ||
mountNode | ||
); | ||
``` | ||
|
||
However, when there is only a single child, `this.props.children` will be the single child component itself _without the array wrapper_. This saves an array allocation. | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var GenericWrapper = React.createClass({ | ||
componentDidMount: function() { | ||
console.log(Array.isArray(this.props.children)); // => false | ||
|
||
// warning: yields 5 for length of the string 'hello', not 1 for the | ||
// length of the non-existant array wrapper! | ||
console.log(this.props.children.length); | ||
}, | ||
render: function() { | ||
return <div />; | ||
} | ||
}); | ||
|
||
React.renderComponent(<GenericWrapper>hello</GenericWrapper>, mountNode); | ||
``` |
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,24 @@ | ||
--- | ||
id: controlled-input-null-value | ||
title: Value of null for Controlled Input | ||
layout: tips | ||
permalink: controlled-input-null-value.html | ||
prev: children-props-type.html | ||
next: componentWillReceiveProps-not-triggered-after-mounting.html | ||
--- | ||
|
||
Specifying the `value` prop on a [controlled component](/react/docs/forms.html) prevents the user from changing the input unless you desire so. | ||
|
||
You might have run into a problem where `value` is specified, but the input can still be changed without consent. In this case, you might have accidentally set `value` to `undefined` or `null`. | ||
|
||
The snippet below shows this phenomenon; after a second, the text becomes editable. | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
React.renderComponent(<input value="hi" />, mountNode); | ||
|
||
setTimeout(function() { | ||
React.renderComponent(<input value={null} />, mountNode); | ||
}, 2000); | ||
``` |
12 changes: 12 additions & 0 deletions
12
docs/tips/09-componentWillReceiveProps-not-triggered-after-mounting.md
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,12 @@ | ||
--- | ||
id: componentWillReceiveProps-not-triggered-after-mounting | ||
title: componentWillReceiveProps Not Triggered After Mounting | ||
layout: tips | ||
permalink: componentWillReceiveProps-not-triggered-after-mounting.html | ||
prev: controlled-input-null-value.html | ||
next: props-in-getInitialState-as-anti-pattern.html | ||
--- | ||
|
||
`componentWillReceiveProps` isn't triggered after the node is put on scene. This is by design. Check out [other lifecycle methods](/react/docs/component-specs.html) for the one that suits your needs. | ||
|
||
The reason for that is because `componentWillReceiveProps` often handles the logic of comparing with the old props and acting upon changes; not triggering it at mounting (where there are no old props) helps in defining what the method does. |
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,62 @@ | ||
--- | ||
id: props-in-getInitialState-as-anti-pattern | ||
title: Props in getInitialState Is an Anti-Pattern | ||
layout: tips | ||
permalink: props-in-getInitialState-as-anti-pattern.html | ||
prev: componentWillReceiveProps-not-triggered-after-mounting.html | ||
next: dom-event-listeners.html | ||
--- | ||
|
||
> Note: | ||
> | ||
> This isn't really a React-specific tip, as such anti-patterns often occur in code in general; in this case, React simply points them out more clearly. | ||
Using props, passed down from parent, to generate state in `getInitialState` often leads to duplication of "source of truth", i.e. where the real data is. Whenever possible, compute values on-the-fly to ensure that they don't get out of sync later on and cause maintenance trouble. | ||
|
||
Bad example: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var MessageBox = React.createClass({ | ||
getInitialState: function() { | ||
return {nameWithQualifier: "Mr. " + this.props.name}; | ||
}, | ||
render: function() { | ||
return <div>{this.state.nameWithQualifier}</div>; | ||
} | ||
}); | ||
|
||
React.renderComponent(<MessageBox name="Rogers"/>, mountNode); | ||
``` | ||
|
||
Better: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var MessageBox = React.createClass({ | ||
render: function() { | ||
return <div>{"Mr. " + this.props.name}</div>; | ||
} | ||
}); | ||
|
||
React.renderComponent(<MessageBox name="Rogers"/>, mountNode); | ||
``` | ||
|
||
For more complex logic: | ||
|
||
```js | ||
/** @jsx React.DOM */ | ||
|
||
var MessageBox = React.createClass({ | ||
render: function() { | ||
return <div>{this.getNameWithQualifier(this.props.name)}</div>; | ||
}, | ||
getNameWithQualifier: function(name) { | ||
return 'Mr. ' + name; | ||
} | ||
}); | ||
|
||
React.renderComponent(<MessageBox name="Rogers"/>, mountNode); | ||
``` |
Oops, something went wrong.