React-Native Context跨層級的組件通信

場景

如圖: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稚失;當Provider存在value時栋艳,會把defaultValue進行覆蓋,Consumer中取的就是Providervalue

  • ? ProviderConsumer 是 一一對應滴~ 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訪問到 Providervalue

??????注意:盡量不要在這里 <Provider value={/* some value */}>value 賦具體的值,比如 <Provider value={{key: 'value',key1: 'value1'...}}
因為只要render執(zhí)行一次问拘,Providervalue就會返回一個全新的{},不管里面的值是否改變,與Provider對應的Consumer都會重新執(zhí)行一次惧所。為了減少不必要的刷新骤坐,盡量使用state,然后配合PureComponent進行性能優(yōu)化

Consumer

<Consumer>
  {
      value => {
          coding......
      }
  }
</Consumer>
注意 Consumer 內(nèi)部是一個方法下愈,有一個value纽绍。這個參數(shù)就是 Providervalue。得到value势似,可以在方法里面進行相應的操作拌夏,返回組件或者存值都可以
image.png

image.png

使用

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.Providervalue 確定站故,有很多個組件需要 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~

image.png

不得不說得吐槽下 開發(fā)人員了。盐欺。赁豆。。這么多人提問題冗美,魔种,,你們新建一個項目用一下不就知道了么粉洼,咋不自測下呢~

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末节预,一起剝皮案震驚了整個濱河市叶摄,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌安拟,老刑警劉巖蛤吓,帶你破解...
    沈念sama閱讀 206,839評論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異糠赦,居然都是意外死亡会傲,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評論 2 382
  • 文/潘曉璐 我一進店門拙泽,熙熙樓的掌柜王于貴愁眉苦臉地迎上來淌山,“玉大人,你說我怎么就攤上這事顾瞻∑靡桑” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評論 0 344
  • 文/不壞的土叔 我叫張陵荷荤,是天一觀的道長退渗。 經(jīng)常有香客問我,道長蕴纳,這世上最難降的妖魔是什么会油? 我笑而不...
    開封第一講書人閱讀 55,371評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮袱蚓,結(jié)果婚禮上钞啸,老公的妹妹穿的比我還像新娘。我一直安慰自己喇潘,他們只是感情好体斩,可當我...
    茶點故事閱讀 64,384評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著颖低,像睡著了一般絮吵。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上忱屑,一...
    開封第一講書人閱讀 49,111評論 1 285
  • 那天蹬敲,我揣著相機與錄音,去河邊找鬼莺戒。 笑死伴嗡,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的从铲。 我是一名探鬼主播瘪校,決...
    沈念sama閱讀 38,416評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了阱扬?” 一聲冷哼從身側(cè)響起泣懊,我...
    開封第一講書人閱讀 37,053評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎麻惶,沒想到半個月后馍刮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡窃蹋,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,007評論 2 325
  • 正文 我和宋清朗相戀三年卡啰,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片脐彩。...
    茶點故事閱讀 38,117評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡碎乃,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出惠奸,到底是詐尸還是另有隱情,我是刑警寧澤恰梢,帶...
    沈念sama閱讀 33,756評論 4 324
  • 正文 年R本政府宣布佛南,位于F島的核電站,受9級特大地震影響嵌言,放射性物質(zhì)發(fā)生泄漏嗅回。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,324評論 3 307
  • 文/蒙蒙 一摧茴、第九天 我趴在偏房一處隱蔽的房頂上張望绵载。 院中可真熱鬧,春花似錦苛白、人聲如沸娃豹。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽懂版。三九已至,卻和暖如春躏率,著一層夾襖步出監(jiān)牢的瞬間躯畴,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評論 1 262
  • 我被黑心中介騙來泰國打工薇芝, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留蓬抄,地道東北人。 一個月前我還...
    沈念sama閱讀 45,578評論 2 355
  • 正文 我出身青樓夯到,卻偏偏與公主長得像嚷缭,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子黄娘,可洞房花燭夜當晚...
    茶點故事閱讀 42,877評論 2 345

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理峭状,服務發(fā)現(xiàn)克滴,斷路器,智...
    卡卡羅2017閱讀 134,600評論 18 139
  • 一次偶然的機會优床,讀完了三毛的撒哈拉的故事劝赔。 剛拿到這本書的時候,我心里就有一種莫名的悲傷胆敞,或許是因為知道一些關...
    探凡閱讀 225評論 0 0
  • 泡沫 日[うたかた][utakata] 【名詞】 (1)泡沫着帽。(水の上に浮く泡)。 泡沫の如く消える/像泡沫一樣瞬...
    萌囧囧閱讀 434評論 0 0
  • [玫瑰]看到今天小文移层,讓我想起在劉老師智慧父母班課程中聽過這樣一個故事仍翰,叫國王的黃金床:有一位國王,想用黃金打造一...
    悅僮老師閱讀 273評論 0 0
  • 2018.9.8 晴 星期六 今天是親子日記的第一百零一十四天观话。 今天下班早去小飯桌接著女兒早回家予借,回到家...
    小徐_390d閱讀 154評論 0 0