javascript - 从 react-native 的 Navigator 按钮调用组件函数

标签 javascript reactjs react-native

这是一个我在完全不同的上下文中看到的问题,没有任何直接的解决方案。一些人还问我,我正在展示一些示例,说明如何让导航执行我想要的代码,因为他们中的大多数人已经使用第三方解决方案或使用创建了自己的导航标题<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 />我们将希望能够共享来自该组件事件实例的状态/ Prop 。执行上面的代码会导致错误,即使你有 onLeftPressed()在您的主页组件中声明,如下所示:

export default class Home extends Component {

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

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

所以手头的问题是......你怎么称呼onRightPressed()来自 navigationBarRouteMapper

最佳答案

这实际上很简单,虽然还有其他方法,例如在路由器中注入(inject)组件,但考虑到我的应用程序使用 Redux传入 connect() Route 对象的方法有点麻烦。

因此,我想出了一个简单而有效的解决方案,无论您使用什么来管理您的状态,它都可以正常工作。 注入(inject)。没错,只需将您需要调用的任何内容直接注入(inject)您的 navigation目的。

navigation可以通过 this.props.navigator 从您的组件中访问对象对我们来说幸运的是,Javascript 对象是可变的,并且本质上是通过引用传递的。这意味着我们对导航器对象所做的任何更改都将反射(reflect)在注入(inject)到 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}而不仅仅是 route.id这意味着它将使用 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(...)。将函数和标题注入(inject) navigator目的。现在,如果您单击左侧按钮,您将执行onLeftPressed。在你的 Home 中运行组件。

但是您可以通过创建自定义组件子类来进一步抽象它。例如:

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>
    }
}

这将向左/右按钮注册一个事件并设置主页组件的标题。您也可以将更多信息注入(inject) Navigator 对象,例如,如果您想要一个 __hasNavigationBar函数返回 true 或 false 以隐藏整个导航栏,或者可能是 __rightNavButton函数返回要显示在右侧按钮上的组件,而不仅仅是一个 TouchableOpacity 按钮。

正如我之前所说,还有其他方法可以做到这一点,但考虑到我正在以这种方式在我的应用程序中使用 Redux 似乎是最简单的,而且我没有遇到任何问题。

关于javascript - 从 react-native 的 Navigator 按钮调用组件函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39254219/

相关文章:

javascript - 在哪里可以找到 _id.$oid 的 mongodb 文档?

javascript - 如何使用表单中的输入变量来更新另一个 php 的图表?

javascript - 按图像过滤 不想显示所有图像

javascript - react 。 setState 不更新子组件的状态

javascript - react native 出现奇怪的样式表错误

javascript - 在给定日期上添加两个小时

javascript - ReactJS + react 路由器 : How to center div?

Javascript 语法 null : ? {}

android - 如何自定义世博推送通知的图标?

javascript - 从 AsyncStorage 检索 JWT 以使用 ApolloClient 创建 httpLink 中间件时出现问题