Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Manipulate NavigatorIOS route on a component

I'm trying to build a very simple Todo application in React Native. It's composed of two views : one with a list of tasks, one with an input field (to add a new one). Navigation is assured by a NavigatorIOS and buttons on it (which would have been UIBarButtonItem with UIKit).

On the list view, there is a Add right button on Navigator, on the view with the text field, there the back button on the left and a Done one on the right. When clicking on done, it should add a new task with content of text field.

Problem is, buttons and their actions are defined when creating the NavigatorIOS component, and I don't find a way to attach a method defined in another component as a button action.

As an example, here is my NavigatorIOS

class TodoList extends Component {

    render() {
        return (
            <NavigatorIOS
                ref="nav"
                style={styles.navbar}
                initialRoute={{
                    component: ItemList,
                    title: 'Todo list',
                    rightButtonTitle: 'Add',
                    onRightButtonPress: () => {
                        this.refs.nav.push({
                            title: 'Add a new task',
                            component: AddTodo,
                            rightButtonTitle: 'Done',
                            onRightButtonPress: () => {
                                console.log('done !');
                            }
                        });
                    }
                }}
            />
        );
    }
}

I don't put here my two other components ItemList and AddTodo as there is nothing interesting on it.

What I need is a way to make components communicate (like in delegation pattern) with the navigation component.

Perhaps it's not possible, or I am totally wrong on the paradigm used with React Native, so feel free to comment if something is not clear on my question.

Edit 05/26

Actually, Facebook team is aware that something is missing to handle that use case with NavigatorIOS component.

From Eric Vicenti (posted on February 3 2015) on an issue on GitHub that exactly covers my question.

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);
like image 605
Blackus Avatar asked Apr 29 '15 12:04

Blackus


1 Answers

A. In initial component

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

B. In pushed component
replace onRightButtonPress func in pushed component.

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);
},
like image 163
Jichao Wu Avatar answered Oct 14 '22 13:10

Jichao Wu