aksonov/react-native-router-flux

how to use nested scene?

Closed this issue ยท 17 comments

Version

Tell us which versions you are using:
"react-native-router-flux": "3.31.1",

  • react-native-router-flux v3.?.?

  • react-native v0.?.?

    "react": "15.2.1",
    "react-native": "0.30.0",

Expected behaviour

Go to nested scene2 without error

Actual behaviour

I go to the scene1 by clicking the scene1 tab at the bottom of the screen, then red screen shows with error as below:
ExceptionsManager.js:61 Objects are not valid as a React child (found: object with keys {key, name, sceneKey, parent, type, children, index, sceneStyle}). If you meant to render a collection of children, use an array instead or wrap the object using createFragment(object) from the React add-ons. Check the render method of View.

my router config:

router_config.txt

ps: I want the sub-scenes share the same parent scene.

Also seeing this behaviour. Example:

<Scene key='apply' component={ApplyWrapper}>
  <Scene key='address' component={Address} />
  <Scene key='mobile' component={Mobile} />
</Scene>

I think reason for the error is that ApplyWrapper is being passed the scene objects as children and doesn't know what to do with them. A possible solution in the wrapper is to map scenes:

const mappedChildren = this.props.children.map(scene => React.createElement(scene.component))

This is pretty horrible. I believe a custom renderer might also be a solution but the documentation around this isn't great. Either way it seems daft that ApplyWrapper would need to know about the router - it should just be rendering the component.

afilp commented

Is my error related to this issue too?

See here:
#1589

The interesting part is that it works once I open the Chrome (V8) debugger. What is different there?

Desired the same functionality with my scene setup as:

export default (
  <Scene key="root" hideNavBar={true} component={Layout}>
    <Scene key="login" component={Login} />
  </Scene>
);

Solution provided by Colin works with the following versions:

    "react": "~15.4.0-rc.4",
    "react-native": "0.40.0",
    "react-native-router-flux": "~3.37.0",

As an aside; Out of interest @afilp - what i18n library are you using within your React app?

As an update; I took a peek under the hood, and I saw DefaultRenderer being used by the Modal component etc, and it's exposed by react-native-router-flux. I was able to provide my wrapping Layout as:

import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { DefaultRenderer } from 'react-native-router-flux';

class Layout extends Component {
  constructor(props) {
    super(props)
  }

  render() {
    const children = this.props.navigationState.children;
    const state = children[0];

    return (
      <View>
        <Text>Parent Layout</Text>
        <DefaultRenderer
          navigationState={state}
          key={state.key}
          {...state}
          onNavigate={this.props.onNavigate}
        />
      </View>
    )
  }
}

export default Layout;

I'm not sure if this is the intent of DefaultRenderer, however it is an alternative solution to @colinramsay's answer

I implemented it as you suggested @AlanFoster, but none of my TouchableHighlights work anymore. If I remove the Layout on my root scene, it all works. Any idea where to look?

afilp commented

@AlanFoster

  1. I do not use any 'i18n library' (at least not explicitly, could a dependency may do this? Does it matter somehow?)

  2. Is this error related to issue #1589 ? Why does it work with certain settings? (Hot reloading AND Debug JS on?)

afilp commented

We found something new.

We changed
import 'babel-polyfill';

TO:
require('babel-polyfill');

and now it works!

I wonder why (and why the problem was only on Android, not iOS).

The above statement is the 1st one on Main.js component, even above the React and React Native imports (as the instructions say).

I had the same problem withe nested Scenes and solution of colinramsay worked for me as well:

 <Provider store={store}>
        <Router>
            <Scene key="root" component={App}>
                <Scene key="search" component={Search} />
                <Scene key="common" component={Info} />
            </Scene>
        </Router>
    </Provider>

that means (in my case) using:
{this.props.children.map(scene => React.createElement(scene.component))}
instead of:
{this.props.children}
in {App}.
I think it would be a good idea to mention this workaround in the docs as nested layouts are very common (drawers, sidebars...). E.g. i use it with react-elements sidebar.

@axlider Did you have any trouble accessing the passed props in your children scenes? When I map them like you suggest, I lose access to them.

no trouble. The nested components look like this:

 <SideMenu
                isOpen={true}
                menu={MenuComponent}>
                <ScrollView
                    toggleSideMenu={false}
                >
                {this.props.children.map(scene => React.createElement(scene.component))}
                </ScrollView>
 </SideMenu>

But this is just what i can say about my initial view. I didn't try out any dynamic navigation yet.

So I've tried out nested scenes using the workarounds mentioned here, but I wouldn't recommend it, since it seems to break scene transition animations.

How does it look like in your case (breaking scene transition animations)?
When i open close the drawer in my nested sidebar example i cannot observe anything suspicous.

@axlider All of my transitions were were rendering like REPLACE transitions.

@petermikitsh
Aha. i do the same, but works fine.

@colinramsay
if use

<Scene key='apply' component={ApplyWrapper}>
<Scene key='address' component={Address} />
<Scene key='mobile' component={Mobile} />
</Scene>

When I call Actions.address({buzzId: 1}) to push into the Address component, I can not get the buzzId by this.props.buzzId in the Address.
Do you konw how to get the passed params?

@leonardgithub having the same issue. Did you find a way to resolve to get the props passed on the Action call?

@leonardgithub @donovantc have you looked at the data prop from your scene?