Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modal and nested Stack routing configuration #3277

Closed
michelebombardi opened this issue Sep 19, 2018 · 2 comments
Closed

Modal and nested Stack routing configuration #3277

michelebombardi opened this issue Sep 19, 2018 · 2 comments

Comments

@michelebombardi
Copy link
Contributor

michelebombardi commented Sep 19, 2018

Version

  • react-native-router-flux v4.0.1
  • react v16.4.1
  • react-native v0.57.0

From the example I see that structure:

<Router createReducer={reducerCreate} onStateChange={stateHandler} getSceneStyle={getSceneStyle} uriPrefix={prefix}>
    <Overlay key="overlay">
      <Modal key="modal" hideNavBar transitionConfig={() => ({ screenInterpolator: CardStackStyleInterpolator.forFadeFromBottomAndroid })}>
        <Lightbox key="lightbox">
          <Stack key="root" titleStyle={{ alignSelf: 'center' }}>
            <Scene key="echo" back clone component={EchoView} getTitle={({ navigation }) => navigation.state.key} />
            <Scene key="launch" component={Launch} title="Launch" initial type={ActionConst.RESET} />
			
			...
          </Stack>

          <Scene key="demo_lightbox" component={DemoLightbox} />
        </Lightbox>
        <Scene key="error" component={ErrorModal} />
        <Stack key="login" headerLayoutPreset='center' path="login/:data" titleStyle={{ alignSelf: 'center' }}>
          <Scene key="loginModal" component={Login} title="Login" onExit={() => console.log('Login: onExit')} leftTitle="Cancel" onLeft={Actions.pop} />
          <Scene key="loginModal2" component={Login2} title="Login2" onEnter={() => console.log('Login2: onEnter') } backTitle="Back" panHandlers={null} duration={1} />
          <Scene key="loginModal3" hideNavBar component={Login3} title="Login3" onEnter={() => console.log('Login3: onEnter') } onExit={() => console.log('Login3: onExit')} panHandlers={null} duration={1} />
        </Stack>
      </Modal>

      <Scene component={MessageBar} />
    </Overlay>
  </Router>

I'm trying to reproduce that structure and I started from Modal only. This is my code ( obviously inside Router)

<Modal key='modal' hideNavBar transitionConfig={() => ({ screenInterpolator: CardStackStyleInterpolator.forHorizontal })}>
    <Stack key='root' navigationBarStyle={sharedStyles.header} titleStyle={{alignSelf: 'center'}}>
        <Scene key='landing' component={LandingScreen} initial
            type={SceneType.RESET as ActionConstShort}
            hideNavBar/>
        <Scene key='signIn' component={SignInScreen}
            title='Accedi'
            titleStyle={sharedStyles.headerTitle}
            type={SceneType.RESET as ActionConstShort}
            init/>
        <Scene key='home' component={HomeScreen} initial
            title={config.app.name}
            titleStyle={sharedStyles.headerTitle}
            init
            renderRightButton={() => <HomeHeaderRight onAccount={() => {Navigation.account()}} onAbout={() => {Navigation.about()}} />}/>
        <Scene key='account' component={AccountScreen}
            title='Gestione Account'
            titleStyle={sharedStyles.headerTitle}
            headerTintColor='white'/>
        <Scene key='about' component={AboutModal}
            title='Informazioni'
            titleStyle={sharedStyles.headerTitle}
            headerTintColor='white'/>
    </Stack>
    <Scene key='login' component={LoginScreen}
            title='Accedi'
            titleStyle={sharedStyles.headerTitle}
            headerTintColor='white'/>
</Modal>

Intially the app load "landing" then if I call Actions.signIn() the following error is thrown:

There is no route define for key signIn. Must be one of: 'root','login'

If I put the signIn scene outside from root at the same level of login scene it works fine but it is shown as Modal and I don't want that. I would like to keep it inside root as a normal scene.

How can I solve this?

@michelebombardi
Copy link
Contributor Author

michelebombardi commented Sep 20, 2018

I notice that the problem is cause by setting type={SceneType.RESET as ActionConstShort} on signIn scene.
Why is this happening? I really need to be able to set type reset in signIn scene.
Could anyone help me?

MOREOVER
I'm experiencing some problems with my "autologin" logic. I have the following code in my root component:

...

export default class App extends Component<Props, State> {
    constructor(props) {
        super(props)

        this.state = {
            isStoreLoading: false,
            store: store
        }
    }

