簡體   English   中英

從react-native的Navigator按鈕調用組件函數

[英]Call a component function from react-native's Navigator buttons

我看到這個問題在非常不同的環境中四處徘徊,沒有任何直接解決方案。 有人問我,我正在向我展示一些示例,說明如何使用導航執行我想要的代碼,因為其中大多數已經采用了第三方解決方案,或者使用<View>

為了使問題有一定的背景,這是我們要完成的工作:

class Example extends Component {
    componentRouteMapper() {
        switch(route.id) {
            case 'home' return <Home navigator={navigator} { ...this.props } />
        }
    }

    navigationBarRouteMapper = {
        LeftButton: (route, navigator, index, navState) => {
            return <TouchableOpacity onPress={this.onLeftPressed.bind(this)}>
                <Text>Left Button</Text>
            </TouchableOpacity>
        },
        RightButton: (route, navigator, index, navState) => {
            // ... Same as left
        },
        Title: (route, navigator, index, navState) => {
            return <Text>{route.id}</Text>
        }
    }

    render() {
        return <Navigator initialRoute={{id: 'home'}}
            renderScene={this.componentRouteMapper}
            navigationBar={
                <Navigator.NavigationBar { ...this.props } 
                    routeMapper={this.navigationBarRouteMapper}/>
            }

    }
}

自然,您將希望能夠從已渲染組件的上下文中處理導航欄邏輯。 在這種情況下: <Home /> ,我們將希望能夠從該組件活動實例共享狀態/屬性。 即使您在home組件中聲明了onLeftPressed() ,執行上述代碼也會導致錯誤,如下所示:

export default class Home extends Component {

    onLeftPressed() {
        console.log('Pressed left button')
    }

    render() {
        return <View>
            <Text>Home Component</Text>
        </View>
    }
}

所以眼前的問題是...如何從navigationBarRouteMapper調用onRightPressed()

它實際上非常簡單,雖然還有其他方法,例如在Router中注入組件,但是考慮到我的應用程序使用Redux ,將connect()方法傳遞給Route對象有點麻煩。

因此,我想出了一個簡單而有效的解決方案,無論您使用什么來管理狀態,該解決方案都可以工作。 注射劑 沒錯,只需將您需要調用的內容直接插入到navigation對象中即可。

可以通過this.props.navigator從組件內部訪問navigation對象,這對我們來說是幸運的,Javascript對象是可變的,並通過引用自然傳遞。 這意味着我們對導航器對象所做的任何更改都將反映在注入到navigationBarRouteMapper

因此,首先讓我們更改一些代碼:

navigationBarRouteMapper = {
    LeftButton: (route, navigator, index, navState) => {
        return <TouchableOpacity onPress={navigator.__onLeftNavButtonPressed}>
            <Text>Left Button</Text>
        </TouchableOpacity>
    },
    RightButton: (route, navigator, index, navState) => {
        // ... Same as left
    },
    Title: (route, navigator, index, navState) => {
        return <Text>{navigator.navTitle || route.id}</Text>
    }
}

您會注意到,我已經將onPress值從{this.onLeftPressed.bind(this)}更改為{navigator.__onLeftNavButtonPressed}現在顯然可以更改正在使用的名稱,但是我喜歡雙下划線前綴。

您還將看到我將標題更改為返回{navigator.navTitle || route.id} {navigator.navTitle || route.id}而不是route.id ,這意味着它將使用navigator中的navTitle屬性(如果可用),如果不可用,則將使用堆棧頂部的路由ID。

現在,讓我們對<Home />組件進行更改,以便我們的navigationBarRouteMapper執行我們想要的代碼。

class Home extends Component {

    constructor(props) {
        super(props)
        var navigator = this.props.navigator
        navigator.navTitle = 'Home'
        navigator.__onLeftNavButtonPressed = this.onLeftPressed.bind(this)
    }

    onLeftPressed() {
        console.log('Pressed left button')
    }

    render() {
        return <View>
            <Text>Home Component</Text>
        </View>
    }
}

如您所見,唯一更改的是添加了一個constructor(...) ,該函數將函數和標題注入了navigator對象。 現在,如果單擊左按鈕,將在Home組件內部執行onLeftPressed函數。

但是,您可以通過創建自定義組件子類來對其進行抽象。 例如:

import React, { Component } from 'react'

export default class NavComponent extends Component {
    constructor(props) {
        super(props)
        console.warn('Constructed')
        var navigator = this.props.navigator
        navigator.navbarTitle = this.__onNavTitleRequested();
        navigator.__onLeftNavButtonPressed = this.__onLeftNavButtonPressed.bind(this)
        navigator.__onRightNavButtonPressed = this.__onRightNavButtonPressed.bind(this)
    }


    __onLeftNavButtonPressed() {

    }

    __onRightNavButtonPressed() {

    }

}

這樣可以確保始終設置左右導航按鈕功能,即使它們什么也不做,也可以防止由於嘗試調用未定義的功能而導致應用程序錯誤。 您還將注意到,存在對__onNavTitleRequested的引用,但是對此沒有默認功能,這是為了確保子類必須定義__onNavTitleRequested ,否則應用程序將無法正常運行。 這樣可以防止您在標題欄中使用標題不正確的組件,因為如果您未設置標題,它將始終使用最后設置的標題。

一個實現此目的的示例如下:

import React from 'react'
import NavComponent from './path/to/nav-component.js'

export default class Home extends NavComponent {
    __onNavTitleRequested() {
        return 'Home'
    }

    __onLeftNavButtonPressed() {
        console.log('Left navigation button pressed')
    }

    __onRightNavButtonPressed() {
        console.log('Right navigation button pressed')
    }

    render() {
        return <View>
            <Text> Home Component </Text>
        </View>
    }
}

這會將一個事件注冊到“向左/向右”按鈕並設置Home組件的標題。 您也可以向Navigator對象中注入更多信息,例如,如果您想讓__hasNavigationBar函數返回true或false以隱藏整個導航欄,或者__rightNavButton函數返回要在右側按鈕上顯示的組件,只是一個TouchableOpacity按鈕。

如前所述,還有其他方法可以做到這一點,但是考慮到我在應用程序中使用Redux似乎是最簡單的方法,而我對此沒有任何問題。

一種替代方法是使用事件總線,例如react-native-event-listeners。 我能夠通過這種方式解決問題,並且比Hobbyist的解決方案簡單得多。

基本上,它的工作方式是按鈕將消息發送給接收方,然后接收方(在組件的上下文中)將執行必要的操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM