如圖:APP
界面嵌套A
嵌套B
嵌套C
嵌套D
嵌套E
嵌套F
......
場景一:從APP
界面獲取數(shù)據(jù)惠毁,需要F
來顯示,怎么把APP
界面的值傳遞給F
袁辈?使用props
一層一層的逐級向下傳遞么??
場景二:最底層F
需要觸發(fā)一個事件onClick
盔然,需要APP界面來接受參數(shù)并進行下一步的操作锣夹,怎么在F
中觸發(fā)onClick
然后APP
界面也響應進行處理减牺?使用props{callBack=>{}}
逐級向上傳遞么??
answer:NO
API
趕快使用 Context 吧~
let { Provider, Consumer } = React.createContext()
創(chuàng)建一對{ Provider, Consumer }
豌习。當 React 渲染 context 組件 Consumer
時,它將從組件樹的上層中最接近的匹配的 Provider
讀取當前的 context
值拔疚。
React.createContext(defaultValue)
可以指定默認值肥隆,當Provider
沒有value
時,Consumer
中取的就是defaultValue
稚失;當Provide
r存在value
時栋艳,會把defaultValue
進行覆蓋,Consume
r中取的就是Provider
的value
- ?
Provider
和Consumer
是 一一對應滴~BConsumer
是取不到AProvider
中的value
滴~- ?
Provider
組件的value
值發(fā)生變更時句各,其內(nèi)部組件樹中對應的Consumer
組件會接收到新值并重新執(zhí)行 內(nèi)部 函數(shù)吸占。此過程不受shouldComponentUpdete
方法的影響晴叨。- ?
Provider
組件利用Object.is
檢測value
的值是否有更新。注意Object.is
和===
的行為不完全相同呀
Provider
<Provider value={/* some value */}>
...
</Provider>
接收一個 value
屬性傳遞給Provider
的后代 Consumers
旬昭。一個 Provider
可以鏈接到多個 Consumers
篙螟。Providers
可以被嵌套以覆蓋組件樹內(nèi)更深層次的值。
Provider
包裹的組價內(nèi)部 可以通過Consumers
訪問到 Provider
的value
值
??????注意:盡量不要在這里
<Provider value={/* some value */}>
給value
賦具體的值,比如<Provider value={{key: 'value',key1: 'value1'...}}
因為只要render
執(zhí)行一次问拘,Provider
的value
就會返回一個全新的{}
,不管里面的值是否改變,與Provider
對應的Consumer
都會重新執(zhí)行一次惧所。為了減少不必要的刷新骤坐,盡量使用state
,然后配合PureComponent
進行性能優(yōu)化
Consumer
<Consumer>
{
value => {
coding......
}
}
</Consumer>
注意 Consumer
內(nèi)部是一個方法下愈,有一個value
纽绍。這個參數(shù)就是 Provider
的 value
。得到value
势似,可以在方法里面進行相應的操作拌夏,返回組件或者存值都可以
使用
context.js
import React from "react";
const AppContext = React.createContext()
const AContext = React.createContext()
const BContext = React.createContext()
export {
AppContext,
AContext,
BContext
}
APP界面
this.state = {
title: '123',
}
render() {
return (
<View>
<TouchableOpacity style={{marginTop: 50, width: 100 ,height: 44, backgroundColor: 'white',justifyContent: 'center',alignItems: 'center'}}
onPress={()=>{
// 點擊按鈕修改數(shù)據(jù)
this.setState({
title: '456'
})
}}>
<Text>點擊改變數(shù)據(jù)</Text>
</TouchableOpacity>
//Provider 包裹組件
<AppContext.Provider value={this.state}>
<A/>
</AppContext.Provider>
</View>
);
}
A中有B中有C中有D中有E中有F,代碼就不都貼了 只貼F中的代碼
F
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>F</Text>
<TouchableOpacity onPress={()=>{
}}>
<Text style={styles.text}>點擊在根視圖觸發(fā)方法</Text>
</TouchableOpacity>
<AppContext.Consumer>
{
context => {
// 可以獲取到 context 在其他地方進行處理
this.contextDataApp = context
return <View>
<Text style={styles.text}>context App:{context.title}</Text>
</View>
}
}
</AppContext.Consumer>
</View>
);
}
OK 以上代碼就可以解決場景一
的問題了履因,不需要每一層都需要props進行向下傳遞數(shù)據(jù)障簿。
開始解決場景二
的問題,其實方法和props
差不多栅迄,傳遞到Consumer
中的value
中含有一個方法即可
APP
this.state = {
title: '123',
bottomClick:this.bottomClick
}
bottomClick(){
console.log('頂層視圖 方法調(diào)用 bottomClick')
}
<AppContext.Provider value={this.state}>
...
</AppContext.Provider>
F
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>F</Text>
<TouchableOpacity onPress={()=>{
// 在此處也可以調(diào)用
this.contextDataApp.bottomClick()
}}>
<Text style={styles.text}>點擊在根視圖觸發(fā)方法</Text>
</TouchableOpacity>
<AppContext.Consumer>
{
context => {
// 可以獲取到 context 在其他地方進行處理
this.contextDataApp = context
return <View>
<Text onPress={()=>{
context.bottomClick() //也可以傳遞參數(shù)
}} style={styles.text}>context App:{context.title}</Text>
</View>
}
}
</AppContext.Consumer>
</View>
);
}
ok 以上代碼就可以解決場景二
的問題了
延伸一點點~
由于 AppContext.Provider
可以對應很多個 AppContext.Consumer
如果 AppContext.Provider
的 value
確定站故,有很多個組件需要 value
的值,那豈不是每個組價都要使用 AppContext.Consumer
進行包裹~
蹬蹬蹬蹬蹬蹬蹬蹬丟丟丟
高階組件登場 ~
高階組件的介紹和使用點這里嘍~
高階組件
import React, {Component} from 'react'
import {AppContext} from './TestContext'
import App from "../App";
export default (WrappedComponent) => {
class NewComponent extends Component {
render(){
return <AppContext.Consumer>
{
context=><WrappedComponent {...this.props} context={context}/>
}
</AppContext.Consumer>
}
}
return NewComponent
}
這里<WrappedComponent {...this.props} context={context}/>
傳遞給普通組件一個 props
毅舆,普通組件可以使用this.props.context
進行數(shù)據(jù)操作
使用 E 頁面 進行模擬
import React, {PureComponent, Component} from 'react';
import {BackAndroid,
TouchableOpacity,
View,
StyleSheet,
Dimensions,
Text
} from "react-native"
const {width, height} = Dimensions.get('window')
import PropTypes from 'prop-types'
import F from './F'
import HocCompenent from './hocComponent'
class E extends Component {
componentDidMount() {
// 拿到 頂層視圖的 value
console.log('E this.props.context=',this.props.context)
}
render() {
return (
<View style={styles.view}>
<Text style={styles.text}>E context:{this.props.context.title}</Text>
<F/>
</View>
);
}
}
const styles = StyleSheet.create({
view: {
width: width - 60 - 60 - 60 - 60,
height: height - 44 - 60 - 60 - 60 - 60,
backgroundColor: 'red',
justifyContent: 'center',
alignItems: 'center'
},
text: {
color: 'white',
fontSize: 20
}
})
// 高階組件使用
export default HocCompenent(E)
最后的最后~
神坑在此~西篓,諸位神魔自行入坑~
Provider不是你想用就可以用的~
最開始使用的舊版本的 API(react16.3.0以前)
,舊版本限制太多,還是別使用憋活,具體的可自行百度岂津、google。
使用新版本的API悦即,還要看 react 和 reactNative 版本~~??
新建最新的項目 使用Provider 會報 undefined is not an object (evaluating 'context._currentValue = currentValue')
或者 Cannot set property '_currentValue' of undefined
等~錯誤
要不說google大法好呢吮成,google work ~~ 不過還是要多關注Issues~
不得不說得吐槽下 開發(fā)人員了。盐欺。赁豆。。這么多人提問題冗美,魔种,,你們新建一個項目用一下不就知道了么粉洼,咋不自測下呢~