Context
Context provides a way to pass data through the component tree without having to pass props down manually at every level.
API
React.createContext
const MyContext = React.createContext(defaultValue);
Context.Provider
<MyContext.Provider value={/* some value */}>
Class.contextType
class MyClass extends React.Component {
componentDidMount() {
let value = this.context;
}
componentDidUpdate() {
let value = this.context;
}
componentWillUnmount() {
let value = this.context;
}
render() {
let value = this.context;
}
}
//The contextType property on a class can be assigned a Context object created by React.createContext()
MyClass.contextType = MyContext;
Context.Consumer
<MyContext.Consumer>
{value => /* render something based on the context value */}
</MyContext.Consumer>
The function receives the current context value and returns a React node.
Context.displayName
Context object accepts a displayName string property. React DevTools uses this string to determine what to display for the context.
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // "MyDisplayName.Provider" in DevTools
<MyContext.Consumer> // "MyDisplayName.Consumer" in DevTools
Example
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
static contextType = ThemeContext;
render() {
return <Button theme={this.context} />;
}
}
Dynamic Context
//theme-context.js
export const theme = {
light: {
foreground: '#000000',
background: '#eeeeee'
},
dark: {
foreground: '#ffffff',
background: '#222222'
}
};
export const ThemeContext = React.createContext(themes.dark);
//themed-button.js
import {ThemeContext} from './theme-context';
class ThemedButton extends React.Component {
render() {
let props = this.props;
let theme = this.context;
return (
<button
{...props}
style={{backgroundColor: theme.background}}
/>
);
}
}
ThemedButton.contextType = ThemeContext;
export default ThemedButton;
//app.js
import {ThemeContext, themes} from './theme-context';
import ThemedButton from './themed-button';
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light
};
}
this.toggleTheme = () => {
this.setState(state => ({
theme: state.theme === themes.dark ? themes.light : themes.dark
}));
};
render() {
return (
<Page>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar changeTheme={this.toggleTheme}/>
</ThemeContext.Provider>
<section>
<ThemedButton />
</section>
</Page>
);
}
}
ReactDOM.render(<App />, document.root);
Updating Context from a Nested Component
//theme-context.js
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () => {}
});
//theme-toggler-button.js
import {ThemeContext} from './theme-context';
function ThemeTogglerButton() {
return (
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button
onClick={toggleTheme}
style={{backgroundColor: theme.background}}
>
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
//app.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends React.Component {
constructor(props) {
super(props);
this.toggleTheme = () => {
this.setState(state => ({
theme: state.theme === themes.dark ? themes.light : themes.dark
}));
}
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme
};
render() {
return (
<ThemeContext.Provider value={this.state}>
<Content />
</ThemeContext.Provider>
);
}
}
}
function Content() {
return (
<div>
<ThemeTogglerButton />
</div>
);
}
ReactDOM.render(<App />, document.root);
Consuming Multiple Contexts
To keep context re-rendering fast, React needs to make each context consumer a separate node in the tree.
const ThemeContext = React.createContext('light');
const UserContext = React.createContext({name: 'Guest'});
class App extends React.Component {
render() {
const {signedInUser, theme} = this.props;
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={signedInUser}>
<Layout />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Layout() {
return (
<div>
<Sidebar />
<Content />
</div>
);
}
function Content() {
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
网友评论