本文已参与「新人创作礼」活动,一起开启掘金创作之路。
前言
本文主要内容:通过一个最简单的例子讲述如何使用context向组件传递参数
这几天忙着做学校里算法与数据结构设计周的项目,只是断断续续地看了一点react context的内容,每次看都觉得有点复杂,直到今天整体地看了一遍也总算捋清了里面的逻辑,心浮气躁的学习果然要不得。
项目预览与分析
是一个非常简单的例子,写了两个组件<Header />和<Button />。我们的目标就是通过react context传递参数,使其能够切换light/dark两种主题。以Hearder.js为例,此时的代码如下
import React, {Component} from "react"
class Header extends Component {
render() {
return (
<header className="light-theme">
<h2>Light Theme</h2>
</header>
)
}
}
export default Header
className为light-theme,所以显示的是light的主题,当设置className为dark-theme时,显示的是dark主题,所以我们要改变主题也就是通过参数改变className
这种由App组件直接调用的组件可以非常容易地通过props传递参数,但是如果是像上一篇文章写的有好几级组件,在这种情况下向各个需要的地方传递参数就不那么容易了,所以就会用到React Context。
创建一个Context
为了方便地向各个组件传递参数,我们首先要创建一个React Context,新建一个文件,命名为themeContext.js,然后编写如下代码来创建
import React from "react";
const ThemeContext = React.createContext()
export default ThemeContext
使用这个context
创建后就是使用context,需要知道对于context有两种身份,Provider和Consumer,所以当我们要向App提供参数时,使用如下代码
<ThemeContext.Provider value={"light"}>
<App />
</ThemeContext.Provider>
contextType
不过在使用Consumer之前,介绍另一种方法,以Header组件为例
import React, {Component} from "react"
import ThemeContext from "./themeContext"
class Header extends Component {
render() {
const theme = this.context
return (
<header className={`${theme}-theme`}>
<h2>{theme === "light" ? "Light" : "Dark"} Theme</h2>
</header>
)
}
}
Header.contextType = ThemeContext
export default Header
首先是引入ThemeContext,然后添加Header.contextType = ThemeContext
这样我们就将传入的参数放到了这个组件的context里,通过this调用
Button同理,再将传入的参数换成dark后,得到如下效果
Context.Consumer
还是以Header为例,使用consumer需要将组件化为函数组件,所以总体代码如下
import React from "react"
import ThemeContext from "./themeContext"
export default function Header(props) {
return (
<ThemeContext.Consumer>
{theme =>(
<header className={`${theme}-theme`}>
<h2>{theme === "light" ? "Light" : "Dark"} Theme</h2>
</header>
)}
</ThemeContext.Consumer>
)
}
同样是引入ThemeContext,然后用<ThemeContext.Consumer>包裹要输出的内容,以大括号包裹需要使用context的内容,并且箭头函数前的参数名便是指代context
在context自己的文件中设置参数
虽然说可以通过Context.Provider向App提供参数,但是肯定还是将参数和context集成在同一个文件中更清晰一点,所以为了直接使用context文件,首先要将其转换为一个组件,代码如下
import React, { Component } from "react";
const themeContext = React.createContext()
class ThemeContextProvider extends Component {
render() {
return (
<themeContext.Provider value={"light"}>
{this.props.children}
</themeContext.Provider>
)
}
}
export default ThemeContextProvider
可以看到此时我们写了一个ThemeContextProvider组件,为了使得后续使用更具有一致性,我们在这里另外提供consumer组件,所以代码如下
import React, { Component } from "react";
const {Provider, Consumer} = React.createContext()
class ThemeContextProvider extends Component {
render() {
return (
<Provider value={"light"}>
{this.props.children}
</Provider>
)
}
}
export {ThemeContextProvider, Consumer as ThemeContextConsumer}
使用时也是引入后调用即可
将context转化为对象
现在我们已经实现了在同一个文件中对context设置参数,但是目标是希望button组件有着切换主题的功能
所以首先在context文件中写下state和切换state的函数,如下
import React, { Component } from "react";
const {Provider, Consumer} = React.createContext()
class ThemeContextProvider extends Component {
state = {
theme: "dark"
}
toggleTheme = () => {
this.setState(prevState => {
return {
theme: prevState.theme === "light" ? "dark" : "light"
}
})
}
render() {
return (
<Provider value={this.state.theme}>
{this.props.children}
</Provider>
)
}
}
export {ThemeContextProvider, Consumer as ThemeContextConsumer}
那么接下来的目标就是将这个toggleTheme函数传给Button组件,所以第一步就是输出这个函数,如下
<Provider value={{theme: this.state.theme, toggleTheme: this.toggleTheme}}>
{this.props.children}
</Provider>
由于此时的参数是个对象,第二步则是要在接收上进行改动,这次以button为例
import React from "react"
import {ThemeContextConsumer} from "./themeContext"
export default function Button(props) {
return (
<ThemeContextConsumer>
{context => (
<button onClick={context.toggleTheme} className={`${context.theme}-theme`}>Switch Theme</button>
)}
</ThemeContextConsumer>
)
}
可以看到接收的参数为context,通过.来访问toggleTheme属性和theme属性。实现效果如下