React Native 解決 Navigator.pop 無法傳引數

Bob-Chen發表於2019-03-04

緊接著上一篇文章 React Native 中實現二維碼掃描 當時掃是掃了,東西是出來了,但是並沒有做介面返回,而自帶的 navigator.pop 方法又沒有引數傳遞,那不是白掃了嗎?

封裝 Navigator

好吧, 這步其實和下面講的沒有什麼關係,不過為了看下面內容的時候不會混淆,這裡還是簡單說下。

React Native 提供了兩個導航元件,NavigatorIOS 和 Navigator。 NavigatorIOS 封裝程度比較高,比較好用,但是隻能在 iOS 上用,Navigator 相對封裝程度比較低,但是為了以後能方便的給 Android 用,我們還是封裝一下 Navigator。

`use strict`;

import React, {Component} from `react`;
import {
    View,
    Text,
    ScrollView,
    StyleSheet,
    Navigator
} from `react-native`;

export default class Navigation extends Component {

    render() {
        return (
            <Navigator
                initialRoute = {{ name:``, component:this.props.component, index:0 }}
                configureScene = { ()=>{ return Navigator.SceneConfigs.FloatFromBottom; } }
                renderScene = {(route, navigator) => {
                    const RouteComponent = route.component;
                    return (
                        <View style={{ flex:1, paddingTop: 64 }}>
                            <RouteComponent navigator={navigator} route={route} {...route.passProps} />
                        </View>
                    )
                }} />
        )
    }
}複製程式碼

這裡使用了 {...route.passProps} 是為了保持和 NavigatorIOS 一樣的介面,這裡轉場動畫規定了用從下到上彈出的方式,可以在 configureScene = { ()=>{ return Navigator.SceneConfigs.FloatFromBottom; } } 這裡修改。

後面的 this.props.navigator 就是從 navigator={navigator} 這裡來的。

呼叫的時候還有一點要注意,千萬不要在 Navigator 外面包任何的 View 或者別的什麼,會報錯。

index.ios.js中呼叫:

  render() {
    return (
          <Navigation component={Xxxx} />
    );
  }複製程式碼

方法一 — 使用回撥

利用 passProps 傳一個 callback 函式進去。

呼叫的地方,book_list.js:


    _changeText(val) {
        this.setState({
            keywords:val
        })
    }

    _scan(){
        this.props.navigator.push({
            component: ScanView,
            passProps: {
                navigator: this.props.navigator,
                callback: this._changeText
            }
        })
    }複製程式碼

這裡的 this._changeText 換成一個匿名函式也可以。

返回的地方,scan_view.js:


    _show(val) {
        this.setState({
            code:val.data
        })

        // Use navigator pop
        if( this.props.callback ){
            this.props.callback(val.data)
        }

        if( this.props.navigator ){
            this.props.navigator.pop();
        }

    }複製程式碼

通過頁面加回撥函式的確可以解決這個問題,但是如果有多個頁面要用到我掃描的資料,那我除了要在用到掃描資料本身的 View 裡面做邏輯,在掃描這個 View 裡面也要做邏輯,每多一個地方要傳資料,就多一個回撥函式。直覺告訴我,這很坑爹。

方法二 — 使用 DeviceEventEmitter

DeviceEventEmitter 是 React Native 提供的,在 Native 和 JavaScript 之間傳遞訊息用的。類似一個釋出訂閱模式,由 DeviceEventEmitter.emit 來發布訊息,需要用到的地方使用 DeviceEventEmitter.addListener 來訂閱訊息。

呼叫的地方,book_list.js:


    componentDidMount() {
        this.subscription = DeviceEventEmitter.addListener(`finishScan`,this._changeText);
    }

    componentWillUnmount() {
        this.subscription.remove();
    }複製程式碼

注意,這裡我們訂閱訊息是在元件 mount 之後,同時我們需要在合適的時候手動取消訂閱 this.subscription.remove(); 否則可能會導致記憶體洩露。

返回的地方,scan_view.js:


    _show(val) {
        this.setState({
            code:val.data
        })

        // Use DeviceEventEmitter
        DeviceEventEmitter.emit(`finishScan`,val.data);

        if( this.props.navigator ){
            this.props.navigator.pop();
        }

    }複製程式碼

這裡就是當我們掃描到東西,就觸發一個叫 finisScan 的事件,並退出當前 View,在 book_list.js 中就可以收到這個事件,並做相應處理。如果有別的地方需要用到掃描的資料,直接訂閱這個事件就可以了,在 scan_view.js 中不需要額外的處理。

在除錯過程中,還遇到一個問題 A valid provisioning profile for this executable was not found
大意就是證照沒了,開啟我的除錯裝置 iPad,通用-描述檔案與裝置管理 果然上週做掃描的時候用的證照沒了,Xcode 開啟專案,找到簽名證照那裡,原來這種測試證照是有期限的,一個星期,剛好剛才過期了。重新點一下又可以獲得七天的 buff 了。

React Native 解決 Navigator.pop 無法傳引數

總結

有時候當你意識到用了一種不好的方法實現了某個功能的時候,你需要去尋找尋找是否有更優雅的方法,畢竟人生已經如此的艱難,不要為自己挖坑。

碎碎念

最近總想記錄一些所思所想,寫寫科技與人文,寫寫生活狀態,寫寫讀書感悟,主要是扯淡和感悟,歡迎關注,交流。

微信公眾號:程式設計師的詩和遠方

公眾號ID : MonkeyCoder-Life

React Native 解決 Navigator.pop 無法傳引數

參考

reactnative.cn/docs/0.36/n…

www.jianshu.com/p/f7d569407…

bbs.reactnative.cn/topic/20/%E…

相關文章