react-router-native icon indicating copy to clipboard operation
react-router-native copied to clipboard

Fix TabsRoute behaviour

Open jonathanglasmeyer opened this issue 9 years ago • 6 comments

TabsRoute should implement two behaviours:

  • it should save the state for each child route and restore it when switching tabs
  • it should reset a child's state if that child is being navigated to twice

Given the following route config:

<Router>
  <TabsRoute path="/" ...>
    <StackRoute path="/foo" ...>
      <Route path="a" ... />
      <Route path="b" ... />
    </StackRoute>
    <Route path="/bar" .../>
  </TabsRoute>
</Router>

Visiting routes should lead to the following results respectively:

  1. /foo --> show /foo
  2. /foo/a --> show /foo/a
  3. /foo/b --> show /foo/b
  4. /bar --> show /bar
  5. /foo --> show /foo/b (a tab route saves and restores its children's state)
  6. /foo --> should reset stack of the child stack route and show /foo

jonathanglasmeyer avatar Jun 12 '16 09:06 jonathanglasmeyer

it should save the state for each child route and restore it when switching tabs

This is supported when root route, /, is leaf of a TabsRoute. I'll make the necessary changes to cover most other cases as well. It's the <StackRoute> that's causing <TabsRoute> to misbehave. It gets a bit tricky when we have nested routes. Making the default reducer used by <StackRoute> route order aware should fix this.

it should reset a child's state if that child is being navigated to twice

This is in the README under Advanced Usage. It is possible with a custom route reducer. But we should probably make this the default behavior.

🍺

jmurzy avatar Jun 12 '16 23:06 jmurzy

Can the state also include its scroll position? Native apps seem to store everything including scroll position, or maybe they keep the rendered view alive somewhere and simply switch to it. I wonder how the life cycle works for those tabs in the native apps.

joonhocho avatar Jun 13 '16 17:06 joonhocho

The F8 app does this, uses NavExp and is open source. So it should be possible. Haven't investigated this in detail but it's a must-have for sure.

jonathanglasmeyer avatar Jun 13 '16 19:06 jonathanglasmeyer

@jonathanewerner @joonhocho That is supported. Previously, there was a bug in NavigationExperimental that dropped component state when swtiching tabs. But that's now fixed, and <Route> and its siblings should now retain component state on all navigation state updates. This includes <ScrollView> state e.g. scroll position, animation state.

UINavigationContoller extends UIViewController and uses the good old lifecycles inherited from it. It does retain all UIViewController instances that are then pushed to it. Very similar to how we do it. Both <TabsRoute> and <StackRoute> retain references to your previously focused views. Here's how they would look when you inspect the view hierarchy.

<StackRoute> with 3 active views
      +------------+
    +-+            |
  +-+ |            |
  | | |            |
  | | |  Focused   |
  | | |   View     |
  | | |            |
  +-+ |            |
    +-+            |
      +------------+

Here a <Pop> would drop the focused view revealing the previous view in the stack with a transition animation. The views in a stack are never unmounted during a transition so you keep your component state. Transition animations can also be customized using transitionRegistry.

<TabsRoute> with 3 active views
 * +-------------+-------------+-------------+
 * |             |             |             |
 * |             |             |             |
 * |             |             |             |
 * |    Next     |   Focused   |  Previous   |
 * |    View     |    View     |    View     |
 * |             |             |             |
 * |             |             |             |
 * |             |             |             |
 * +-------------+-------------+-------------+

By default, transition animations are turned off for <TabsRoute> mirroring native behavior. But there's nothing preventing you from making them animate when switching tabs. Aviato example does this for its inner "swticher" tabs.

<TabsRoute> is also smart enough to lazily render its tabs. So when your app launches, you will have only one of the tabs (focused view) rendered, but once you tap other tabs, all are retained until you kill the app.

Are you perhaps running into a bug we can try to reproduce and fix?

🍺

jmurzy avatar Jun 13 '16 20:06 jmurzy

Thanks @jmurzy for such detailed answer. I once noticed that tabs on react native apps did not retain previous view states, but did not know that it was fixed. It's pretty cool to know how they can lazily render other tabs.

joonhocho avatar Jun 14 '16 01:06 joonhocho

Any movement on this? This is quite limiting and is stopping me from truly being able to use this on my app. Switching between tabs does not retain that tabs state and instead pushed the new route on top. I also don't know enough to write my own reducer, that seems that's pretty involved.

aforty avatar Oct 17 '16 15:10 aforty