介绍
在 React 中,数据通常从顶部到底部通过插件(父母组件到儿童组件)流动,但这并不总是理想的。
在这种情况下,使用 Redux来管理状态似乎是一个好主意,但许多人认为 这不应该是你的第一个选择 。
React Context是一个替代的解决方案,可以通过组件共享数据,而无需在每个级别上手动传递准则。
在本文中,您将探索背景API,并了解如何使用它来管理用户状态。
前提条件
要跟随这篇文章,你将需要:
本教程已通过 Node v15.3.0、npm v6.14.9 和 react v17.0.1 进行验证。
了解问题
以下是通过用户
和avatarSize
的组件的示例:
1<Page user={user} avatarSize={avatarSize} />
使一个PageLayout
组件:
1<PageLayout user={user} avatarSize={avatarSize} />
使一个NavigationBar
组件:
1<NavigationBar user={user} avatarSize={avatarSize} />
返回一个链接
和Avatar
,使用用户
和avatarSize
特征:
1<Link href={user.permalink}>
2 <Avatar user={user} size={avatarSize} />
3</Link>
在上面的例子中,只有Avatar
组件实际上使用了用户
组件,但是它的每个祖先组件(父母,祖父母等)都接收了用户
并将其传递下来,这意味着如果Avatar
组件在未来需要另一个组件,你将不得不确保它的每个祖先组件接收和传递它。
实际上,用户
状态需要在许多不同的组件中共享,因此通过它作为一个支撑将导致它比上面的例子更深入。
创建React.createContext
React.createContext
方法返回一个Context
对象. 这个Context
对象配备了两个重要的 React 组件,允许用户订阅数据:供应商
和消费者
。
当 React 返回订阅此背景
对象的组件时,它会读取树上最接近匹配的提供商
组件的当前背景值。
「CreateContext」方法采用可选的「默认值」参数,如果在树中找不到匹配的「Context.Provider」组件,则将其提供给「Context.Consumer」。
创建一个背景
对象,并将其导出用于其他组件:
1[label src/userContext.js]
2import React from 'react';
3
4const userContext = React.createContext({user: {}});
5
6export { userContext };
在上面的示例中,您初始化了userContext
,并提供了DefaultValue
的{user: {}}
。
现在你有一个背景
对象,你可以为它提供一个值,并订阅更改。
应用Context.Provider
将用户状态作为值传输到context.Provider
,这样它就可以被context.Consumer
消耗:
1[label src/App.js]
2import React from 'react';
3
4import Main from './Main';
5
6import {userContext} from './userContext';
7
8class App extends React.Component {
9 constructor(props) {
10 super(props);
11 this.state = {
12 user: {}
13 };
14 }
15
16 componentDidMount() {
17 // get and set currently logged in user to state
18 }
19
20 render() {
21 return (
22 <userContext.Provider value={this.state.user}>
23 <Main/>
24 </userContext.Provider>
25 );
26 }
27}
28
29export default App;
这是一个很好的开始,包装主
组件与userContext.Provider
确保您传递的价值可以消耗在任何主
的后代子组件中。
应用Context.Consumer
userContext.Consumer
接收一个函数作为一个孩子. 该函数接收当前的背景值(作为向 userContext.Provider
传递的代码的值)并返回一个 React 节点。
1[label src/Main.js]
2import Sidebar from './Sidebar';
3import Content from './Content';
4import Avatar from './Avatar';
5
6import {userContext} from './userContext';
7
8function Main(props) {
9 return (
10 <Sidebar/>
11 <userContext.Consumer>
12 {({value}) => {
13 <Avatar value={value}/>
14 }}
15 </userContext.Consumer>
16 <Content/>
17 )
18}
19
20export default Main;
在这种情况下,它将应用程序
组件的state.user
作为值,并返回一个Avatar
组件。
从嵌入式组件中更新背景
到目前为止,您已经使用 React Context 将数据传输到需要数据的组件中,而无需手动传输附件。
考虑一个按钮来登录用户。
在这种情况下,您可以通过相同的背景传递函数,以允许消费者更新该背景。
1[label src/App.js]
2import React from 'react';
3
4import Main from './Main';
5
6import {userContext} from './userContext';
7
8class App extends React.Component {
9 constructor(props) {
10 super(props);
11 this.state = {
12 user: {}
13 };
14
15 this.logout = this.logout.bind(this);
16 }
17
18 logout() {
19 this.setState({user: {}});
20 }
21
22 componentDidMount() {
23 // get and set currently logged in user to state
24 }
25
26 render() {
27 const value = {
28 user: this.state.user,
29 logoutUser: this.logout
30 }
31
32 return (
33 <userContext.Provider value={value}>
34 <Main/>
35 </userContext.Provider>
36 );
37 }
38}
39
40export default App;
传递到更新背景的函数可以在userContext.Provider
组件中的任何嵌入组件中使用。
1[label src/Main.js]
2import Sidebar from './Sidebar';
3import Content from './Content';
4import Avatar from './Avatar';
5import LogoutButton from './LogoutButton';
6
7import {userContext} from './userContext';
8
9function Main(props) {
10 return (
11 <Sidebar/>
12 <userContext.Consumer>
13 {({user, logoutUser}) => {
14 return (
15 <Avatar user={user}/>
16 <LogoutButton onClick={logoutUser}/>
17 );
18 }}
19 </userContext.Consumer>
20 <Content/>
21 )
22}
23
24export default Main;
登录按钮已被添加到主要
组件中。
这就总结了如何使用React的Context API来管理用户状态的例子。
结论
在本文中,您被介绍了 React Context,并使用Context.Producer
和Context.Consumer
。
如果您想了解更多关于 React 的信息,请查看我们的 如何在 React.js 中编码系列,或查看 我们的 React 主题页面以获取练习和编程项目。