14. react - context
1. react 中的 context 使用了生产者消费者模式 【Provider和Customer模式】。
2. 可以在顶层的Provider中传入value,在子孙级的Consumer中获取该值,并且能够传递函数,用来修改context
// 1. context.js 中 import React from 'react' const ThemeContext = React.createContext({ theme: 'dark', toggle: () => {}, //向上下文设定一个回调方法 }); // const ThemeContext = React.createContext('light'); export default ThemeContext
// 2. index.js 中 import ThemeContext from './context' import Content from './Toolbar' const themes = { dark: 'dark', light: 'light' } // //运行APP class App extends React.Component { constructor(props) { super(props); this.toggle = () => { //设定toggle方法,会作为context参数传递 this.setState(state => ({ theme: state.theme === themes.dark ? themes.light : themes.dark, })); }; this.state = { theme: themes.light, toggle: this.toggle, }; } render() { //state包含了toggle方法 return ( <ThemeContext.Provider value={this.state}> <Content /> </ThemeContext.Provider> ); } } ReactDOM.render( <App />, document.getElementById('root') )
// 3. 中间组件 Toolbar.js import React from 'react' import Button from './ThemeButton' export default class Toolbar extends React.Component{ constructor (props) { super(props) } render () { return ( <div> <Button /> </div> ) } }
// 4. 子组件 Button.js import React from 'react' import ThemeContext from './context' class Button extends React.Component { constructor (props) { super(props) } render () {
// context.Consumer 中必须是一个函数式组件。这个函数接收当前的 context 值,返回一个 React 节点。 return ( <ThemeContext.Consumer> {({theme, toggle}) => ( <button onClick={toggle} style={{backgroundColor: theme}}> {theme} </button> )} </ThemeContext.Consumer> ) } }
3. 如何使用 this.context: 挂载在 class 上的 contextType
属性会被重赋值为一个由 React.createContext()
创建的 Context 对象。这能让你能在任何生命周期中使用 this.context
import React from 'react' import ThemeContext from './utils' class Button extends React.Component { constructor (props) { super(props) } render () { console.log(this.context, "BBBBBBBBBBBB") return ( <ThemeContext.Consumer> {({theme, toggle}) => ( <button onClick={toggle} style={{backgroundColor: theme}}> {theme} </button> )} </ThemeContext.Consumer> ) } } Button.contextType = ThemeContext //调用后可以在 Button 的组件的类中使用this.context export default Button
4. 那些生命周期中可以使用 this.context
constructor(props, context)
componentWillReceiveProps(nextProps, nextContext)
shouldComponentUpdate(nextProps, nextState, nextContext)
componentWillUpdate(nextProps, nextState, nextContext)
componentDidUpdate(prevProps, prevState, prevContext)
import React from 'react' import ThemeContext from './utils' class Button extends React.Component { constructor (props, context) { super(props, context) console.log(context) } componentWillReceiveProps(nextProps, nextContext) { console.log(nextContext, "componentWillReceiveProps context") } shouldComponentUpdate(nextProps, nextState, nextContext) { console.log(nextContext, "shouldComponentUpdate context") } componentWillUpdate(nextProps, nextState, nextContext) { console.log(nextContext, "componentWillUpdate context") } componentDidUpdate(prevProps, prevState, prevContext) { console.log(prevContext, "componentDidUpdate context") } render () { console.log(this.context, "BBBBBBBBBBBB") return ( <ThemeContext.Consumer> {({theme, toggle}) => ( <button onClick={toggle} style={{backgroundColor: theme}}> {theme} </button> )} </ThemeContext.Consumer> ) } } Button.contextType = ThemeContext export default Button
5. React context的局限性
1. 在组件树中,如果中间某一个组件 ShouldComponentUpdate returning false 了,会阻碍 context 的正常传值,导致子组件无法获取更新。
2. 组件本身 extends React.PureComponent 也会阻碍 context 的更新。