Coder Social home page Coder Social logo

rfcs's Introduction

React Navigation 7

Build Status Code Coverage MIT License

Routing and navigation for your React Native apps.

Documentation can be found at reactnavigation.org.

This branch contains the code for the pre-release version of React Navigation 7. You can find the code for the latest stable version in the 6.x branch.

Package Versions

Name Latest Version
@react-navigation/bottom-tabs badge
@react-navigation/core badge
@react-navigation/devtools badge
@react-navigation/drawer badge
@react-navigation/elements badge
@react-navigation/material-top-tabs badge
@react-navigation/native-stack badge
@react-navigation/native badge
@react-navigation/routers badge
@react-navigation/stack badge
react-native-tab-view badge

Contributing

Please read through our contribution guide to get started!

Installing from a fork on GitHub

Since we use a monorepo, it's not possible to install a package from the repository URL. If you need to install a forked version from Git, you can use gitpkg.

First install gitpkg:

yarn global add gitpkg

Then follow these steps to publish and install a forked package:

  1. Fork this repo to your account and clone the forked repo to your local machine
  2. Open a Terminal and cd to the location of the cloned repo
  3. Run yarn to install any dependencies
  4. If you want to make any changes, make them and commit
  5. Run yarn lerna run prepack to perform the build steps
  6. Now cd to the package directory that you want to use (e.g. cd packages/stack for @react-navigation/stack)
  7. Run gitpkg publish to publish the package to your repo

After publishing, you should see something like this:

Package uploaded to [email protected]:<user>/<repo>.git with the name <name>

You can now install the dependency in your project:

yarn add <user>/<repo>.git#<name>

Remember to replace <user>, <repo> and <name> with right values.

rfcs's People

Contributors

brentvatne avatar deb0ch avatar ericvicenti avatar jonnyburger avatar peterpme avatar satya164 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rfcs's Issues

navigation.continue / next: push but without passing in a route name

πŸ‘‹

Given a stack navigator with the following routes:

{
  Login,
  ConnectGmail,
  Loading,
  Welcome
}

What

I'm proposing a navigation.continue or navigation.next method that will automatically determine the next route in line.

Why

Over the past 6 months we've built different onboarding flows and moving routes around for testing purposes. I have to open up individual files and update to the correct route name.

This isn't the worst thing in the world, but if I could do this at the navigator level it would improve my productivity.

Issues

  • sort order may be inconsistent. I would propose a key that would maintain sort order for you:
{
 Login: { key: 0, screen: LoginScreen }
}

How

I would be more than happy to implement this.

Thank you!

Add support to dispatch navigation thunks?

Hi,

It seems there are cases where you might want to dispatch multiple synchronous navigations. Supporting thunks like does Redux would be helpful to factorise such code.

For example, the code I put in this issue: react-navigation/react-navigation#1715 (comment)

export const navigateToRootTab = (navigation,tabName) => {
  const actions = [
    NavigationActions.reset({
      index: 0,
      actions: [
        NavigationActions.navigate({
          routeName: "Root",
        }),
      ]
    }),
    NavigationActions.navigate({
      routeName: tabName,
    })
  ];
  actions.forEach(navigation.dispatch);
};

The client code is navigateToRootTab(this.props.navigation,"MyTab");

