Browse Source

Reorganize examples & legacy docs

main
Alex Krolick 7 years ago
parent
commit
0780f7252e
  1. 215
      content/docs/context.md
  2. 215
      content/docs/legacy-context.md

215
content/docs/context.md

@ -6,15 +6,9 @@ permalink: docs/context.html
Context provides a way to pass data through the component tree without having to pass props down manually at every level. Context provides a way to pass data through the component tree without having to pass props down manually at every level.
## Using Context ## API
Here is an example illustrating how you might inject a "theme" using context: ### `React.createContext`
`embed:context/theme-example.js`
### API
#### `React.createContext`
```js ```js
const {Provider, Consumer} = React.createContext([default]); const {Provider, Consumer} = React.createContext([default]);
@ -25,7 +19,7 @@ Creates a `{ Provider, Consumer }` pair.
Takes one argument, the default context that Consumers will receive when they don't have a matching Provider. Takes one argument, the default context that Consumers will receive when they don't have a matching Provider.
#### `Provider` ### `Provider`
```js ```js
<Provider value={/* some value */}> <Provider value={/* some value */}>
@ -35,7 +29,7 @@ A React component that allows Consumers to subscribe to context changes.
Takes one prop, `value`, which will be passed to the [render prop](/docs/render-props.html) of child Consumers for the matching context anywhere in the component tree. One Provider can be connected to many Consumers. Takes one prop, `value`, which will be passed to the [render prop](/docs/render-props.html) of child Consumers for the matching context anywhere in the component tree. One Provider can be connected to many Consumers.
#### `Consumer` ### `Consumer`
```js ```js
<Consumer> <Consumer>
@ -51,28 +45,32 @@ Takes a function as the `children` prop that receives the `value` prop of the ma
> >
> For more information about this pattern, see [render props](/docs/render-props.html). > For more information about this pattern, see [render props](/docs/render-props.html).
### Typical Usage ## Examples
`embed:context/theme-detailed-theme-context.js` ### Static Context
`embed:context/theme-detailed-themed-button.js` Here is an example illustrating how you might inject a "theme" using context:
`embed:context/theme-detailed-app.js` `embed:context/theme-example.js`
### Dynamic Context
## Experimental API (Deprecated in React 16.3) A more complex example with dynamic values for the theme:
> The old experimental API is deprecated as of React 16.3. The API will be supported in all 16.x releases, but applications using it should migrate to the new API. **theme-contex.js**
`embed:context/theme-detailed-theme-context.js`
The experimental API lacked a safe mechanism to update context. Version 16.3 introduced a new context API that is more efficient and supports both static type checking and deep updates. **themed-button.js**
`embed:context/theme-detailed-themed-button.js`
### How To Use Context **app.js**
`embed:context/theme-detailed-app.js`
> This section documents a deprecated API ## Motivation
Suppose you have a structure like: Context is designed to relieve the pain of passing props down through a deeply nested component tree. For example, in the code below we manually thread through a color prop in order to style the Button and Message components. Using context, we can avoid passing props through intermediate elements.
```javascript ```js
class Button extends React.Component { class Button extends React.Component {
render() { render() {
return ( return (
@ -87,6 +85,11 @@ class Message extends React.Component {
render() { render() {
return ( return (
<div> <div>
{/*
The Message component must take `color` as as prop to pass it to the
Button. Using context, the Button could connect to the color context
on its own.
*/}
{this.props.text} <Button color={this.props.color}>Delete</Button> {this.props.text} <Button color={this.props.color}>Delete</Button>
</div> </div>
); );
@ -104,170 +107,8 @@ class MessageList extends React.Component {
} }
``` ```
In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Using context, we can pass this through the tree automatically: ## Legacy API
```javascript{6,13-15,21,28-30,40-42}
import PropTypes from 'prop-types';
class Button extends React.Component {
render() {
return (
<button style={{background: this.context.color}}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: PropTypes.string
};
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
getChildContext() {
return {color: "purple"};
}
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: PropTypes.string
};
```
By adding `childContextTypes` and `getChildContext` to `MessageList` (the context provider), React passes the information down automatically and any component in the subtree (in this case, `Button`) can access it by defining `contextTypes`.
If `contextTypes` is not defined, then `context` will be an empty object.
> Note:
>
> `React.PropTypes` has moved into a different package since React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types) to define `contextTypes`.
>
> We provide [a codemod script](/blog/2017/04/07/react-v15.5.0.html#migrating-from-react.proptypes) to automate the conversion.
### Parent-Child Coupling
> This section documents a deprecated API
Context can also let you build an API where parents and children communicate. For example, one library that works this way is [React Router V4](https://reacttraining.com/react-router):
```javascript
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
```
By passing down some information from the `Router` component, each `Link` and `Route` can communicate back to the containing `Router`.
Before you build components with an API similar to this, consider if there are cleaner alternatives. For example, you can pass entire React components as props if you'd like to.
### Referencing Context in Lifecycle Methods
> This section documents a deprecated API
If `contextTypes` is defined within a component, the following [lifecycle methods](/docs/react-component.html#the-component-lifecycle) will receive an additional parameter, the `context` object:
- [`constructor(props, context)`](/docs/react-component.html#constructor)
- [`componentWillReceiveProps(nextProps, nextContext)`](/docs/react-component.html#componentwillreceiveprops)
- [`shouldComponentUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#shouldcomponentupdate)
- [`componentWillUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#componentwillupdate)
> Note:
>
> As of React 16, `componentDidUpdate` no longer receives `prevContext`.
### Referencing Context in Stateless Functional Components
> This section documents a deprecated API
Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows a `Button` component written as a stateless functional component.
```javascript
import PropTypes from 'prop-types';
const Button = ({children}, context) =>
<button style={{background: context.color}}>
{children}
</button>;
Button.contextTypes = {color: PropTypes.string};
```
### Updating Context
> This section documents a deprecated API
Don't do it.
React has an API to update context, but it is fundamentally broken and you should not use it.
The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children.
```javascript
import PropTypes from 'prop-types';
class MediaQuery extends React.Component {
constructor(props) {
super(props);
this.state = {type:'desktop'};
}
getChildContext() {
return {type: this.state.type};
}
componentDidMount() {
const checkMediaQuery = () => {
const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
if (type !== this.state.type) {
this.setState({type});
}
};
window.addEventListener('resize', checkMediaQuery);
checkMediaQuery();
}
render() {
return this.props.children;
}
}
MediaQuery.childContextTypes = {
type: PropTypes.string
};
```
The problem is, if a context value provided by component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. This is totally out of control of the components using context, so there's basically no way to reliably update the context. [This blog post](https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076) has a good explanation of why this is a problem and how you might get around it. > The legacy context API was deprecated in React 16.3
>
> React previously shipped with an experimental context API. The old API will be supported in all 16.x releases, but applications using it should migrate to the new version. Read the [legacy context docs here](/docs/legacy-context.html).

215
content/docs/legacy-context.md

@ -0,0 +1,215 @@
---
id: legacy-context
title: Legacy Context
permalink: docs/legacy-context.html
---
> This API is deprecated as of React 16.3.
>
> The API will be supported in all 16.x releases, but applications using it should migrate to the [new API](/docs/context.html). The experimental API lacked a safe mechanism to update context. Version 16.3 introduced a new context API that is more efficient and supports both static type checking and deep updates.
## How To Use Context
> This section documents a deprecated API. See the [new API](/docs/context.html).
Suppose you have a structure like:
```javascript
class Button extends React.Component {
render() {
return (
<button style={{background: this.props.color}}>
{this.props.children}
</button>
);
}
}
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button color={this.props.color}>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
render() {
const color = "purple";
const children = this.props.messages.map((message) =>
<Message text={message.text} color={color} />
);
return <div>{children}</div>;
}
}
```
In this example, we manually thread through a `color` prop in order to style the `Button` and `Message` components appropriately. Using context, we can pass this through the tree automatically:
```javascript{6,13-15,21,28-30,40-42}
import PropTypes from 'prop-types';
class Button extends React.Component {
render() {
return (
<button style={{background: this.context.color}}>
{this.props.children}
</button>
);
}
}
Button.contextTypes = {
color: PropTypes.string
};
class Message extends React.Component {
render() {
return (
<div>
{this.props.text} <Button>Delete</Button>
</div>
);
}
}
class MessageList extends React.Component {
getChildContext() {
return {color: "purple"};
}
render() {
const children = this.props.messages.map((message) =>
<Message text={message.text} />
);
return <div>{children}</div>;
}
}
MessageList.childContextTypes = {
color: PropTypes.string
};
```
By adding `childContextTypes` and `getChildContext` to `MessageList` (the context provider), React passes the information down automatically and any component in the subtree (in this case, `Button`) can access it by defining `contextTypes`.
If `contextTypes` is not defined, then `context` will be an empty object.
> Note:
>
> `React.PropTypes` has moved into a different package since React v15.5. Please use [the `prop-types` library instead](https://www.npmjs.com/package/prop-types) to define `contextTypes`.
>
> We provide [a codemod script](/blog/2017/04/07/react-v15.5.0.html#migrating-from-react.proptypes) to automate the conversion.
### Parent-Child Coupling
> This section documents a deprecated API. See the [new API](/docs/context.html).
Context can also let you build an API where parents and children communicate. For example, one library that works this way is [React Router V4](https://reacttraining.com/react-router):
```javascript
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
const BasicExample = () => (
<Router>
<div>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/topics">Topics</Link></li>
</ul>
<hr />
<Route exact path="/" component={Home} />
<Route path="/about" component={About} />
<Route path="/topics" component={Topics} />
</div>
</Router>
);
```
By passing down some information from the `Router` component, each `Link` and `Route` can communicate back to the containing `Router`.
Before you build components with an API similar to this, consider if there are cleaner alternatives. For example, you can pass entire React components as props if you'd like to.
### Referencing Context in Lifecycle Methods
> This section documents a deprecated API. See the [new API](/docs/context.html).
If `contextTypes` is defined within a component, the following [lifecycle methods](/docs/react-component.html#the-component-lifecycle) will receive an additional parameter, the `context` object:
- [`constructor(props, context)`](/docs/react-component.html#constructor)
- [`componentWillReceiveProps(nextProps, nextContext)`](/docs/react-component.html#componentwillreceiveprops)
- [`shouldComponentUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#shouldcomponentupdate)
- [`componentWillUpdate(nextProps, nextState, nextContext)`](/docs/react-component.html#componentwillupdate)
> Note:
>
> As of React 16, `componentDidUpdate` no longer receives `prevContext`.
### Referencing Context in Stateless Functional Components
> This section documents a deprecated API. See the [new API](/docs/context.html).
Stateless functional components are also able to reference `context` if `contextTypes` is defined as a property of the function. The following code shows a `Button` component written as a stateless functional component.
```javascript
import PropTypes from 'prop-types';
const Button = ({children}, context) =>
<button style={{background: context.color}}>
{children}
</button>;
Button.contextTypes = {color: PropTypes.string};
```
### Updating Context
> This section documents a deprecated API. See the [new API](/docs/context.html).
Don't do it.
React has an API to update context, but it is fundamentally broken and you should not use it.
The `getChildContext` function will be called when the state or props changes. In order to update data in the context, trigger a local state update with `this.setState`. This will trigger a new context and changes will be received by the children.
```javascript
import PropTypes from 'prop-types';
class MediaQuery extends React.Component {
constructor(props) {
super(props);
this.state = {type:'desktop'};
}
getChildContext() {
return {type: this.state.type};
}
componentDidMount() {
const checkMediaQuery = () => {
const type = window.matchMedia("(min-width: 1025px)").matches ? 'desktop' : 'mobile';
if (type !== this.state.type) {
this.setState({type});
}
};
window.addEventListener('resize', checkMediaQuery);
checkMediaQuery();
}
render() {
return this.props.children;
}
}
MediaQuery.childContextTypes = {
type: PropTypes.string
};
```
The problem is, if a context value provided by component changes, descendants that use that value won't update if an intermediate parent returns `false` from `shouldComponentUpdate`. This is totally out of control of the components using context, so there's basically no way to reliably update the context. [This blog post](https://medium.com/@mweststrate/how-to-safely-use-react-context-b7e343eff076) has a good explanation of why this is a problem and how you might get around it.
Loading…
Cancel
Save