React的context就是一個全域性變數,可以從根元件跨級別在React的元件中傳遞。React context的API有兩個版本,React16.x之前的是
老版本的context,之後的是新版本的context。
1.老版本的context
getChildContext 根元件中宣告,一個函式,返回一個物件,就是context
childContextTypes 根元件中宣告,指定context的結構型別,如不指定,會產生錯誤
contextTypes 子孫元件中宣告,指定要接收的context的結構型別,可以只是context的一部分結構。contextTypes 沒有定義,context將是一個空物件。
this.context 在子孫元件中通過此來獲取上下文
(注:從React v15.5開始 ,React.PropTypes 助手函式已被棄用,可使用 prop-types 庫 來定義contextTypes)
舉例如下:
//根元件 class MessageList extends React.Component { getChildContext() { return {color: "purple",text: "item text"}; } render() { const children = this.props.messages.map((message) => <Message text={message.text} /> ); return <div>{children}</div>; } } MessageList.childContextTypes = { color: React.PropTypes.string text: React.PropTypes.string }; //中間元件 class Message extends React.Component { render() { return ( <div> <MessageItem /> <Button>Delete</Button> </div> ); } } //孫元件(接收元件) class MessageItem extends React.Component { render() { return ( <div> {this.props.text} </div> ); } } MessageItem.contextTypes = { text: React.PropTypes.string }; class Button extends React.Component { render() { return ( <button style={{background: this.context.color}}> {this.props.children} </button> ); } } Button.contextTypes = { color: React.PropTypes.string };
2.新版本的context
新版本的React context使用了Provider和Customer模式,和redux-react的模式非常像。在頂層的Provider中傳入value,
在子孫級的Consumer中獲取該值,並且能夠傳遞函式,用來修改context,如下程式碼所示:
//建立Context元件 const ThemeContext = React.createContext({ theme: 'dark', toggle: () => {}, //向上下文設定一個回撥方法 }); //執行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() { return ( <ThemeContext.Provider value={this.state}> //state包含了toggle方法 <Content /> </ThemeContext.Provider> ); } } //中間元件 function Content() { return ( <div> <Button /> </div> ); } //接收元件 function Button() { return ( <ThemeContext.Consumer> {({theme, toggle}) => ( <button onClick={toggle} //呼叫回撥 style={{backgroundColor: theme}}> Toggle Theme </button> )} </ThemeContext.Consumer> ); }
詳細用法可以參考官方文件:https://react.docschina.org/docs/context.html#reactcreatecontext
3. context在如下的生命週期鉤子中可以使用
constructor(props, context)
componentWillReceiveProps(nextProps, nextContext)
shouldComponentUpdate(nextProps, nextState, nextContext)
componentWillUpdate(nextProps, nextState, nextContext)
componentDidUpdate(prevProps, prevState, prevContext)
4. 在無狀態元件中可以通過引數傳入
function D(props, context) { return ( <div>{this.context.user.name}</div> ); } D.contextTypes = { user: React.PropTypes.object.isRequired }
5. React context的侷限性
1. 在元件樹中,如果中間某一個元件 ShouldComponentUpdate returning false 了,會阻礙 context 的正常傳值,導致子元件無法獲取更新。
2. 元件本身 extends React.PureComponent 也會阻礙 context 的更新。
注意點:
1. Context 應該是唯一不可變的
2. 元件只在初始化的時候去獲取 Context
參考:https://www.tuicool.com/articles/nUryimf
https://segmentfault.com/a/1190000012575622