Context 基本使用
Context 设计目的是为了共享那些对于一个组件树而言是“全局”的数据,例如当前认证的用户、主题或首选语言。
import React from "react";
// 创建一个ThemeContext
const ThemeContext = React.createContext("light");
class App extends React.Component {
state = { theme: "dark" };
render() {
return (
// 包裹消费组件,并提供value
<ThemeContext.Provider value={this.state.theme}>
<Toolbar />
</ThemeContext.Provider>
);
}
}
function Toolbar() {
return (
<div>
<ThemedButton />
</div>
);
}
class ThemedButton extends React.Component {
// 使用静态contexType属性去接ThemeContext,然后这个组建中都可以使用this.context,他的是就是 <ThemeContext.Provider value="dark">中的value
static contextType = ThemeContext;
render() {
return <div>{this.context}</div>;
}
}
export default App;
什么时候使用Context
一些全局状态需要在子孙组件中使用,这时候我们将考虑Context。我们先不使用redux等状态管理库,比如我们自己封装组建是不考虑这些外部库的。但是很多情况我们是不需要使用Context也可以达到一样的目的。我改改上面的例子如下:
import React from "react";
class App extends React.Component {
state = { theme: "dark" };
render() {
const themeButton = <ThemedButton theme={this.state.theme} />;
return <Toolbar themeButton={themeButton} />;
}
}
function Toolbar(props) {
return (
<div>
{/* <ThemedButton /> */}
{props.themeButton}
</div>
);
}
function ThemedButton(props) {
return <div>{props.theme}</div>;
}
export default App;
Context API
Cntext.displayName
const ThemeContext = React.createContext("light");
ThemeContext.displayName = 'MyThemeContext'
context 对象接受一个名为 displayName 的 property,类型为字符串。React DevTools 使用该字符串来确定 context 要显示的内容。
Context.Consumer
我们改写第一部分的ThemedButton如下
const ThemedButton = ()=> {
// 这里不使用static contextType = ThemeContext
// 我们用 <ThemeContext.Consumer>{value=>{}}</ThemeContext.Consumer>
return <ThemeContext.Consumer>{value=><div>{value}</div>}</ThemeContext.Consumer>
}
这里使用函数组件去消费context
如何在嵌套组件中直接更新context
我们继续改写上面的例子
import React from "react";
// 创建一个ThemeContext
const ThemeContext = React.createContext("light");
ThemeContext.displayName = "MyThemeContext";
class App extends React.Component {
changeTheme = (theme) => {
this.setState({ theme });
};
state = { theme: "dark", changeTheme: this.changeTheme };
render() {
return (
// 包裹消费组件,并提供value
<ThemeContext.Provider value={this.state}>
<Toolbar />
</ThemeContext.Provider>
);
}
}
function Toolbar() {
return (
<div className="tool-bal">
<ThemedButton />
</div>
);
}
const ThemedButton = () => {
// 这里不使用static contextType = ThemeContext
// 我们用 <ThemeContext.Consumer>{value=>{}}</ThemeContext.Consumer>
return <ThemeContext.Consumer>{({theme, changeTheme}) => <div onClick={()=>{changeTheme('pure')}}>{theme}</div>}</ThemeContext.Consumer>;
};
export default App;
其实就是context里面可以提供函数。
如何消费多个Context
import React from "react";
const admin = { user: "admin" };
// 创建一个ThemeContext
const ThemeContext = React.createContext("light");
const UserContext = React.createContext(admin);
ThemeContext.displayName = "MyThemeContext";
UserContext.displayName = "MyUserContext";
class App extends React.Component {
changeTheme = (theme) => {
this.setState({ theme: { theme } });
};
state = {
theme: { theme: "dark", changeTheme: this.changeTheme },
user: "gavin",
};
render() {
return (
// 包裹消费组件,并提供value
<ThemeContext.Provider value={this.state.theme}>
<UserContext.Provider value={this.state.user}>
<Toolbar />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
}
function Toolbar() {
return (
<div className="tool-bal">
<ThemedButton />
</div>
);
}
const ThemedButton = () => {
// 这里不使用static contextType = ThemeContext
// 我们用 <ThemeContext.Consumer>{value=>{}}</ThemeContext.Consumer>
return (
<ThemeContext.Consumer>
{({ theme, changeTheme }) => (
<UserContext.Consumer>
{(user) => (
<div
onClick={() => {
changeTheme("pure");
}}
>
{theme}-{user}
</div>
)}
</UserContext.Consumer>
)}
</ThemeContext.Consumer>
);
};
export default App;
使用Context要注意的事
Context.Provider value属性事浅比较,不要使用字面量。应该是value={this.state}
value={{something: 'something'}} ❌
value={this.state.value} ✔️