    ...

    autoLogin() {
        if (authSelectors.isAuthInvalidOrExpired(store.getState())) {
            authService.clearAuth().then(() => {
                Navigation.signIn()
                store.dispatch(authActionCreators.update(null))
            })
        } else {
            authService.refresh().then((auth: IAuth) => {
                Navigation.home()
                store.dispatch(authActionCreators.update(auth))
            }).catch(() => {
                Navigation.signIn()
            })
        }
    }

    onBeforeLift = () => {
        console.log('PersistGate:onBeforeLift')

        this.autoLogin()
        this.setState({isStoreLoading: false})
    }

    render() {
        return (
            <Root>
                <StatusBar
                    backgroundColor={config.style.colors.primary}
                    barStyle='light-content'
                    translucent={true}
                />
                <Provider store={this.state.store}>
                    <PersistGate
                        loading={<SplashScreen />}
                        onBeforeLift={this.onBeforeLift}
                        persistor={persistor}>
                        <AppRouter />
                    </PersistGate>
                </Provider>
            </Root>
        )
    }
}

and this is the AppRouter:

...

const onBackPress = () => {
    let goBackOnly: boolean = ['home', 'splash', 'signIn']
        .every((scene: string) => Navigation.currentScene !== scene)
    Navigation.pop()
    return goBackOnly // return 'false' to close app and 'true' otherwise
}

// const RouterWithRedux = connect()(Router as any)
const createReducer = (params) => {
    const defaultReducer = new Reducer(params)
    return (state, action) => {
      return defaultReducer(state, action)
    }
}

const stateHandler = (prevState, newState, action) => {
    console.log('onStateChange: ACTION:', action)
}

const getSceneStyle = () => ({
    shadowOpacity: 1,
    shadowRadius: 3
})

// on Android, the URI prefix typically contains a host in addition to scheme
const prefix = Platform.OS === 'android' ? 'app://app/' : 'app://'

// transitionConfig={() => ({screenInterpolator: CardStackStyleInterpolator.forHorizontal})}
const scenes = Navigation.create(
    <Overlay key='overlay'>
        <Modal key='modal' hideNavBar transitionConfig={() => ({ screenInterpolator: CardStackStyleInterpolator.forHorizontal })}>
            <Lightbox key='lightbox'>
                <Stack key='root' navigationBarStyle={sharedStyles.header} titleStyle={{alignSelf: 'center'}}>
                    <Scene key='landing' component={LandingScreen} initial
                        type={SceneType.RESET as ActionConstShort}
                        hideNavBar/>
                    <Scene key='signIn' component={SignInScreen} init
                        // type={SceneType.RESET as ActionConstShort}
                        hideNavBar />
                    <Scene key='home' component={HomeScreen} init
                        // type={SceneType.RESET as ActionConstShort}
                        title={config.app.name}
                        titleStyle={sharedStyles.headerTitle}
                        renderLeftButton={null}
                        renderRightButton={() => <HomeHeaderRight onAccount={() => {Navigation.account()}} onAbout={() => {Navigation.about()}} />}/>
                    <Scene key='account' component={AccountScreen}
                        title='Gestione Account'
                        titleStyle={sharedStyles.headerTitle}
                        headerTintColor='white'/>
                </Stack>

                {/* <Scene key='login' component={LoginLightbox}
                    title='Accedi'
                    titleStyle={sharedStyles.headerTitle}/> */}
            </Lightbox>

            <Scene key='login' component={LoginScreen}/>
            <Scene key='about' component={AboutModal}/>
        </Modal>

        <Scene component={MessageBar} />
    </Overlay>
  )

// https://github.com/aksonov/react-native-router-flux/blob/master/docs/API.md
const AppRouter: StatelessComponent<{ dispatch }> = ({ dispatch }) => (
    <Router createReducer={createReducer}
        scenes={scenes}
        backAndroidHandler={onBackPress}
        onStateChange={stateHandler}
        getSceneStyle={getSceneStyle}
        uriPrefix={prefix}/>
)

...

Logically, if I open the app and the user is not logged in the signIn scene is loaded (this works).
If the user is logged in the autoLogin method should redirect to the home scene with Navigation.home() but this doesn't happen and the initial screen (landing) is loaded.

Any help? :(

@aksonov
Copy link
Owner

aksonov commented Sep 24, 2018

You have to use 'replace' not reset as type

@aksonov aksonov closed this as completed Sep 24, 2018
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants