how to use nested routing with react-native
Asked Answered
A

1

8

I am using react-native-router-flux for my apps main navigation. I need to setup a nested router. I have a map component that has a side bar with a List of Territories. When I click on a row I need to switch to a view that has the List of Subdivisions that belong to that Territory. I looked at some examples and tried to figure it out. Currently there are no errors in console but nothing shows up in the sidebar. If there is a better way of doing this please let me know. thanks!

Maprouter

    export default class RootRouter extends Component {
    render() {
        return(
            <Router hideNavBar={true}>
                <Schema name="default" sceneConfig={Navigator.SceneConfigs.FloatFromRight}/>
                <Route name="mapSurveyTerritories" wrapRouter={false} component={MapSurveyTerritories} initial={true}/>
                <Route name="mapSubdivisions" wrapRouter={false} component={MapSubdivisions} />
            </Router>
        );
    }
}

Map Component

BackAndroid.addEventListener('hardwareBackPress', function() {
    Actions.pop();
    return true;
});
export default class Map extends Component {
    constructor(props) {
        super(props);
        this.state = {
            region: Albuquerque,
        };
    }


    render() {
        const { region, markers,surveyTerritories,selectedMarket } = this.state;
        return (
          <View style={styles.container}>
                    <Navbar
                        title="Map"/>

            <View style={styles.innerContainer}>
                <MapView
                    style={styles.map}
                    initialRegion={region}
                    onLongPress={this.onPress.bind(this)}>
                    {markers.map(marker => (
                        <MapView.Marker
                            ref="m1"
                            key={marker.id}
                            coordinate={marker.coordinate}
                            title={marker.name}>
                        </MapView.Marker>
                    ))}
                </MapView>
                <ScrollView style={styles.sidebarContainer}>

                    <MapRouter />
                </ScrollView>
            </View>
          </View>
        );
    }
};

module.exports = Map;

Territories

class MapSurveyTerritories extends Component {
    constructor(props) {
        super(props);

        var ds = new ListView.DataSource({
            rowHasChanged: (r1, r2) => r1 != r2
        });

        this.state = {
            dataSource: ds,
            showProgress: true
        };
    }

    componentDidMount() {
        this.fetchTerritories();
    }

    fetchTerritories() {
        this.setState({
            dataSource: this.state.dataSource
                .cloneWithRows(territoriesAlbuquerque),
            showSpinner: false
        });
    }

    renderRow(rowData) {
        return (
            <TouchableHighlight
                onPress={()=>Actions.mapSubdivisions({selectedTerritory:rowData})}
                underlayColor='#ddd'>
                <View style={styles.row}>
                    <View style={{paddingLeft: 20}}>
                        <Text>
                            <Text style={{ fontWeight: '600' }}> {rowData.properties.name} </Text>
                        </Text>
                    </View>
                </View>
            </TouchableHighlight>
        );
    }

    render() {
        return (
            <View style={{flex: 1,justifyContent: 'flex-start'}}>
<ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow.bind(this)}/>
            </View>
        );
    }
}

module.exports = MapSurveyTerritories;

Subdivisions

class MapSubdivisions extends Component {
    constructor(props) {
        super(props);
var ds = new ListView.DataSource({
            rowHasChanged: (r1, r2) => r1 != r2
        });
this.state = {
            dataSource: ds
        };
    }

    componentDidMount() {
        this.fetchSubdivisions();
    }

    fetchSubdivisions() {
        console.log('fetchSubdivisions', this.props.selectedTerritory);
        this.setState({
            dataSource: this.state.dataSource
                .cloneWithRows(subdivisionsAlbuquerque),
            showSpinner: false
        });
    }

    renderRow(rowData) {
        return (
            <TouchableHighlight
                onPress={()=>Actions.mapSubdivisionDetail({selectedSubdivision:rowData})}
                underlayColor='#ddd'>
                <View style={styles.row}>
                    <View style={{paddingLeft: 20}}>
                        <Text>
                            <Text style={{ fontWeight: '600' }}> {rowData.properties.name} </Text>
                        </Text>
                    </View>
                </View>
            </TouchableHighlight>
        );
    }

    render() {
         return (
            <View style={{flex: 1,justifyContent: 'flex-start'}}>
                <ListView
                    dataSource={this.state.dataSource}
                    renderRow={this.renderRow.bind(this)}/>
            </View>
        );
    }
}

module.exports = MapSubdivisions;
Aventurine answered 22/3, 2016 at 14:17 Comment(0)
B
5

Right.

The best way to go about this is to use the Navigator through the component's props- so, in this case, if you have a ListView component that you'd like to move to a DetailedView component, simply call navigator.push (which should be passed to ListView through props).

In other words, you have Navigator getting passed down to ListView, available on this.props.navigator. Then (inside an onPress), just call a push on the navigator, feeding in the next component you'd like to render (along with any other props you'd like it to have as well).

In this case, I would expect your code to look something like this:

// Within the ListView component's 'onPress' event

this.props.navigator.push({
  component: DetailedView,
  location: this.props.location,
  // any other props you need to access inside DetailedView
});

Hope this helps!

Bumbledom answered 22/3, 2016 at 19:43 Comment(7)
Will try it out tonight. So I in the sthis Map Component. I would replace the Navigator Element and put back in place, <MainListView/>. Because that does load the listing correctly. And then i would implement the navigation props between the MainListView qnd DetailView? I come from a angular background so I am used to using ui-router for nested views. My question is how does the DetailView know where to render itself?Aventurine
No worries. Yes, you'll need to pass the navigator as a prop through MainListView to DetailView.Bumbledom
I updated the post with the MainListView. do you mind showing me what I need to do. I understand what you are saying as far as how it needs to work. just dont know how to implement itAventurine
Sorry- SO cut off my edits from the last comment. I meant to write: No worries. Yes, you'll need to pass the navigator as a prop through MainListView to DetailView. You can think of the navigator as a stack, pushing and popping views off of whatever its given. If you give the Navigator object a property 'SceneConfigs', you can set it to 'FloatFromBottom' (or left / right / etc) - so it knows where to come in from.Bumbledom
ok, i updated the post. I couldnt figure out how to get it going. Please take a look.Aventurine
Please note that you are using an outdated version of RNRF. Now working as V3 + RN ^.22Cursive
I'm confused, does react-native-router-flux really pass a navigator object in the props of each child automatically - or are you suggesting a solution that is irrelevant to RNRF ?Cephalo

© 2022 - 2024 — McMap. All rights reserved.