持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第1天,点击查看活动详情
Context
在 React 中组件间的数据通信是通过 props 进行的,父组件给子组件设置 props,子组件给后代组件设置 props,props 在组件间自上向下(父传子)的逐层传递数据。但并不是所有的数据都适合这种传递方式,有些数据需要再多个组件中共同使用,如果还通过 props 一层一层的传统,就很麻烦。
Context 为我们提供了一种在不同组件间共享数据的方式,它不再拘泥于 props 刻板的逐层传递,而是在外层组件中统一设置,设置后内层所有的组件都可以访问到 Context 中所存储的数据。换句话说,Context 类似于 JS 中的全局作用域,可以将一些公共数据设置到一个同一个 Context 中,使得所有的组件都可以访问到这些数据。
使用
放在 src/store 中
// src/store/testContext.js
import React from "react"
const TestContext = React.createContext({
name: "孙悟空",
age: 18
})
export default TestContext
- 使用方式1
- 引入
context - 使用
XXX.Consumer组件来创建元素
- 引入
注意,这里包裹的是一个函数,函数的参数 ctx 就是我们 context 中定义的对象
import React from 'react'
import TestContext from '../store/testContext'
export default function A() {
return (
<TestContext.Consumer>
{/* 这里ctx就是我们context中定义的对象 */}
{(ctx) => {
return <div>
{ctx.name} - {ctx.age}
</div>
}}
</TestContext.Consumer>
)
}
- 使用方式二
- 导入
Context - 使用钩子函数
useContext获取contextuseContext需要一个Context作为参数- 它会将
Context中数据获取并作为返回值返回
- 导入
import React, { useContext } from 'react'
import TextContext from "../store/testContext"
export default function B() {
// 使用钩子函数获取context
const ctx = useContext(TextContext)
return (
<div>
{ctx.name} -- {ctx.age}
</div>
)
}
注意,因为这种用法是钩子函数,所以只能用于函数组件,类组件只能用方法一
- 使用方式三:生产者、消费者
XXX.Provider 表示数据的生产者,可以使用它来指定 Context 中的数据
通过 value 来指定 Context 中存储的数据
这样一来,在该组件的所有子组件中都可以通过 Context 来访问它所指定的数据
import React, { useState } from 'react'
import B from './components/B';
import TextContext from "./store/testContext"
export default function App() {
return (
<TextContext.Provider value={{name: "猪八戒", age:28}}>
<div>
<B />
</div>
</TextContext.Provider>
)
}
就近原则:当我们通过
Context访问数据时,他会读取离他最近的Provider中的数据。如果没有
Provider,则读取Context中的默认数据
子组件使用
import CartContext from '../../../store/cart-context';
import React, { useContext } from 'react'
export default function Counter(props) {
const ctx = useContext(CartContext)
const addButtonHandler = () => {
ctx.addItem(props.meal)
}
const subButtonHandler = () => {
ctx.removeItem(props.meal)
}
return (
<div className={classes.Counter}>
...
</div>
)
}