Search code examples
reactjsflux

How to implement navigation controller/tab bar controller in React/Flux?


I'm creating a SPA mobile app using React. I'm wondering how I would create a navigation controller or a tab bar controller using the Flux way. Basically I'm wondering how I handle ownership of children and who/what handles the actual transitions.

Right now I have a navigationController component that has a push method to add pages to the stack and transition them in our out. All of this is stored in the state, and the parent component knows nothing about this.

For my tab bar controller, the parent component passes in some tabBar items with the children of the tabBar item being the content to show when the tab is active. The tab bar controller handles when a tab is active and what content to show based on the active tab. The parent doesn't know anything about which tab is active. the active tab is stored in the tab bar controller's state.

Stuff like this just doesn't seem to be easily implemented in Flux. How would I, from the parent, tell a navigation controller to add an element, and then handle the transition from within controller. Also, how would added pages to the controller be able to push new pages if they have to go all the way up to the root?

I guess my problem might be that I don't fully understand Flux.

Any help would be greatly appreciated.


Solution

  • It sounds like you're doing too much in the components. There are many ways to implement the Flux architecture, but often the easiest one to think through assumes that you almost never use state, only props. All the logic about which tabs are available and what's active would go into a TabStore outside the React components. The basic flux flow might go like this:

    • TabStore keeps an internal list of tabs and content, and tracks the activeTab. It exposes a method like .getTabs() to allow the view to access the current state. It also exposes EventEmitter methods to allow it to publish changes.

    • The root component in your app sets a listener to changes in the tab store. The simplest version of this is something like:

      _onChangeTabStore: function() {
          this.setState({
              tabs: TabStore.getTabs(),
              activeTab: TabStore.getActiveTab()
          });
      },
      
    • The root component then passes tabs and activeTab to your TabBar component as props. It might also pass a handler like:

      onTabClick: function(clickedTab) {
          TabActions.setActiveTab(clickedTab);
      },
      
    • TabActions.setActiveTab is going to dispatch an action via the AppDispatcher. See the Flux docs for more details.

    • The TabStore processes the setActiveTab action, and updates its internal state. If the active tab has changed, it emits a change event.

    • The root component receives the change event, updates state, and passes new props to the TabBar.

    Nowhere here does any React component keep track of its own state - that's the job of the store. This keeps a really clean separation between business logic and the view. It also avoids any "how does the parent know what tab is selected" question, because the parent is receiving the tab state as well.