Supporting thunks would allow: The client code is this.props.navigation.dispatch(navigateToRootTab("MyTab"); which looks more natural

This way, we don't have to provide the navigation/dispatch function to the factorised function that dispatch multiple actions

So, to better understand this, are you suggesting to reset asyncronously, wait for the transition to complete, and then perform the second navigation? Or do you expect both actions to happen right away?

@ericvicenti I'm suggesting dispatching multiple actions at once should be made easier by using thunks, not changing the current behavior when dispatching multiple actions which could be discussed in an other issue.

But to answer your question: I would prefer both actions to happen right away in an atomic way.

In my usecase I have a StackNav where initial element is a TabNab. I want to go back to StackNav root, on the 2nd tab. I have to dispatch 2 actions because I am currently unable to do that in a single action. If it did I would only have to dispatch a single action. See the original issue, the following does not work:

NavigationActions.reset({
  index: 0,
  actions: [
    NavigationActions.navigate({
      routeName: "Root", // StackNav root, whose screen is a TabNav
      action: NavigationActions.navigate({
        routeName: tabName, // This does not work, the TabNab is always reset to its initialRouteName
      })
    }),
  ]
});

Notice that I don't know if code above not working is expected or a bug, if the react-navigation library is supposed to always allow setting the nav in an appropriate state with a unique reset action, maybe dispatching multiple actions in a row does not make any sense et thus neither do thunks

Original issue: react-navigation/react-navigation#3402

Improve analytics tracking

Hello,

It's going to be a bit complicated to properly track routing change in a middleware, can we think about a nice way to play with screen tracking middleware ?

Currently we can access the current route name and whatever that is in the router state.

It could be nice if each screens can specify a analyticsScreenName meta that depend on something like params, or pre specified configuration like routes' metas of VueJS Router.

For example at the moment I got some route named as the following :

export default StackNavigator(
  {
    ExploreHome: {
      screen: require('../../Containers/ExploreScreen').default
    },
    PatientStoriesSeeAll: {
      screen: require('../../Components/Explore/PatientStoriesSeeAll').default
    },
    CategoriesSeeAll: {
      screen: require('../../Components/Explore/CategoriesSeeAll').default
    },
    SeeAllList: {
      screen: require('../../Containers/Explore/SeeAllList').default
    }
  }

If i need to dispatch "Authenticated/Explore/ExploreHome" for ExploreHome, I need to maintain a map collection alongside, if we had the capability to add some kind of meta, this could be nice.

On declaration or directly in screen via navigationOptions.

What do you think of that ? Should we make a separate module that can be imported as redux middleware ? I can develop in a RFC if you think that's a good point.

Best regards

Customizable per-screen transitions with StackNavigator

This is highly requested and it would be very convenient. Need to outline the use cases, how some hypothetical new API would look and how it would improve over the current way to do this with separate stacks. Also, are there things we cannot currently do without screen-specific transitions?

react-navigation/react-navigation#2585 includes a link to several issues about this.

Copied over from @satya164's post on react-navigation/react-navigation#3217:


Recently I needed to customize screen transition animation for a single screen and it wasn't really straightforward. This proposal aims to provide a simple and straightforward way to specify screen transition for a single screen.

There is an existing proposal react-navigation/react-navigation#175, but it looks very confusing and difficult to use.

Problem

Currently, to be able to customize screen transition for a specific screen, you need to configure it globally and it's not very intuitive. It looks something like this:

navigationOptions: {
  transitionSpec: {
    duration: 200,
  },
  transitionConfig: () => ({
    screenInterpolator: props => {
      // Transitioning to search screen (navigate)
      if (props.scene.route.routeName === 'Search') {
        return CardStackStyleInterpolator.forFade(props);
      }

      const last = props.scenes[props.scenes.length - 1];

      // Transitioning from search screen (goBack)
      if (last.route.routeName === 'Search') {
        return CardStackStyleInterpolator.forFade(props);
      }

      return CardStackStyleInterpolator.forHorizontal(props);
    },
  }),
}

It's kinda weird and also doesn't allow me to specify a different duration for the back transition.

Proposal

When customizing the transition for a specific screen, we would want to customize 2 different transitions:

  1. Animation when navigating to the screen
  2. Animation when going back from the screen

For both animations, we should be able to specify which style properties should be animated, e.g. opacity, transform or both, also control the duration of both animations individually. We should also be able to specify transitions for the header buttons.

Keeping these in mind, the following would work for the above scenario:

type TransitionConfigurator = (
  toTransitionProps: TransitionProps,
  fromTransitionProps: TransitionProps) =>  {
    transitionSpec?: NavigationTransitionSpec,
    screenInterpolator?: Object,
    headerLeftInterpolator?: Object,
    headerTitleInterpolator?: Object,
    headerRightInterpolator?: Object,
  } 

This differs from the current type definition https://github.com/react-navigation/react-navigation/blob/master/src/TypeDefinition.js#L522 and therefore is a breaking change. However, it's possible to support both styles and deprecate the old style gradually without breaking existing code.

This also changes the behavior so that:

  1. Empty object (screenInterpolator: {}) will disable transition animations for any property (I think this is the current behavior too)
  2. null/undefined (screenInterpolator: null) will use the default transition animations (this is a new behavior)

Basically, this proposal aims to keep the semantics as close to the previous semantics but changes the way the options are specified to be more flexible.

Usage example

navigationOptions: {
  transitionConfig: (toTransitionProps, fromTransitionProps) => {
    const isBack = fromTransitionProps.navigation.state.index >= toTransitionProps.navigation.state.index;
    const routeName = isBack ? fromTransitionProps.scene.route.routeName : toTransitionProps.scene.route.routeName;

    // This check is only for the case where the transitionConfig is specified globally per navigator basis
    // If the config is specified per screen basis, then `routeName` will always refer to the current screen
    if (routeName === 'Search') {
      return {
        transitionSpec: { duration: isBack ? 150 : 200 },
        screenInterpolator: CardStackStyleInterpolator.forFade(props),
      }
    }
  },
}

Options specified per screen will always take priority over options specified globally.

When navigation from ScreenA -> ScreenB, the transitionConfig option on both screens are called with the same set of arguments, i.e. toTransitionProps.scene refers to ScreenB and fromTransitionProps refers to ScreenA. However, the config returned from ScreenA.navigationOptions.transitionConfig is applied only to ScreenA and the config returned from ScreenB.navigationOptions.transitionConfig is applied only to ScreenB.

Redux support: what's it for?

@satya164 asked about this on Twitter and received a handful of responses, gathered below:

  • How do you cause navigation as a side effect to redux state change? How do you persist navigation state? These are my main use cases for redux integration (plus some edge cases around rewriting navy state history). In an app where networking is done from a saga/epic/thunk you may want to request data and update a loading state before navigating to the next screen. Doing these as two sequential method calls in component feels too coupled. @jevakallio
  • To trigger navigation actions from side effects this approach works great. @hectahertz
  • Easier navigation to nested routes from anywhere. (From actions mostly). @liamhubers
  • I remember using rnav with redux so i can prevent double dispatch of a page if the user clicks fast enough. Ex-nav used to handle this but not rnav. I guess there was other way to prevent this, without redux. @tychota
  • We are about to use Redux with React navigation, because we need some calculations in different screens and we don’t think that should be passed in params.
  • To dispatch actions from sagas. Redirect to an error screen when some fetch fails. @sibelius
  • I use the same StackNavigator in all tabs of a TabNavigator because many of the screens are shared (except the root). The screen don’t have to know where is it. The reducer know which stackrouter to give the action regarding index of the tabrouter. (because React Navigation doesn't make it possible to handle this currently) @Freddy03h
  • Also it’s very convenient to open a modal (in root stacknavigation) with a redux action from anywhere. Don’t open twice the same view on stack. Reinitiate all routers on logout. @Freddy03h
  • Also use redux-saga to handle fetch instead of doing it on componentDidMount. @Freddy03h
    1. To prevent navigating twice to the same route 2. To navigate in sagas 3. To create some custom navigation actions, specific for the app (RESET is a bit finicky) Example: https://github.com/Minishlink/DailyScrum/blob/04c7d19bd4960deea05f63c1d2b7b2e90f9a2d0c/src/modules/navigation/reducer.js @Minishlink
  • It's really nice way to navigate when fetching data is completed (instead of using callback style that passed when dispatching action). Good fit with redux-saga and easier to test. In my case is user login. I mostly put every side effect in redux-saga. Then, after the authentication is succeed, I can simply dispatch an action to navigate into the app. The other way that I tried is using callback, like onSuccess, when dispatching the action. For testing, I don't really test the navigation itself, but integration with redux helps me to fully test the saga that it dispatches the right navigation action with the right data when side-effect happened 😁 @AudyOdi
  • Trigger custom action called INITIAL_ROUTE. If user is not logged in set login, else set to home. @lucianomlima
  • Use case: opening deep links where navigation with both the top level and nested navigators is required.
  • Use case: a feature that needs to been enabled that is preventing some use of the app. Maybe show an alert. Then, going from wherever the user is where they cannot access that feature to wherever in the app they need to go to enable that feature.
  • One nice benefit I got from this integration is responding to notifications. I can easily dispatch an action using the notification’s payload and push a new screen to show context.

Ideally you shouldn't need Redux integration to do these things.

Passing route params as first level props

Current behavior:

If we call this.props.navigator.navigate("RouteName", {routeParams}) we will have to call this.props.navigator.params.routeParams for get it inside the screen with "RouteName" route.

Actually it`s not a big trouble. But some inconvenient cases exists:
For example if we already have a screen component, that expect some outer data for work. We will have to rewrite its behavior. So it can be a reusable component and just one of usage case with navigation.

On the other hand, we can create a component and don`t know will it be a route screen or not.

Proposal

Remake the interface of params.

Pass params as first level props:

Passed the same way params: navigation.navigate("routeName", {param0: "foo", param1: "bar"})
Should be available to get: this.props.param0

benefits:

  • it will make components more independent from a navigator.
  • it will reduce interface overhead with getting params with default values by delegating it to the well known react way

Save navigation prop with navigation methods

For backward compatibility and for those who makes exactly navigation scenes that should know about the navigator.

Think about changing the params

I still don`t know how to share data with header. But I think params passed by .navigate method should not be able to be changed from inside a screen. An alternative way should be found.
I guess we need to save route params as is and make an independent way to crosspassing data between a scene and a header (something like outer state of component).

If someone see any obstacles, pls tell it. We should to take into account all options.

Helper to determine if first screen in routes

Should be available on navigation, like isFocused: navigation.isFirstRoute() or something like that. This is useful if you want to add a custom back button and perhaps other things as well.

Add unsetParams to navigation prop

I searched a lot for this and didn't find anything regarding what I am about to write. Sorry if I missed any open issue about this.

Context

Let's consider the case where when I show some random component I set a param and I read that parameter in, let's say, the appbar.

Component setting the param:

import React from 'react';

export default class RandomComponent extends React.Component {

    ...

    componentDidMount() {
        this.props.navigation.setParams({ randomParam: 'my_value' });
    }

    ...

}

Component reading the param:

import React from 'react';

export default class RandomComponent extends React.Component {

    ...

    render() {
        const randomParam = this.props.navigation.getParam('randomParam', 'default');

        ...
    }
}

As you can see, when I don't set the param I use a default value using the getParam function on the navigation API.

Problem

In the first same component, when I unmount it I want to restore the default value. BUT I don't want to set the param again with the default value because I am using getParam form that. I want to unset that param.
Setting the param to undefined does not work.

Solution

Maybe implement a unsetParams function to unset parameters from the navigation state.

React Navigation developer tools

As per #14 the only good reason that I can see for integrating React Navigation state into Redux is to take advantage of the Redux developer tooling. We can create our own version that is more specialized for React Navigation and would provide a better experience without the downsides that go with storing your navigation state in Redux. Let's discuss this further in this thread.

Migrate to TypeScript! -- Or at least internalize the typescript definitions

Currently, TypeScript definitions for react-navigation are maintained by the community via DefinitelyTyped.

It'd be great if the TypeScript definitions were owned in house so they release in lockstep with API changes, and one way to do that would be to have the project itself be written in TypeScript.

I don't intend to give a whole sales pitch for TypeScript as that can be found elsewhere, but strong typing, with types for flow/typescript embedded in the repo would really smooth the learning curve, and help correct usage of the APIs.

There are people out there with tooling / willing to help with this project specifically, so it shouldn't be a giant burden on the core maintainers.

What would be people's thoughts about moving to TypeScript?

Should hardware back button press back action include some metadata?

When we press the hardware back button while the drawer is open, we expect it to close the drawer. However, if we fire goBack(null) from the drawer content view while it's open, I'm not sure that we'd expect it to close the drawer - maybe I'm wrong about this. Are there other cases where the drawer back button should be treated slightly differently than goBack(null)?

Action property that indicates to routes that they should not change index

COMPLETE_TRANSITION and SET_PARAMS are examples of actions that should not change the focused index for any router if they are applied to a child route.

https://github.com/react-navigation/react-navigation-core/blob/master/src/routers/StackRouter.js#L574-L583

The problem is that navigators can define their own actions that need to behave the same. For example, drawer actions (except maybe open drawer, unsure about that) need this behavior (or this happens: react-navigation/react-navigation#5183) because they can fire on a child route when the parent stack (or whichever navigator) is navigating to another screen.

Improve ergonomics of overlays / popovers / modals

Default params in navigator route config

It may be useful to specify default params in some cases, eg: to reuse screens for multiple routes.

let TabNavigator = createBottomTabNavigator({
  Brent: {
    screen: FriendScreen,
    initialParams: { firstName: 'Brent', lastName: 'Vatne' },
  },
  Eric: {
    screen: FriendScreen,
    initialParams: { firstName: 'Eric', lastName: 'Vicenti' },
  },
});

An alternative for this would be to wrap FriendScreen so we have BrentFriendScreen which passes in some props. This is maybe also fine and makes me hesitant to want to include something like initialParams unless we have some motivating use cases where this is infeasible. So let's gather use cases here.

Action to reload a screen maybe

I came across a use case where someone wanted to reload a screen in their app but couldn't figure out how to do it so they reloaded the app. Right now you can use replace for this in stack, eg: https://snack.expo.io/Skn48EdeQ. We could build in support for this more cleanly if it seems valuable for people

Declarative way to register event listener (<OnNavigationEvent/>)

Hey,

Here is a pattern I've used in my app that in some cases may be simpler to use than the withNavigationFocus HOC (particularly if you want to do something like loading/refreshing data on "willFocus" instead of "didFocus")

class MyScreen extends React.Component {
  render() {
    return (
      <React.Fragment>
        <OnNavigationEvent
          navigation={navigation}
          name="willFocus"
          do={(payload,count) => {
            // Ignore first call, as data already loads on mount no need to refresh it
            if ( count > 0 ) this.mySubComponent.imperativeApi().refresh()
          }}
        />
        <MySubComponent
          ref={c => this.mySubComponent = c}
        />
      </React.Fragment>
    );
  }
}

A very simple implementation:

export class OnNavigationEvent extends React.Component {
  componentDidMount() {
    let count = 0;
    this.subscription = this.props.navigation.addListener(this.props.name, payload => {
      this.props.do(payload,count);
      count++;
    });
  }
  componentWillUnmount() {
    this.subscription.remove();
  }
  render() {
    return this.props.children ?
      this.props.children : null;
  }
}

Just wondering if you like the idea and if it's worth working on a decent API (to subscribe eventually to multiple distinct events at once etc...) and a PR

Add navigation.carefullyGetParent() function

I think people tend to get confused about what state refers to on the navigation object. For example, when we emit focus and blur events for a tab, people get the state for their route but not the state for the navigator. Usually the state for the route doesn't change. I think there could be many cases where you might want to know the state of the parent navigator. For example, if I'm on tab C and someone just swiped over to tab B, then maybe I want to start fetching data required to render my tab. Another use case came to mind while reading over this: react-navigation/react-navigation#3554. I'd like to be able solve this issue with the following:

const modalStackConfig = {
  navigationOptions({ navigation }) {
    const { routeState, navigatorState } = navigation;

    if (routeState.key === navigatorState.routes[0].key) {
      return {
        headerLeft: (
          <Button title="X" onPress={() => navigation.goBack(null)} />
        ),
      };
    }
  },
};

export default StackNavigator(
  {
    Main: StackNavigator({
      MainScreen: Main,
    }),
    Modal: StackNavigator(
      {
        ModalMainScreen: ModalMain,
        ModalDetailScreen: ModalDetail,
      },
      modalStackConfig
    ),
  },
  {
    mode: 'modal',
    headerMode: 'none',
  }
);

If we have multiple modal stack navigators, we can just pass that config in and the back button appears wherever expected. It feels like the navigator state is information that we should have access to and I feel a bit handcuffed without it. In the above case I'd have to set the navigationOptions on the ModalMainScreen route, and probably would want to be explicit about the initialRouteName, which would be workable but I believe not quite as clean or intuitive.

We could make this change on master with this code in createNavigator.js:

const childNavigation = addNavigationHelpers({
  dispatch,
  get state() {
    console.warn('navigation.state is deprecated, please use navigation.routeState instead');
    return route;
  },
  routeState: route,
  navigatorState: state,
  addListener: getChildEventSubscriber(addListener, route.key),
});

I believe we'd need to change some other places for events. But before I embark on a formal RFC for this I wanted to get some thoughts.

  • Why didn't we do this in the first place?
  • Are there any implications around optimizing re-rendering we need to account for here?

API for overriding back button handling

  • Should let you inject a back handler that runs before the current screen
  • Need to only run this handler when the screen is active maybe?
  • Need to be able to disable the back button for any given screen

Support rendering tab bar and tab screens separately

If the tab bar was completely customizable and the screens behaved more like a stack navigator (in other words, if you navigate to a route in it with a certain key and it's not there, then it would add a screen for it and switch to it, roughly) this may solve the common request for dynamic tabs. Similar behavior could be given to drawer.

Configuring screen options based on props and state

Currently the screen options can be specified statically. If you need to configure any options based on props and state of the component, or want to update state and props based on some action such as tab press, you need to do it in a hacky way by changing params. it's way more complicated than it needs to be. It also breaks when used with HOCs which don't hoist static props, a common source of confusion. (#145, #2725, #2804, #2955)

Proposal

We can add an additional method setOptions on the navigation prop:

class Home extends Component {
  constructor(props) {
    super(props);

    this.props.navigation.setOptions({
      title: 'Home'
    });
  }

  render() {
    ...
  }
}

If you call setOptions again at some point, the object is shallow merged with previous configuration. It might seem a little ugly at first, but this imperative API allows us to build a declarative API on top of it:

function Profile({ route }) {
  return (
    <React.Fragment>
      <NavigationOptions
        title={`${route.user}'s Profile`}
      />
      <ScreenContent />
    </React.Fragment>
  );
}

NavigationOptions is a React component that can be used to configure the current screen from the render method. It's very useful when your screen's configuration depends on the props, state or both. (#2546)

The static way of specifying the config can still be supported for simplicity and backward compatibility.

Improve and Simplify the API for resetting the navigation state

This is a very clunky API for resetting the stack state:

const resetAction = StackActions.reset({
  index: 0,
  actions: [NavigationActions.navigate({ routeName: 'ReportHome'})],
});
this.props.navigation.dispatch(resetAction);

It would be great if we could do something like this instead:

this.props.navigation.navigate('ReportHome').then(() => {
  this.props.navigation.reset()
})

This way after you've gone back to the home screen, all the stacks are globally reset and when you click on a tab again, it won't take you to where you left off.

Add documentation for single file nested navigation structures

A navigation structure as described below works beautifully but isn't documented anywhere.
It allows you to navigate from nested screens to other nested screens easily, without having to pass navigation props from one screen to another.

I feel like such an example should be documented, since it's been discussed in various issues:
react-navigation/react-navigation#1979
react-navigation/react-navigation#983
react-navigation/react-navigation#913
react-navigation/react-navigation#335
react-navigation/react-navigation#1127

and more...

export const AppNavigator = StackNavigator(
    {
        Login: {
            screen: LoginScreen,
        },
        SetPassword: {
            screen: SetPasswordScreen,
        },

        mainFlow: {
            screen: TabNavigator(
                {
                    overviewFlow: {
                        screen: StackNavigator(
                            {
                                Overview: {
                                    screen: OverviewScreen,
                                },
                                DietitianInfo: {
                                    screen: DietitianInfoScreen,
                                },
                            },
                            {
                                headerMode: 'none',
                            }
                        )
                    },
                    Goals: {
                        screen: GoalsScreen,
                    },
                    diaryFlow: {
                        screen: StackNavigator(
                            {
                                DiaryOverview: {
                                    screen: DiaryOverviewScreen,
                                },
                                DiaryEntry: {
                                    screen: DiaryEntryScreen,
                                },
                            },
                            {
                                headerMode: 'none',
                            }
                        )
                    },

                    Notes: {
                        screen: NotesScreen,
                    },
                },
                {
                    tabBarPosition: 'bottom',
                    navigationOptions: ({ navigation }) => ({
                        // ...                         
                    }),
                    tabBarOptions: {
                       // ...
                    },
                }
            )
        }
    },
    {
        headerMode: 'none',
        // onTransitionStart: (e) => {
        //     console.log('Navigating somewhere');
        //     console.log(e);
        // },
    }
);

how to expose component ref for react-navigation HOC?

Improve ergonomics of back

  • goBack() - no key passed in, defaults to the key for the current route
  • goBack(key) - go back from this key to the route before it
  • goBack(null) - let any navigator handle this back action - if the deepest active one is already on index 0, a parent will handle
  • dismiss() - goBack(key) where key is the key of the navigator itself

this is all a bit confusing, in particular when you want to deal with going back across navigators

Solutions for our various layout woes

These values can update in response to orientation changes or on other events.

  • Status bar: translucent or opaque? in phone call? other?
  • "Safe areas": iPhone X is the main driver for this at the moment but probably other devices will add other weird layouts in the future.
  • Header height and tab bar height can change on layout.
  • We may use header height, status bar height, tab bar in various places, eg: if we have translucent header then to set insets on underlying ScrollView.
  • In landscape users may decide to show the status bar on iOS (even though this isn't the default behavior), we should adjust the header accordingly

The current SafeAreaView implementation handles some of this but it has limitations (async layout measurement and positioning for example).

Let's use this issue to collect problems that we need to solve related to this.

Remove navigation and navigationConfig from StackView, TabView

I propose each navigation view like StackView, TabView should declare needed input properties directly as Props: goBack (for StackView), navigate, tabBarComponent (for TabView) state, descriptors and remove generic dispatch (use direct methods like completeTransition instead of dispatch(NavigationActions.completeTransition()))

This way API for views will become easier to understand.

Question about card layout design

Hi,

The documentation is very scarce about some of the very fundamental aspects of inner workings of the library, e.g. screen components lifecycle: how screens are created, reused and destroyed during navigation.

But, looking at the source code, in particular Transitioner.js and ScenesReducer.js files, it looks like scenes/cards have 1:1 correspondence with routes, that is a new card is created each time a new route is added to the navigator by calling 'navigate' or 'push' methods.

I think this is not the optimal way of doing this. Instead, cards should have 1:1 correspondence with screen components used by the navigator, OR the combination of screen component and route key (in that case, multiple use of the same key should be allowed for the same screen, which would indicate the intent to re-use the card which corresponds to that key). Also when navigating between two routes which correspond to the same card, no animation should be applied during the transition. It should just call the (already existing) screen component with new parameters for the route you are navigating to.

One possible use case would be a hybrid native/web application, where one of the screens has a web view which would allow internal navigation inside the web view. You could track such navigation from inside the screen, add new routes with parameters (web url etc.) to the navigator, and when you press the "Back" button, the navigator would pass the parameters of the routes back to the screen, which would figure it out what it has to do. It could, for example, call .goBack() method of the web view.

With react-navigation, I think it is possible to implement the first part, that is to add routes without navigating to them (because it has been done already) using the technique described here, but I don't think it would be possible to do the rest...

StatusBar configuration in navigator config

I have a plan for handling part of this myself. Which may not work for everyone, but might be useful for coming up with ideas.

For me I'm following Material Design with translucent headers. The primary StatusBar properties I need to control are barStyle and backgroundColor so they are compatible with the background color of the header (or the page background if there is no header). I'm working on a library for handling Material Design in React Native and I plan to build a header component anyways – to extend React Navigation's Header so it follows Material Design closer and can handle some of the Material Design patterns that React Navigation doesn't implement. So my plan is to just make the Header component handle the StatusBar automatically, calculating the correct barStyle and backgroundColor based on the current background color for the app bar.

via @dantman in react-navigation/react-navigation#11

Related feature request: https://react-navigation.canny.io/feature-requests/p/control-statusbar-config-for-screens-in-navigationoptions

Preferred way to load heavy screens

Moved from react-navigation/react-navigation#4578


This is a discussion issue. If you feel it does not go here, please just close it. For me this is the most important point of navigation: Navigate without lag.

I am using in this case react-native-calendars, in their example of course they use react-native-navigation. So I am trying it with react-navigation. This is an example of a "heavy" screen but I am sure there are many others.

This example is as it is (as I'd do it in just native Android):

im_off

This example uses InteractionManager.runAfterInteractions and shows a loading spinner first:

im_on

This next example uses requestAnimationFrame to change the state and make it visible:

raf

All examples are with JS minified in one of the highest end Android devices (Pixel 2).

The first example is definitely laggy (I guess in lower devices even more) and the second and third feel slow to me if you come from checking native apps with similar components like a calendar. I know the limitations so I am asking myself if I can do something better or we are in this point right now?

I know there is this post about State of React Native 2018 and things like new core and async rendering can probably help.

One of my thinkings is that even that React Native docs state:

The views in React Navigation use native components and the Animated library to deliver 60fps animations that are run on the native thread.

So even that you use useNativeDriver as much as possible, that does not really solve the problem. What are your thoughts on this? :)

Btw, I actually opened a similar discussion in wix/react-native-navigation#3432 with the same example using their library (if you are interested).

dispatch: return a promise resolving on navigation animation completion

Hi,

I'd like to dispatch a navigation event, and only once the navigation has completed, perform some side-effect.

As the navigation may be animated, I can't just do this:

navigation.dispatch(action);
showSomething();

Otherwise the thing I want to show will be displayed before animation completes, leading to unexpected flicker.

I think due to the async/animated nature of the navigation, dispatching could return a promise, so that I can do:

navigation.dispatch(action).then(() => {
  showSomething();
});

Currently dispatch return a boolean. I guess this would be a breaking change and the boolean is maybe used as BackHandler return value?

Navigation helper names

  • navigate: it can be used in a variety of situations, but people learn it first as a way to push a route onto the stack, and the word seems best suited for that case. But you can do all sorts of things with navigate, such as go back (using a key)

  • goBack: we should distinguish between the goBack(null) and goBack() and goBack({key: 'someKey'}) cases with separate helpers with more intention revealing names.

    • goBack() - no key passed in, defaults to the key for the current route
    • goBack(key) - go back from this key to the route before it
    • goBack(null) - let any navigator handle this back action - if the deepest active one is already on index 0, a parent will handle
    • dismiss() - goBack(key) where key is the key of the navigator itself

    this is all a bit confusing, in particular when you want to deal with going back across navigators

Navigator config to pass params down

I was chatting with @geirman and I think we may want to add passParams to the navigator config:

createStackNavigator({
  Main,
  MyTabs: createTabNavigator({
    A,
    B,
  }, { passParams: [ 'foo' ] })
})

Say you go from Main .navigate('MyTabs', {foo: 'bar'}).. Thanks to the proposed passParams, screens A and B would have access to the "foo" param.

I'll try to get to this in the coming weeks. Let me know if anybody wants to take a stab at implementing this.. I'd be happy to support you.

cc @brentvatne

Standard flag for routers such as TabRouter whose children can handle actions without forcing the parent to switch focus

Currently the TabRouter will switch to a child router that handles a navigation action if it is not SET_PARAMS or (soon) COMPLETE_TRANSITION. We should have some flag on navigation actions that either a) tells the router to switch focus to the child that handles the action or b) tells the router to not switch focus if the child handles the action. This lets people with custom routers and actions deal with the behavior properly without forking TabNavigator to add their action to the whitelist.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.