Connor McSheffrey
11 years ago
27 changed files with 34 additions and 423 deletions
@ -1,13 +0,0 @@ |
|||
--- |
|||
id: introduction-tip |
|||
title: Cookbook Introduction |
|||
layout: cookbook |
|||
permalink: introduction-tip.html |
|||
next: inline-styles.html |
|||
--- |
|||
|
|||
The React.js cookbook provides common React tips, bite-sized information that can surprisingly answer lots of questions you might have had and warn you against common pitfalls. |
|||
|
|||
### Contributing |
|||
|
|||
Submit a pull request to the [React repo](https://github.com/facebook/react) following the cookbook entries' style. If you have a recipe that needs review prior to submitting a PR you can find help in the [#reactjs IRC on freenode](irc://chat.freenode.net/reactjs) or the [reactjs Google group](http://groups.google.com/group/reactjs). |
@ -1,24 +0,0 @@ |
|||
--- |
|||
id: inline-styles-tip |
|||
title: Inline Styles |
|||
layout: cookbook |
|||
permalink: inline-styles-tip.html |
|||
next: if-else-in-JSX.html |
|||
prev: introduction.html |
|||
--- |
|||
|
|||
In React, inline styles are not specified as a string, but as an object whose key is the camelCased version of the style name, and whose value is the style's value in string: |
|||
|
|||
```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 using node.style.___ in DOM. This also explains why WebkitTransition has an uppercase "W". |
@ -1,31 +0,0 @@ |
|||
--- |
|||
id: if-else-in-JSX-tip |
|||
title: If-Else in JSX |
|||
layout: cookbook |
|||
permalink: if-else-in-JSX-tip.html |
|||
prev: inline-styles.html |
|||
next: self-closing-tag.html |
|||
--- |
|||
|
|||
`if-else` statements don't work inside JSX, since JSX is really just sugar for functions: |
|||
|
|||
```js |
|||
/** @jsx React.DOM */ |
|||
|
|||
// this |
|||
React.renderComponent(<div id="msg">Hello World!</div>, mountNode); |
|||
// is the same as this |
|||
React.renderComponent(React.DOM.div({id:"msg"}, "Hello World!"), mountNode); |
|||
``` |
|||
|
|||
Which means `<div id={if (true){ 'msg' }}>Hello World!</div>` doesn't make sense, as (if it worked) it would be compiled down to something like this `React.DOM.div({id: if (true){ 'msg' }}, "Hello World!")`, which isn't valid JS. |
|||
|
|||
What you're searching for is ternary expression: |
|||
|
|||
```js |
|||
/** @jsx React.DOM */ |
|||
|
|||
React.renderComponent(<div id={true ? 'msg' : ''}>Hello World!</div>, mountNode); |
|||
``` |
|||
|
|||
Try the [JSX compiler](/react/jsx-compiler.html). |
@ -1,12 +0,0 @@ |
|||
--- |
|||
id: self-closing-tag-tip |
|||
title: Self-Closing Tag |
|||
layout: cookbook |
|||
permalink: self-closing-tag-tip.html |
|||
prev: if-else-in-JSX.html |
|||
next: jsx-root-node-count.html |
|||
--- |
|||
|
|||
In JSX, `<MyComponent />` alone is valid while `<MyComponent>` isn't. |
|||
|
|||
Related: every React component can be self-closing: `<div/>`. |
@ -1,12 +0,0 @@ |
|||
--- |
|||
id: jsx-root-node-count-tip |
|||
title: Maximum number of JSX root nodes |
|||
layout: cookbook |
|||
permalink: jsx-root-node-count-tip.html |
|||
prev: self-closing-tag.html |
|||
next: style-prop-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. |
@ -1,29 +0,0 @@ |
|||
--- |
|||
id: style-prop-value-px-tip |
|||
title: Shorthand for specifying pixel values in style prop |
|||
layout: cookbook |
|||
permalink: style-prop-value-px-tip.html |
|||
prev: jsx-root-node-count.html |
|||
next: children-prop-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/docs/cookbook/inline-styles-tip.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 |
@ -1,12 +0,0 @@ |
|||
--- |
|||
id: children-prop-type-tip |
|||
title: Type of the children prop |
|||
layout: cookbook |
|||
permalink: children-prop-type-tip.html |
|||
prev: style-prop-value-px.html |
|||
next: controlled-input-null-value.html |
|||
--- |
|||
|
|||
Usually, a component's `this.props.children` is an array of components. To save an extra array allocation, it returns the component itself when there's only one. |
|||
|
|||
This means accessing, for example, `this.props.children.length` might be misleading, as it could either be the `length` property of the array of children, or that of a single string component. |
@ -1,24 +0,0 @@ |
|||
--- |
|||
id: controlled-input-null-value-tip |
|||
title: Value of null for controlled input |
|||
layout: cookbook |
|||
permalink: controlled-input-null-value-tip.html |
|||
prev: children-prop-type.html |
|||
next: componentWillReceiveProps-not-triggered-after-mounting.html |
|||
--- |
|||
|
|||
Specifying the `value` prop on a [controlled component](/react/docs/cookbook/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); |
|||
``` |
@ -1,12 +0,0 @@ |
|||
--- |
|||
id: componentWillReceiveProps-not-triggered-after-mounting-tip |
|||
title: componentWillReceiveProps not triggered after mounting |
|||
layout: cookbook |
|||
permalink: componentWillReceiveProps-not-triggered-after-mounting-tip.html |
|||
prev: controlled-input-null-value.html |
|||
next: props-in-getInitialSate-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/cookbook/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. |
@ -1,62 +0,0 @@ |
|||
--- |
|||
id: props-in-getInitialSate-as-anti-pattern-tip |
|||
title: props in getInitialState is an anti-pattern |
|||
layout: cookbook |
|||
permalink: props-in-getInitialSate-as-anti-pattern-tip.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="Zuck"/>, mountNode); |
|||
``` |
|||
|
|||
Better: |
|||
|
|||
```js |
|||
/** @jsx React.DOM */ |
|||
|
|||
var MessageBox = React.createClass({ |
|||
render: function() { |
|||
return <div>{"Mr. " + this.props.name}</div>; |
|||
} |
|||
}); |
|||
|
|||
React.renderComponent(<MessageBox name="Zuck"/>, 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="Zuck"/>, mountNode); |
|||
``` |
@ -1,40 +0,0 @@ |
|||
--- |
|||
id: dom-event-listeners-tip |
|||
title: DOM event listeners in a component |
|||
layout: cookbook |
|||
permalink: dom-event-listeners-tip.html |
|||
prev: props-in-getInitialSate-as-anti-pattern.html |
|||
next: initial-ajax.html |
|||
--- |
|||
|
|||
> Note: |
|||
> |
|||
> This entry shows how to attach DOM events not provided by React ([check here for more info](/react/docs/cookbook/events.html)). This is good for integrations with other libraries such as jQuery. |
|||
|
|||
Try to resize the window: |
|||
|
|||
```js |
|||
/** @jsx React.DOM */ |
|||
|
|||
var Box = React.createClass({ |
|||
getInitialState: function() { |
|||
return {windowWidth: window.innerWidth}; |
|||
}, |
|||
handleResize: function(e) { |
|||
this.setState({windowWidth: window.innerWidth}); |
|||
}, |
|||
componentDidMount: function() { |
|||
window.addEventListener("resize", this.handleResize); |
|||
}, |
|||
componentWillUnmount: function() { |
|||
window.removeEventListener("resize", this.handleResize); |
|||
}, |
|||
render: function() { |
|||
return <div>Current window width: {this.state.windowWidth}</div>; |
|||
} |
|||
}); |
|||
|
|||
React.renderComponent(<Box />, mountNode); |
|||
``` |
|||
|
|||
`componentDidMount` is called after the component's mounted and has a DOM representation. This is often a place where you'd attach generic DOM events. |
@ -1,45 +0,0 @@ |
|||
--- |
|||
id: initial-ajax-tip |
|||
title: Load initial data via AJAX |
|||
layout: cookbook |
|||
permalink: initial-ajax-tip.html |
|||
prev: dom-event-listeners.html |
|||
--- |
|||
|
|||
Fetch data in `componentDidMount`. When they arrive, put them inside your state then render them. |
|||
|
|||
This example fetches the desired Github user's lastest gist: |
|||
|
|||
```js |
|||
/** @jsx React.DOM */ |
|||
|
|||
var UserGist = React.createClass({ |
|||
getInitialState: function() { |
|||
return { |
|||
username: '', |
|||
lastGistUrl: '' |
|||
}; |
|||
}, |
|||
componentDidMount: function() { |
|||
$.get(this.props.source, function(result) { |
|||
var lastGist = result[0]; |
|||
this.setState({ |
|||
username: lastGist.user.login, |
|||
lastGistUrl: lastGist.html_url |
|||
}); |
|||
}.bind(this)); |
|||
}, |
|||
render: function() { |
|||
return ( |
|||
<div> |
|||
{this.state.username}'s last gist is |
|||
<a href={this.state.lastGistUrl}>here</a>. |
|||
</div> |
|||
); |
|||
} |
|||
}); |
|||
|
|||
React.renderComponent( |
|||
<UserGist source="https://api.github.com/users/octocat/gists" />, mountNode |
|||
); |
|||
``` |
@ -1,29 +0,0 @@ |
|||
--- |
|||
id: false-in-jsx-tip |
|||
title: False in JSX |
|||
layout: cookbook |
|||
permalink: initial-ajax.html |
|||
prev: initial-ajax.html |
|||
--- |
|||
|
|||
Here's how `false` renders in different contexts: |
|||
|
|||
Renders as `id="false"`: |
|||
```js |
|||
/** @jsx React.DOM */ |
|||
React.renderComponent(<div id={false} />, mountNode); |
|||
``` |
|||
|
|||
String "false" as input value: |
|||
```js |
|||
/** @jsx React.DOM */ |
|||
React.renderComponent(<input value={false} />, mountNode); |
|||
``` |
|||
|
|||
No child: |
|||
```js |
|||
/** @jsx React.DOM */ |
|||
React.renderComponent(<div>{false}</div>, mountNode); |
|||
``` |
|||
|
|||
The reason why this one doesn't render as the string `"false"` as a `div` child is to allow the more common use-case: `<div>{x > 1 && You have more than one item}</div>`. |
Loading…
Reference in new issue