Introduction: Refer to the React Chinese document for notes
What is Context?
In react applications, data is always passed top-down through props. This can be extremely cumbersome for certain types of attributes (e.g. locale preferences, UI themes). Context can share data that is “global” to a component tree. This eliminates the need to explicitly pass props layer by layer through the component tree
class App extends React.Component {
render() {
return <Toolbar theme="dark" />; }}/ / pass prop
function Toolbar(props) {
return (
<div>
<ThemedButton theme={props.theme} />
</div>
);
}
// Pass prop
class ThemedButton extends React.Component {
render() {
return <Button theme={this.props.theme} />; }}Copy the code
Using context avoids passing props through intermediate elements
//1. Create a context for theme. The default value is light
const ThemeContext = React.createContext('light');
class App extends React.Component {
render() {
return (
// 2. Use Provider to pass the theme. Here, pass on the dark
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>); }}/ /! Intermediate components need not be specified
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 3. Specify contextType to read the theme context object.
static contextType = ThemeContext;
// 4.React finds the nearest Provider and uses this.context to read the Provider's value.
render() {
return <Button theme={this.context} />; }}Copy the code
Context is mainly used when many components at different levels need to access the same data. Use with caution, as this makes components less reusable
API
React.createContext
Create a Context object:
const MyContext = React.createContext(defaultValue);
Copy the code
Context.Provider
The Context object returns a Provider React component:
<MyContext.Provider value={some value}/>
Copy the code
- The Provider receives a value property and passes it to the consumer component (the component inside the Provider React component).
- When the value of the Provider changes, all of its internal consuming components are re-rendered
- When the consuming component does not match the Provider, the Context object’s defaultValue parameter takes effect.
- A Provider can be associated with multiple consumer components. Multiple providers can also be nested, with the inner layer overwriting the data in the outer layer
Class.contextType
If the public Class Fields syntax is used, the contextType can be initialized static. ContextType specifies the Context object to read:
class MyClass extends React.Component {
static contextType = MyContext;
render() {
let value = this.context; }}Copy the code
The more common is class.contextType. Class. ContextType Reassigns to Context:
class MyClass extends React.Component {
/ /...
render() {
let value = this.context; }}/ / assignment
MyClass.contextType = MyContext;
Copy the code
The contextType mounted on the class will be reassigned to a Context object created by react.createcontext (). Allows you to use this.context to access the most recent context value. It can be accessed in any lifecycle
Context.Consumer
Render the React node based on the context value
<MyContext.Consumer>
{value= > /* Render based on context value */}
</MyContext.Consumer>
Copy the code
This requires the practice of function as a child. The React function takes the context value and returns a React node. The value passed to the function is the value provided by the Provider closest to the context.
Context.displayName
Change the name of the context object displayed in React DevTools
const MyContext = React.createContext(/* some value */);
MyContext.displayName = 'MyDisplayName';
<MyContext.Provider> // DevTools will display "myDisplayName.provider"
Copy the code
Example 01- Dynamic Context
Theme-context. js: stores the themes and theme context objects
//1. Declare a Themes object to store the theme export
export const themes = {
light: {
background: 'orange',},dark: {
background: '#eee',}};//2. Create the context object export
export const ThemeContext = React.createContext(
themes.dark //2. Set the default value dark
);
Copy the code
Themed Button.js: Creating a Themed button widget (ThemedButton)
//1. Introduce the theme context object
import {ThemeContext} from './theme-context';
class ThemedButton extends Component {
render() {
let props = this.props;
return (
<button
{. props}
style={{backgroundColor: this.context.background/ /}}3.Read the values / >); }}//2. Context is reassigned
ThemedButton.contextType = ThemeContext;
//4. Export button components
export default ThemedButton;
Copy the code
App.js
//1. Introduce the context object and themes object
import {ThemeContext, themes} from './theme-context';
//2. Introduce the button component
import ThemedButton from './themed-button';
// The middle component puts buttons to switch themes
function Toolbar(props) {
return (
<ThemedButton onClick={props.changeTheme}>
Change Theme
</ThemedButton>
);
}
/ / the parent component
class App extends Component {
constructor(props) {
super(props);
this.state = {
theme: themes.light,
};
//3. Define the event to switch the theme
this.toggleTheme = () = > {
this.setState(state= > ({
theme:state.theme === themes.dark? themes.light:themes.dark,
}));
};
}
render() {
return (
<div>{/* 4. Assign the value of the Context object's Provider */}<ThemeContext.Provider value={this.state.theme}>{/* 5.prop assign incoming event */}<Toolbar changeTheme={this.toggleTheme} />
</ThemeContext.Provider>}}}}}}}}}}}}}}}}}}}}}}<div>
<Toolbar />
</div>
</div>); }}export default App
Copy the code
Example 02- Updating the Context in a nested component
Pass a function through the context that causes the consuming component to update the context itself (scenario: update the context in a deeply nested component) :
theme-context.js
export const ThemeContext = React.createContext({
theme: themes.dark,
toggleTheme: () = >{}});Copy the code
theme-toggler-button.js
import {ThemeContext} from './theme-context';
// The button component not only gets the theme value, but also a toggleTheme function from the context
function ThemeTogglerButton() {
return (
// context. Consumer: Render the React node based on the Context value
<ThemeContext.Consumer>
{({theme, toggleTheme}) => (
<button onClick={toggleTheme}
style={{backgroundColor: theme.background}} >
Toggle Theme
</button>
)}
</ThemeContext.Consumer>
);
}
export default ThemeTogglerButton;
Copy the code
App.js
import {ThemeContext, themes} from './theme-context';
import ThemeTogglerButton from './theme-toggler-button';
class App extends Component {
constructor(props) {
super(props);
//1. Define events
this.toggleTheme = () = > {
this.setState(state= > ({
theme:state.theme === themes.dark? themes.light:themes.dark,
}));
};
/ / 2. Define the state
this.state = {
theme: themes.light,
toggleTheme: this.toggleTheme,
};
}
render() {
// 3. Assign a value to the Provider that contains the current topic and event
return (
<ThemeContext.Provider value={this.state}>
<ThemeTogglerButton />
</ThemeContext.Provider>); }}Copy the code
Example 03- Consuming multiple contexts
To ensure that the context is quickly rerendered, React needs to make each consuming component’s context a separate node in the component tree.
App.js
import ProfilePage from './ProfilePage'
// 1. Create the theme context
const ThemeContext = React.createContext({
bgColor:'#eee'.fontColor:'balck'
});
// 2. Create user context
const UserContext = React.createContext({
name: 'Guest'});class App extends Component {
constructor(props){
super(props)
//3. Set the desired state of the app component
this.state = {
theme: {
bgColor:'orange'.fontColor:'white'
},
user: {
name:'Jack'}}; }render() {
const {theme,user}=this.state
//4. Pass the value to the Provider
return (
<ThemeContext.Provider value={theme}>
<UserContext.Provider value={user}>
<Content />
</UserContext.Provider>
</ThemeContext.Provider>); }}function Content() {
//5. You can now access the theme and user passed by the Provider
return (
<ThemeContext.Consumer>
{theme => (
<UserContext.Consumer>
{user => (
<ProfilePage user={user} theme={theme} />
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
}
export default App
Copy the code
ProfilePage.js
export default function ProfilePage (props){
const {user,theme}=props
return(
// Pass an object to style
<div style={{display:'inline-block',padding:'5px 8px',backgroundColor:theme.bgColor.color:theme.fontColor}} >
{user.name}
</div>)}Copy the code
Sample source code is available in branches 10, 11, and 12