React-context
1、Context 简介
Context 提供了一个传递数据的方法,避免了在每一个层级手动的传递 props 属性。
在一个典型的 React 应用中,数据是通过 props属性由上向下(由父及子)的进行传递的,但这对于某些类型的属性而言是极其繁琐的(例如:地区偏好,UI主题),这是应用程序中许多组件都所需要的。
Context 提供了一种在组件之间共享此类值的方式,而不必通过组件树的每个层级显式地传递 props 。
2、context API
1)React.createContext:
const {Provider, Consumer} = React.createContext(defaultValue);
- 创建一对 { Provider, Consumer }。当 React 渲染 context 组件 Consumer时,它将从组件树的上层中最接近的匹配的 Provider 读取当前的 context 值。
- 如果上层的组件树没有一个匹配的 Provider,而此时你需要渲染一个 Consumer 组件,那么你可以用到 defaultValue。这有助于在不封装它们的情况下对组件进行测试。
2)Provider(提供者):
<Provider value={/* some value */}>
- React 组件允许 Consumers 订阅 context 的改变。
- 接收一个 value 属性传递给 Provider 的后代 Consumers。一个 Provider 可以联系到多个 Consumers。Providers 可以被嵌套以覆盖组件树内更深层次的值。
3)Consumer(消费者):
<Consumer>
{value => /* render something based on the context value */}
</Consumer
- 一个可以订阅 context 变化的 React 组件。
- 接收一个 函数作为子节点. 函数接收当前 context 的值并返回一个 React 节点。传递给函数的 value 将等于组件树中上层 context 的最近的 Provider 的 value 属性。如果 context 没有 Provider ,那么 value 参数将等于被传递给 createContext() 的 defaultValue 。
PS:
- 每当Provider的值发生改变时, 作为Provider后代的所有Consumers都会重新渲染。
- 从Provider到其后代的Consumers传播不受shouldComponentUpdate方法的约束,因此即使祖先组件退出更新时,后代Consumer也会被更新。
3、context 传递静态数据
就是引用公共的 React.createContext()创建的实例。
context.js
import React from "react";
export const ThemeContext = React.createContext(
themes.dark // 默认值
);
app.js(父级)
import { ThemeContext, themes } from "./context";
import Children from "./Children";
class App extends React.Component {
constructor(props) {
super(props);
this.state = {
theme2: {
name: "theme2",
background: "red",
},
};
}
render() {
return (
<div>
<ThemeContext.Provider value={this.state.theme2}>
<Children></Children>
</ThemeContext.Provider>
</div>
);
}
}
export default App;
children.js(子级)
import React, { Component } from "react";
import { Context, ThemeContext } from "./context.js";
import Children2 from "./Children2";
class Children extends Component {
static contextType = Context;
render() {
return (
<ThemeContext.Consumer>
{(theme) => (
<div>
主题颜色(子组件):{theme.background}
<Children2></Children2>
</div>
)}
</ThemeContext.Consumer>
);
}
}
export default Children;
children2.js (孙级)
import React from "react";
import { ThemeContext } from "./context";
class Children2 extends React.Component {
render() {
return (
<ThemeContext.Consumer>
{(theme) => <div>主题Name(孙子组件):{theme.name}</div>}
</ThemeContext.Consumer>
);
}
}
export default Children2;
4、context 传递动态数据
context.js
import React from "react";
export const themes = {
light: {
name: "light",
background: "#222222",
},
dark: {
name: "dark",
background: "#eeeeee",
},
};
export const ThemeContext = React.createContext(
themes.dark // 默认值
);
app.js (父级&子级)
import { ThemeContext, themes } from "./context";
import ThemedButton from "./themed-button";
// 一个使用到ThemedButton组件的中间组件
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() {
// ThemedButton 位于 ThemeProvider 内
// 在外部使用时使用来自 state 里面的 theme
// 默认 dark theme
return (
<div>
<ThemeContext.Provider value={this.state.theme}>
<Toolbar changeTheme={this.toggleTheme} />
</ThemeContext.Provider>
</div>
);
}
}
export default App;
themed-button.js(孙级)
import { ThemeContext } from "./context";
function ThemedButton(props) {
return (
<ThemeContext.Consumer>
{(theme) => (
<button
{...props}
style={{ backgroundColor: theme.background }}
/>
)}
</ThemeContext.Consumer>
);
}
export default ThemedButton;
按钮主题切换:
参考链接:
React 文档