0

I'm trying to build a dynamic wizard with react-native-navigation v2.
I say dynamic because the number of steps may vary depending on which options the user selects.

I was thinking to use nested stacks, so the layout of my app would look something like this:

{
  root: {
    sideMenu: {
      left: {/*...*/},
      center: {
        stack: {
          children: [component1, /*...,*/ componentX]
        }
      }
    }
  }
}

ComponentX is where I start my wizard, so I push a new stack like this:

{
// ...
  stack: {
    children: [
      component1,
      //...,
      componentX,
      {
        stack: {
          children: [step1, step2, /*...,*/ stepN]
        }
      }
    ]
  }
}

After the user make the last choice on stepN, I would like to replace the nested stack with a summary screen to have something like:

{
//...
  stack: {
    children: [
      component1,
      //...,
      componentX,
      summaryScreen
    ]
  }
}

I could use Navigation.setRoot to reset the whole thing but that means I would probably have to store the navigation in Redux. I've also tried using Navigation.setStackRoot but I'm under the impression that it's setting the parent stack root and not my nested stack...

Gpack
  • 1,878
  • 3
  • 18
  • 45

1 Answers1

0

I've finally managed to solve it.
Here's how:

  1. At the start of my app, when I give an id to my main stack
const sideMenu = {
    left: { /*...*/ },
    center: {
      stack: {
        id: 'main', // this line is important
        children: [/*...*/]
      }
    },
  };
  Navigation.setRoot({
    root: { sideMenu },
  });
  1. When I want to start my wizard, I push a new stack
Navigation.push(componentId, {
  stack: {
    id: 'wizard',
    children: [
      {
        component: { /*...*/ },
      },
    ],
  }
})
  1. I push the screens on the new stack wizard as the user progresses

  2. When I want to display the final summary screen, I call setStackRoot on the nested stack

Navigation.setStackRoot('wizard', [
  {
    component: { /*...*/ },
  },
]);
  1. On that summary screen, I have a button labelled 'Finish' which removes the nested stack
Navigation.pop('main');

EDIT: with this approach alone, if you click on the back arrow when you are on a nested screen, it will dismiss the entire nested stack instead of this screen only.
I had to use a custom back button as follows:

I solved it by using a custom back button: 1. When pushing a new screen where I want to override the button, use the options

import Icon from 'react-native-vector-icons/MaterialIcons';
/* ... */
const backIcon = await Icon.getImageSource('arrow-back', 24, '#000');
const component = {
  id: screenID,
  name: screenID,
  passProps,
  options: {
    topBar: {
      leftButtons: [
        {
          id: 'backButton',
          icon: backIcon,
        },
      ],
    },
  }
};
return Navigation.push(componentId, { component });
  1. Create a HOC to implement you custom back action
import React, { Component } from 'react';
import { Navigation } from 'react-native-navigation';

const getDisplayName = WrappedComponent => WrappedComponent.displayName || WrappedComponent.name || 'Component';

export default function withCustomBackButton(WrappedComponent) {
  class WithCustomBackButton extends Component {
    componentDidMount() {
      this.navigationEventListener = Navigation.events().bindComponent(this);
    }

    componentWillUnmount() {
      if (this.navigationEventListener) this.navigationEventListener.remove();
    }

    navigationButtonPressed() {
      // Your custom action
      const { componentId } = this.props;
      Navigation.pop(componentId);
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  }

  WithCustomBackButton.displayName = `WithCustomBackButton(${getDisplayName(WrappedComponent)})`;

  return WithCustomBackButton;
}
  1. When registering the screen with the custom back button, wrap it in your HOC
import withCustomBackButton from '../components/hoc/WithCustomBackButton';
/* ... */
Navigation.registerComponent('selectLocation', () => withCustomBackButton(SelectLocation));
Gpack
  • 1,878
  • 3
  • 18
  • 45
  • Hi @Gpack, I need a help regrading multiple stack. In my app there the 1000+ components and sub components. How to set divide the stack in my project. I am very confuse how to approach the routing. Please help me. – Harleen Kaur Arora Jun 04 '19 at 13:34
  • Hi @HarleenKaurArora, I'm far from being an expert.Here's a [link](https://medium.com/@alexmngn/why-react-developers-should-modularize-their-applications-d26d381854c1) which you may find useful to organize your app – Gpack Jun 06 '19 at 00:50