React Native - 从 NavigatorIOS 调用子函数

React Native - Call Function of child from NavigatorIOS

我正在尝试从父导航器上的右键调用子函数。

我需要的基本代码示例如下:

Main.js

<NavigatorIOS
    style={styles.container}
    initialRoute={{
        title: 'Test',
        component: Test,
        rightButtonTitle: 'Change String',
        onRightButtonPress: () => ***I Want to call miscFunction from here*** ,
        passProps: {
            FBId: this.state.fbidProp,
            favsPage: true
        }
    }}/>

Test.js

class Test extends React.Component{
    constructor(props){
        super(props);
        this.state = {
            variable: 'some string'
        };
    }
    miscFunction(){
        this.setState({
            variable: 'new string'
        };
    }
    render(){
        return(
            <Text> {variable} </Text>
        )
    }
}

这在以下 github 问题中有所介绍:

https://github.com/facebook/react-native/issues/31

Eric Vicenti 评论描述 Facebook 如何在内部解决这个问题:

Currently the best way to do that is to create an EventEmitter in the owner of the NavigatorIOS, then you can pass it down to children using route.passProps. The child can mix in Subscribable.Mixin and then in componentDidMount, you can

this.addListenerOn(this.props.events, 'myRightBtnEvent', this._handleRightBtnPress);

It is clear that this API needs improvement. We are actively working the routing API in Relay, and hopefully react-router, but we want NavigatorIOS to be usable independently. Maybe we should add an event emitter inside the navigator object, so child components can subscribe to various navigator activity:

this.addListenerOn(this.props.navigator.events, 'rightButtonPress', this._handleRightBtnPress);

这是一个实际示例:

'use strict';

var React = require('react-native');
var EventEmitter = require('EventEmitter');
var Subscribable = require('Subscribable');

var {
    AppRegistry,
    StyleSheet,
    Text,
    View,
    NavigatorIOS
} = React;

首先,我们引入所有需求,包括 EventEmitter 和 Subscribable。

var App = React.createClass({
    componentWillMount: function() {
        this.eventEmitter = new EventEmitter();
    },

    onRightButtonPress: function() {
        this.eventEmitter.emit('myRightBtnEvent', { someArg: 'argValue' });
    },

    render: function() {
        return <NavigatorIOS
                style={styles.container}
                initialRoute={{
                    title: 'Test',
                    component: Test,
                    rightButtonTitle: 'Change String',
                    onRightButtonPress: this.onRightButtonPress,
                    passProps: {
                        events: this.eventEmitter
                    }
                }}/>
    }
});

在我们的主要顶级组件中,我们创建了一个新的 EventEmitter(在 componentWillMount 中)以在整个组件中可用,然后使用 passProps 将其传递给 Test 我们为导航器指定的组件。

我们还为右按钮按下定义了一个处理程序,当该按钮被按下时它会发出一个带有一些虚拟参数的 myRightBtnEvent。现在,在 Test 组件中:

var Test = React.createClass({
    mixins: [Subscribable.Mixin],

    getInitialState: function() {
        return {
            variable: 'original string'
        };
    },

    componentDidMount: function() {
        this.addListenerOn(this.props.events, 'myRightBtnEvent', this.miscFunction);
    },

    miscFunction: function(args){
        this.setState({
            variable: args.someArg
        });
    },
    render: function(){
        return(
            <View style={styles.scene}><Text>{this.state.variable}</Text></View>
        )
    }
});

我们添加 Subscribable mixin,我们唯一需要做的另一件事就是监听 App 组件触发的 myRightBtnEvent 并挂钩 miscFunction 到此为止。 miscFunction 将从 App 新闻处理程序传递虚拟参数,因此我们可以使用它们来设置状态或执行其他操作。

你可以在 RNPlay 上看到这个的工作版本:

https://rnplay.org/apps/H5mMNQ

一个。在初始组件中

this.props.navigator.push({
    title: 'title',
    component: MyComponent,
    rightButtonTitle: 'rightButton',
    passProps: {
        ref: (component) => {this.pushedComponent = component},
    },
    onRightButtonPress: () => {
        // call func
        this.pushedComponent && this.pushedComponent.myFunc();
    },
});

乙。在推送组件中
替换推送组件中的 onRightButtonPress 函数。

componentDidMount: function() {
    // get current route
    var route = this.props.navigator.navigationContext.currentRoute;
    // update onRightButtonPress func
    route.onRightButtonPress =  () => {
        // call func in pushed component
        this.myFunc();
    };
    // component will not rerender
    this.props.navigator.replace(route);
},

您可以使用 flux, here is a demo: https://github.com/backslash112/react-native_flux_demo