上下文(Context) : React.createContext
上下文(Context) 提供了一种通过组件树传递数据
的方法,无需在每个级别手动传递 props 属性。
不必在树的每个层级显式传递一个 prop
Context
旨在共享一个组件树内可被视为 “全局” 的数据
适用于 组件直接将数据传递给 孙子级组件
当一些数据需要在不同的嵌套级别上被许多组件访问时,首先考虑使用 Context
两个概念:Provider(提供者)Consumer(消费者)
不使用Context,直接使用props一级级传递: 1 2 3 4 5 6 7 class App extends React .Component { render() { return <Toolbar theme ="dark" /> ; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 function Toolbar (props ) { return ( <div> <ThemedButton theme={props.theme} /> </div> ); }
1 2 3 4 5 6 class ThemedButton extends React .Component { render() { return <Button theme ={this.props.theme} /> ; } }
使用 context: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 const ThemeContext = React.createContext('light' );class App extends React .Component { render() { return ( <ThemeContext.Provider value="dark" > <Toolbar /> </ThemeContext.Provider> ); } }
1 2 3 4 5 6 7 8 9 function Toolbar (props ) { return ( <div> <ThemedButton /> </div> ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class ThemedButton extends React .Component { static contextType = ThemeContext; render() { return <Button theme ={this.context} /> ; } } ThemedButton.contextType = ThemeContext; class ThemedButton extends React .Component { render() { return ( <ThemeContext.Consumer> {value => <div > {value}</div > } </ThemeContext.Consumer> ) } }
Context API React.createContext
创建一个 Context
对象
defaultValue
参数 仅 当 consumer
(使用者) 在树中没有匹配的 Provider
(提供则) 时使用它
defaultValue
:默认值,可以是任何数据类型,
1 2 3 4 5 6 const MyContext = React.createContext(defaultValue);const ThemeContext = React.createContext({ theme: themes.dark, toggleTheme: () => {}, });
Context.Provider 提供者
接受一个 value
属性传递给使用组件(覆盖创建时初始化的 数据
),这个 consumer(使用者) 组件 为 Provider(提供者) 的后代组件
。
一个 Provider
可以连接到许多 consumers
。
每当 Provider(提供者) 的 value 属性发生变化时,所有作为 Provider(提供者) 后代的 consumer(使用者) 组件 都将重新渲染
value
值可以是组件的state
,方便动态改变上下文
value
值可以是组件的一个方法
,方便深层嵌套的组件动态改变该组件的数据
1 <MyContext.Provider value={}>
Context.Consumer
一个可以订阅 context
变化的 React
组件。 这允许您订阅 函数式组件 中的 context
。
接收一个 函数作为子节点。
该函数接收当前 context
值并返回一个 React 节点。
传递给函数的 value
参数将等于组件树中上层这个 context
最接近的 Provider
的 value
属性。
如果上层没有提供这个 context
的 Provider
,value
参数将等于传递给 createContext()
的 defaultValue
。
1 2 3 4 <MyContext.Consumer> {value => } </MyContext.Consumer>
Class(类组件).contextType:
类组件上的 contextType
属性可以绑定由 React.createContext()
创建的 Context
对象。
在组件中使用this.context
使用该 Context
类型的最近的当前值
。
可以在任何生命周期方法中引用它,包括 render
函数。
接收方式 MyClass.contextType = MyContext; 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 class MyClass extends React .Component { componentDidMount() { let value = this .context; } componentDidUpdate() { let value = this .context; } componentWillUnmount() { let value = this .context; } render() { let value = this .context; } } MyClass.contextType = MyContext;
从嵌套组件更新 context(context传递一个函数)
theme-context.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 export const themes = { light: { foreground: '#000000' , background: '#eeeeee' , }, dark: { foreground: '#ffffff' , background: '#222222' , }, }; export const ThemeContext = React.createContext({ theme: themes.dark, toggleTheme: () => {}, });
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 import {ThemeContext} from './theme-context' ;function ThemeTogglerButton ( ) { return ( <ThemeContext.Consumer> {({theme, toggleTheme} ) => ( <button onClick={toggleTheme} style={{backgroundColor : theme.background}}> Toggle Theme </button> )} </ThemeContext.Consumer> ); } export default ThemeTogglerButton;
app.js 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 import {ThemeContext, themes} from './theme-context' ;import ThemeTogglerButton from './theme-toggler-button' ;class App extends React .Component { constructor (props) { super (props); this .toggleTheme = () => { this .setState(state => ({ theme: state.theme === themes.dark ? themes.light : themes.dark, })); }; this .state = { theme: themes.light, toggleTheme: this .toggleTheme, }; } render() { return ( <ThemeContext.Provider value={this .state}> <Content /> </ThemeContext.Provider> ); } } function Content ( ) { return ( <div> <ThemeTogglerButton /> </div> ); } ReactDOM.render(<App /> , document .root);
使用多个 context 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 const ThemeContext = React.createContext('light' );const UserContext = React.createContext({ name: 'Guest' , }); class App extends React .Component { render() { const {signedInUser, theme} = this .props; return ( <ThemeContext.Provider value={theme}> <UserContext.Provider value={signedInUser}> <Layout /> </UserContext.Provider> </ThemeContext.Provider> ); } }
1 2 3 4 5 6 7 8 function Layout ( ) { return ( <div> <Sidebar /> <Content /> </div> ); }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 function Content ( ) { return ( <ThemeContext.Consumer> {theme => ( <UserContext.Consumer> {user => ( <ProfilePage user={user} theme={theme} /> )} </UserContext.Consumer> )} </ThemeContext.Consumer> ); }
高级使用 context: 创建 Provider 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 import React, { createContext } from 'react' const ToggleContext = createContext({ toggle: true , handleToggle: () => {} }) export class ToggleProvider extends React .Component { handleToggle = () => { this .setState({ toggle : !this .state.toggle }) } state = { toggle: true , handleToggle: this .handleToggle } render() { return ( <ToggleContext.Provider value={this .state}> {this .props.children} </ToggleContext.Provider> ) } } export const ToggleConsumer = ToggleContext.Consumer
上面的代码主要分为三大部分:
1 2 3 4 5 6 7 8 const ToggleContext = createContext()export class ToggleProvider extends React .Component {}export cnost ToggleConsumer = ToggleContext.Consumer
步骤解析
首先,我们需要引入 createContext
上下文并调用,传入我们希望在其他层级组件中使用的 state
和改变 state
的方法,注意这里的 state
和方法只是一个“骨架
”(或者说预设值),后面的 Provider
会覆盖
接下来创建 Provider
这里头维护真正的 state
,并通过 render
函数里面的 Context.Provider
组件的 value
属性传递和覆盖这些方法与属性
然后创建 Consumer
,直接导出 Context.Consumer
给外部使用即可
使用 Provider
使用 Provider
比较简单直接包裹在父组件上层
即可(直接作为父组件的父级)
下边的 App组件只是个示例,可以是任何 父组件
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import React from 'react' ;import { ToggleProvider } from './ToggleContext' function App ( ) { return ( <ToggleProvider> <Switcher></Switcher> {} </ToggleProvider> ); } export default App;
使用 Consumer
通过 Consumer
直接使用 props
传递的 state
属性在 render
函数中渲染即可
如果需要调用方法,则可调用 props
传递的函数
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 import React from 'react' ;import { ToggleProvider, ToggleConsumer } from './ToggleContext' function App ( ) { return ( <ToggleProvider> <Switcher></Switcher> </ToggleProvider> ); } const Switcher = () => { return <Pannel /> } const Pannel = () => { return ( <ToggleConsumer> {({ toggle, handleToggle } ) => <div onClick ={() => handleToggle()}>{ toggle ? '✔' : '❌'}</div > } </ToggleConsumer> ) } export default App;