diff --git a/.circleci/config.yml b/.circleci/config.yml index 3c3fb40a9a..d8104746f1 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -19,6 +19,5 @@ jobs: key: v3-react-navigation-{{ .Branch }}-{{ checksum "package.json" }} paths: - ~/.cache/yarn - - ~/react-navigation/website/node_modules - ~/react-navigation/examples/NavigationPlayground/node_modules - ~/react-navigation/examples/ReduxExample/node_modules diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md deleted file mode 100644 index 26865e9a81..0000000000 --- a/docs/CONTRIBUTING.md +++ /dev/null @@ -1,181 +0,0 @@ -# React Navigation Contributor Guide - -Want to help improve React Navigation? Your help would be greatly appreciated! - -Here are some of some of the ways to contribute to the project: - -- [Reporting Bugs](#Reporting-Bugs) -- [Improving the Documentation](#Improving-the-Documentation) -- [Responding to Issues](#Responding-to-Issues) -- [Bug Fixes](#Bug-Fixes) -- [Suggesting a Feature](#Suggesting-a-Feature) -- [Big Pull Requests](#Big-Pull-Requests) - -And here are a few helpful resources to aid in getting started: - -- [Issue Template](#Issue-Template) -- [Pull Request Template](#Pull-Request-Template) -- [Forking the Repository](#Forking-the-Repository) -- [Code Review Guidelines](#Code-Review-Guidelines) -- [Run the Example App](#Run-the-Example-App) -- [Run the Website](#Run-the-Website) -- [Run Tests and Type-Checking](#Run-Tests-and-Type-Checking) - -> Note that we used Yarn in the examples below but you're welcome to use NPM instead. - -## Contributing - -### Reporting Bugs - -You can't write code without writing the occasional bug. Especially as React Navigation is in beta and moving quickly, bugs happen. When you think you've found one here's what to do: - -1. Search the existing issues for one like what you're seeing. If you see one, add a 👍 reaction (please no +1 comments). Read through the comments and see if you can provide any more valuable information to the thread -2. If there are no other issues like yours then create a new one. Be sure to follow the [issue template](https://github.com/react-community/react-navigation/blob/master/.github/ISSUE_TEMPLATE.md). - -Creating a high quality reproduction is critical. Without it we likely can't fix the bug and, in an ideal situation, you'll find out that it's not actually a bug of the library but simply done incorrectly in your project. Instant bug fix! - -### Improving the Documentation - -Any successful projects needs quality documentation and React Navigation is no different. - -The docs are currently organized as follows - -- __Getting Started__: Introduction and basics of React Navigation. Help people get up and running with the package quickly. Introduce and demonstrate core functionality. -- __Navigators__: API documentation for the included navigators and supporting APIs -- __Advanced Guides__: (Advanced) Beyond the basics, what can you do with React Navigation? Discuss and demonstrate that here. -- __Routers__: (Advanced) API documentation for the included routers and how to use/customize them -- __Views__: (Advanced) API documentation for the included views and how to use/customize them - -The documentation isn't fixed to what categories and documents currently exist. If your documentation contributation is appropriate for any existing document, add it there. If it makes sense to create a new document for your contribution please do so and add it to the docs index. - -The docs are indexed in [App.js](https://github.com/react-community/react-navigation/blob/master/website/src/App.js), where all the pages are declared alongside the titles. To test the docs, follow the instructions for running the website. - -The markdown from the `docs` folder gets generated and dumped into a json file as a part of the build step. To see updated docs appear in the website, re-run the build step by running `yarn run build-docs` from the `react-navigation` root folder. - -### Responding to Issues - -Another great way to contribute to React Navigation is by responding to issues. Maybe it's answering someone's question, pointing out a small typo in their code, or helping them put together a reproduction. If you're interested in a more active role in React Navigation start with responding to issues - not only is it helpful but it demonstrates your commitment and knowledge of the code! - -### Bug Fixes - -Find a bug, fix it up, all day long you'll have good luck! Like it was mentioned earlier, bugs happen. If you find a bug do the following: - -1. Check if a pull request already exists addressing that bug. If it does give it a review and leave your comments -2. If there isn't already a pull request then figure out the fix! If it's relatively small go ahead and fix it and submit a pull request. If it's a decent number of changes file an issue first so we can discuss it (see the [Big Pull Requests](#big-pull-requests) section) -3. If there is an issue related to that bug leave a comment on it, linking to your pull request, so others know it's been addressed. - -Check out the [help wanted](https://github.com/react-community/react-navigation/issues?q=is%3Aissue+is%3Aopen+label%3A%22help+wanted%22) and [good first issue](https://github.com/react-community/react-navigation/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) tags to see where you can start helping out! - -### Suggesting a Feature - -Is there something you want to see from React Navigation? Go ahead and open and issue, describe what it is you want to accomplish and why you want to accomplish that. A few things to consider/add - -1. Is there already a way to do this and you want to simplify it? -2. Do you have any thoughts on how to implement this feature? Have you done something similar already? - -Hold off on submitting feature pull requests until the feature has been discussed. Once the feature has been established and agreed upon, create the pull request (following the [big pull requests](#big-pull-requests) guide). - -### Big Pull Requests - -For any changes that will add/remove/modify multiple files in the project (new features or bug fixes) hold off on writing code right away. There's a few reasons for that - -1. Big pull requests take a lot of time to review and it's sometimes hard to pick up the context -2. Often you may not have to make as big of a change as you expect - -With that in mind, here's the suggestion - -1. Open an issue and clearly define what it is you want to accomplish and how you intend to accomplish it -2. Discuss that solution with the community and maintainers. Provide context, establish edge cases, and figure out the design -3. Decide on a plan of action -4. Write the code and submit the PR -5. Review the PR. This can take some time but, if you followed the steps above, hopefully it won't take too much time. - -The reason we want to do this is to save everyone time. Maybe that feature already exists but isn't documented? Or maybe it doesn't fit with the library. Regardless, by discussing a major change up front you're saving your time and others time as well. - -## Information - -### Issue Template - -Before submitting and issue please take a look at the [issue template](https://github.com/react-community/react-navigation/blob/master/.github/ISSUE_TEMPLATE.md) and follow it. This is in place to help everyone better understand the issue you're having and reduce the back and forth to get the necessary information. - -Yes, it takes time and effort to complete the issue template. But that's the only way to ask high quality questions that actually get responses. - -Would you rather take 1 minute to create an incomplete issue report and wait months to get any sort of response? Or would you rather take 20 minutes to fill out a high quality issue report, with all the necessary elements, and get a response in days? It's also a respectful thing to do for anyone willing to take the time to review your issue. - -### Pull Request Template - -Much like the issue template, the [pull request template](https://github.com/react-community/react-navigation/blob/master/.github/PULL_REQUEST_TEMPLATE.md) lays out instructions to ensure your pull request gets reviewd in a timely manner and reduces the back and forth. Make sure to look it over before you start writing any code. - -### Forking the Repository - -- Fork [`react-navigation`](https://github.com/react-community/react-navigation) on GitHub -- Run these commands in the terminal to download locally and install it: - -```bash -git clone https://github.com//react-navigation.git -cd react-navigation -git remote add upstream https://github.com/react-community/react-navigation.git -yarn install -``` - -### Code Review Guidelines - -Look around. Match the style of the reset of the codebase. This project uses ESLint to ensure consistency throughout the project. You can check your project by running - -```bash -yarn run eslint -``` - -If any errors occur you'll either have to manually fix them or you can attempt to automatically fix them by running `yarn run format`. - -### Run the Example App - -```bash -yarn install -cd examples/NavigationPlayground -yarn install -yarn start -``` - -You will be show a QR code to scan in the Expo app. You can get Expo [here](https://docs.expo.io/versions/latest/index.html) if you don't have it yet. - -All examples: - -- [NavigationPlayground](https://github.com/react-community/react-navigation/tree/master/examples/NavigationPlayground) -- [ReduxExample](https://github.com/react-community/react-navigation/tree/master/examples/ReduxExample) -- [SafeAreaExample](https://github.com/react-community/react-navigation/tree/master/examples/SafeAreaExample) - -Commands are the same as above for any of the example apps. If you run into any issues, please try the following to start fresh: - -```bash -watchman watch-del-all -yarn start -- --reset-cache -``` - -### Run the Website - -For development mode and live-reloading: - -```bash -cd website -yarn install -yarn start -``` - -To run the website in production mode with server rendering: - -```bash -yarn run prod -``` - -If you've made any changes to the `docs` directory you'll need to run `yarn run build-docs` from the root of the project before they're picked up by the website. - -### Run Tests and Type-Checking - -React Navigation has tests implemented in [Jest](https://facebook.github.io/jest/). To run either of these, from the React Navigation directory, run either of the following commands (after installing the `node_modules`) to run tests or type-checking. - -```bash -yarn run jest -``` - -These commands will be run by our CI and are required to pass before any contributtions are merged. diff --git a/docs/api/navigators/DrawerNavigator.md b/docs/api/navigators/DrawerNavigator.md deleted file mode 100644 index 700a63f6d2..0000000000 --- a/docs/api/navigators/DrawerNavigator.md +++ /dev/null @@ -1,191 +0,0 @@ -# DrawerNavigator - -Used to easily set up a screen with a drawer navigation. For a live example please see [our expo demo](https://exp.host/@react-navigation/NavigationPlayground). - -```js -class MyHomeScreen extends React.Component { - static navigationOptions = { - drawerLabel: 'Home', - drawerIcon: ({ tintColor }) => ( - - ), - }; - - render() { - return ( - -); -``` - - -### The static `router` - -A router object may be statically defined on your component. If defined, it must follow this interface: - -```javascript -type BackAction = {type: 'Navigation/BACK'}; -type URIAction = {type: 'Navigation/URI', uri: string}; - -interface Router { - getStateForAction(action: (A | BackAction | URIAction), lastState: ?S): ?S; - getActionForURI(uri: string): ?A; -} -``` - -The state and action types of the static router must match the state and action types associated with the navigation prop passed into the component. - -#### router.getStateForAction(action, lastState) - -This function is defined on the static router and is used to define the expected navigation state. - -```javascript -class ScreenWithEditMode extends React.Component { - static router = { - getStateForAction: (action, prevState) => { - return { isEditing: true }; - }, - }; - render() { - // this.props.navigation.state.isEditing === true - ... - } -} -``` - -`getStateForAction` must **always** return a navigation state that can be rendered by the component when passed in as the `navigation.state` prop. - -If null is returned, we are signaling that the previous navigation state has not changed, but the action is handled. This is usually used in cases where the action is being swallowed. - - -#### router.getActionForURI(uri) - -Return an action if a URI can be handled, otherwise return `null` - - - -### Special Actions - -There are two special actions that can be fired into `navigation.dispatch` and can be handled by your `router.getStateForAction`. - -#### Back Action - -This action means the same thing as an Android back button press. - -``` -type BackAction = { type: 'Navigation/BACK' }; -``` - -#### URI Open Action - -Used to request the enclosing app or OS to open a link at a particular URI. If it is a web URI like `http` or `https`, the app may open a WebView to present the page. Or the app may open the URI in a web browser. In some cases, an app may choose to block a URI action or handle it differently. - -``` -type URIAction = { type: 'Navigation/URI', uri: string }; -``` - - -### Special Navigation State - -The state defined by `router.getStateForAction` can contain special navigation properties that may be relevant to your app. The title and current URI of a component may change over time, and the parent often needs to observe the behavior. - -#### `state.title` - -If the navigation state contains 'title', it will be used as the title for the given component. This is relevant for top-level components on the web to update the browser title, and is relevant in mobile apps where a title is shown in the header. - -#### `state.uri` - -A URI can also be put in `state.uri`, which will signal to the parent how it may be possible to deep link into a similar navigation state. In web apps, this will be used to keep the URI bar in sync with the current navigation state of the app. - - -## Use Cases - -### "Block the Android back button on one screen of my app" - -To block the Android back button: - -``` -class Foo extends React.Component { - static router = { - getStateForAction(action, prevState = {}) { - if (action.type === 'Navigation/BACK') return null; - else return prevState; - }, - }; - render() { - ... -``` - -Because we return null, we signal to our container that the action has been handled but the state does not change. The parent should not handle the back behavior at this point, and nothing should be re-rendered. - -### "Link deeply into one screen of my app" - -``` -class Foo extends React.Component { - static router = { - getStateForAction(action, prevState = {deep: false}) { - if (action.type === 'GoDeep') return { deep: true }; - else return prevState; - }, - getActionForURI(uri) { - if (uri === 'myapp://foo') - return {type: 'Go'}; - else if (uri === 'myapp://foo_deep') - return {type: 'GoDeep'}; - return null; - }, - }; - render() { - // this.props.navigation.state.deep may be true or false - ... -``` - -Based on the state URI we may decide to return an action. If an action is returned, `getStateForAction` is expected to output the correct state for a deep link. - -## Reference Implementations - -A library to that helps easily produce navigation-aware components: https://github.com/react-community/react-navigation . (Also uses a HOC to provide navigation containers when needed.) - -A simple navigation container: https://gist.github.com/ericvicenti/77d190e2ec408012255937400e34bdb1 - -A web implementation of a navigation container: https://gist.github.com/ericvicenti/55bef95fcd8558029a3bae8483baea6c diff --git a/docs/guides/Custom-Navigators.md b/docs/guides/Custom-Navigators.md deleted file mode 100644 index 7eb2201b64..0000000000 --- a/docs/guides/Custom-Navigators.md +++ /dev/null @@ -1,94 +0,0 @@ -# Custom Navigators - -A navigator is any React component that has a [router](/docs/routers/) on it. Here is a basic one, which uses the [router's API](/docs/routers/api) to get the active component to render: - -```js -class MyNavigator extends React.Component { - static router = MyRouter; - render() { - const { state, dispatch } = this.props.navigation; - const { routes, index } = state; - - // Figure out what to render based on the navigation state and the router: - const Component = MyRouter.getComponentForState(state); - - // The state of the active child screen can be found at routes[index] - let childNavigation = { dispatch, state: routes[index] }; - // If we want, we can also tinker with the dispatch function here, to limit - // or augment our children's actions - - // Assuming our children want the convenience of calling .navigate() and so on, - // we should call addNavigationHelpers to augment our navigation prop: - childNavigation = addNavigationHelpers(childNavigation); - - return ; - } -} -``` - -## Navigation Prop - -The navigation prop passed down to a navigator only includes `state` and `dispatch`. This is the current state of the navigator, and an event channel to send action requests. - -All navigators are controlled components: they always display what is coming in through `props.navigation.state`, and their only way to change the state is to send actions into `props.navigation.dispatch`. - -Navigators can specify custom behavior to parent navigators by [customizing their router](/docs/routers/). For example, a navigator is able to specify when actions should be blocked by returning null from `router.getStateForAction`. Or a navigator can specify custom URI handling by overriding `router.getActionForPathAndParams` to output a relevant navigation action, and handling that action in `router.getStateForAction`. - -### Navigation State - -The navigation state that is passed into a navigator's `props.navigation.state` has the following structure: - -``` -{ - index: 1, // identifies which route in the routes array is active - routes: [ - { - // Each route needs a name, which routers will use to associate each route - // with a react component - routeName: 'MyRouteName', - - // A unique id for this route, used to keep order in the routes array: - key: 'myroute-123', - - // Routes can have any additional data. The included routers have `params` - ...customRouteData, - }, - ...moreRoutes, - ] -} -``` - -### Navigation Dispatchers - -A navigator can dispatch navigation actions, such as 'Go to a URI', 'Go back'. - -The dispatcher will return `true` if the action was successfully handled, otherwise `false`. - -## API for building custom navigators - -To help developers implement custom navigators, the following utilities are provided with React Navigation: - -### `createNavigator` - -This utility combines a [router](/docs/routers/) and a [navigation view](/docs/views/) together in a standard way: - -```js -const MyApp = createNavigator(MyRouter)(MyView); -``` - -All this does behind the scenes is: - -```js -const MyApp = ({ navigation }) => ( - -); -MyApp.router = MyRouter; -``` - -### `addNavigationHelpers` - -Takes in a bare navigator navigation prop with `state` and `dispatch`, and augments it with all the various functions in a screen navigation prop, such as `navigation.navigate()` and `navigation.goBack()`. These functions are simply helpers to create the actions and send them into `dispatch`. - -### `createNavigationContainer` - -If you want your navigator to be usable as a top-level component, (without a navigation prop being passed in), you can use `createNavigationContainer`. This utility will make your navigator act like a top-level navigator when the navigation prop is missing. It will manage the app state, and integrate with app-level nav features, like handling incoming and outgoing links, and Android back button behavior. diff --git a/docs/guides/Customizing-Navigation.md b/docs/guides/Customizing-Navigation.md deleted file mode 100644 index a9dccc672a..0000000000 --- a/docs/guides/Customizing-Navigation.md +++ /dev/null @@ -1,53 +0,0 @@ -## Customizing Navigation Views - -Modify the presentation of navigation, including styles, animations and gestures. - -## Customizing Routers - -Building a custom router allows you to change the navigation logic of your component, manage navigation state, and define behavior for URIs. - - -A router can be defined like this: - -```js -class MyNavigationAwareComponent extends React.Component { - - static router = { - - // Defines the navigation state for a component: - getStateForAction: (action: {type: string}, lastState?: any) => { - const state = lastState = { myMode: 'default' }; - if (action.type === 'MyAction') { - return { myMode: 'action' }; - } else if (action.type === NavigationActions.BACK) { - return { myMode: 'blockBackButton' }; - } else { - return state; - } - }, - - // Defines if a component can handle a particular URI. - // If it does, return an action to be passed to `getStateForAction` - - getActionForURI: (uri: string) => { - if (uri === 'myapp://myAction') { - return { type: 'MyAction' }; - } - return null; - }, - - }; - - render() { - // render something based on this.props.navigation.state - ... - } - - onButtonPress = () => { - this.props.navigation.dispatch({ type: 'MyAction' }); - }; - - ... - -} -``` diff --git a/docs/guides/Deep-Linking.md b/docs/guides/Deep-Linking.md deleted file mode 100644 index 286ca457d2..0000000000 --- a/docs/guides/Deep-Linking.md +++ /dev/null @@ -1,111 +0,0 @@ -# Deep Linking - -In this guide we will set up our app to handle external URIs. Let's start with the SimpleApp that [we created in the getting started guide](/docs/intro). - -In this example, we want a URI like `mychat://chat/Taylor` to open our app and link straight into Taylor's chat page. - -## Configuration - -Previously, we had defined a navigator like this: - -```js -const SimpleApp = StackNavigator({ - Home: { screen: HomeScreen }, - Chat: { screen: ChatScreen }, -}); -``` - -We want paths like `chat/Taylor` to link to a "Chat" screen with the `user` passed as a param. Let's re-configure our chat screen with a `path` that tells the router what relative path to match against, and what params to extract. This path spec would be `chat/:user`. - -```js -const SimpleApp = StackNavigator({ - Home: { screen: HomeScreen }, - Chat: { - screen: ChatScreen, - path: 'chat/:user', - }, -}); -``` - - -### URI Prefix - -Next, let's configure our navigation container to extract the path from the app's incoming URI. - -```js -const SimpleApp = StackNavigator({...}); - -// on Android, the URI prefix typically contains a host in addition to scheme -const prefix = Platform.OS == 'android' ? 'mychat://mychat/' : 'mychat://'; - -const MainApp = () => ; -``` - -## iOS - -Let's configure the native iOS app to open based on the `mychat://` URI scheme. - -In `SimpleApp/ios/SimpleApp/AppDelegate.m`: - -``` -// Add the header at the top of the file: -#import - -// Add this above the `@end`: -- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url - sourceApplication:(NSString *)sourceApplication annotation:(id)annotation -{ - return [RCTLinkingManager application:application openURL:url - sourceApplication:sourceApplication annotation:annotation]; -} -``` - -In Xcode, open the project at `SimpleApp/ios/SimpleApp.xcodeproj`. Select the project in sidebar and navigate to the info tab. Scroll down to "URL Types" and add one. In the new URL type, set the identifier and the url scheme to your desired url scheme. - -![Xcode project info URL types with mychat added](/assets/xcode-linking.png) - -Now you can press play in Xcode, or re-build on the command line: - -```sh -react-native run-ios -``` - -To test the URI on the simulator, run the following: - -``` -xcrun simctl openurl booted mychat://chat/Taylor -``` - -To test the URI on a real device, open Safari and type `mychat://chat/Taylor`. - -## Android - -To configure the external linking in Android, you can create a new intent in the manifest. - -In `SimpleApp/android/app/src/main/AndroidManifest.xml`, add the new `VIEW` type `intent-filter` inside the `MainActivity` entry: - -``` - - - - - - -``` - -Now, re-install the app: - -```sh -react-native run-android -``` - -To test the intent handling in Android, run the following: - -``` -adb shell am start -W -a android.intent.action.VIEW -d "mychat://mychat/chat/Taylor" com.simpleapp -``` - -```phone-example -linking -``` diff --git a/docs/guides/Guide-Basic-Example.md b/docs/guides/Guide-Basic-Example.md deleted file mode 100644 index a6721e015e..0000000000 --- a/docs/guides/Guide-Basic-Example.md +++ /dev/null @@ -1,235 +0,0 @@ -# Hello Mobile Navigation - -Let's use React Navigation to build a simple chat-like application for Android and iOS. - -## Setup and Installation - -First, make sure you're [all set up to use React Native](http://facebook.github.io/react-native/docs/getting-started.html). Next, create a new project and add `react-navigation`: - -```sh -# Create a new React Native App -react-native init SimpleApp -cd SimpleApp - -# Install the latest version of react-navigation from npm -npm install --save react-navigation - -# Run the new app -react-native run-android -# or: -react-native run-ios -``` - -If you are using `create-react-native-app` instead of `react-native init`, then: - -```sh -# Create a new React Native App -create-react-native-app SimpleApp -cd SimpleApp - -# Install the latest version of react-navigation from npm -npm install --save react-navigation - -# Run the new app -npm start - -# This will start a development server for you and print a QR code in your terminal. -``` - -Verify that you can successfully see the bare sample app run on iOS and/or Android: - -```phone-example -bare-project -``` - -We want to share code on iOS and Android, so let's delete the contents of `index.js` (or `index.ios.js` and `index.android.js` if using a React Native version before 0.49) and replace it with `import './App';` - after which, we need to create the new file for our app implementation, `App.js` (if you used `create-react-native-app` this has been already done) - -## Introducing Stack Navigator - -For our app, we want to use the `StackNavigator` because conceptually we want to obtain a 'card stack' effect of movement, where each new screen is put on the top of the stack and going back removes a screen from the top of the stack. Let's start with just one screen: - -```js -import React from 'react'; -import { - AppRegistry, - Text, -} from 'react-native'; -import { StackNavigator } from 'react-navigation'; - -class HomeScreen extends React.Component { - static navigationOptions = { - title: 'Welcome', - }; - render() { - return Hello, Navigation!; - } -} - -export const SimpleApp = StackNavigator({ - Home: { screen: HomeScreen }, -}); - -AppRegistry.registerComponent('SimpleApp', () => SimpleApp); -``` - -If you used `create-react-native-app` the already existing `App.js` will be modified to - -```js -import React from 'react'; -import { StyleSheet, Text, View } from 'react-native'; -import { StackNavigator } from 'react-navigation'; - -class HomeScreen extends React.Component { - static navigationOptions = { - title: 'Welcome' - }; - render() { - return Hello, Navigation!; - } -} - -const SimpleApp = StackNavigator({ - Home: { screen: HomeScreen } -}); - -export default class App extends React.Component { - render() { - return ; - } -} - -const styles = StyleSheet.create({ - container: { - flex: 1, - backgroundColor: '#fff', - alignItems: 'center', - justifyContent: 'center' - } -}); - -``` - -The `title` of the screen is configurable on the [static `navigationOptions`](/docs/navigators/navigation-options), where many options can be set to configure the presentation of the screen in the navigator. - -Now the same screen should appear on both iPhone and Android apps: - -```phone-example -first-screen -``` - -## Adding a New Screen - -In our `App.js` file, let's add a new screen called `ChatScreen`, defining it under `HomeScreen`: - -```js -// ... - -class HomeScreen extends React.Component { - //... -} - -class ChatScreen extends React.Component { - static navigationOptions = { - title: 'Chat with Lucy', - }; - render() { - return ( - - Chat with Lucy - - ); - } -} - -``` - -We can then add a button to our `HomeScreen` component that links to `ChatScreen`: we need to use the provided method `navigate` (from the [screen navigation prop](/docs/navigators/navigation-prop)) by giving it the `routeName` of the screen we want to reach, in this case `Chat`. - -```js -class HomeScreen extends React.Component { - static navigationOptions = { - title: 'Welcome', - }; - render() { - const { navigate } = this.props.navigation; - return ( - - Hello, Chat App! - - -); -``` - -Inside the infra: - -``` -class InfraScreen extends React.Component { - constructor() { - const {initURI, type} = this.props; - const ScreenView = ScreenRegistry[type].screen; - const router = ScreenView.router; - const deepLinkAction = router.getActionForURI(initURI); - const initAction = deepLinkAction || {type: 'init'} - const nav = router.getStateForAction(initAction); - this.state = { - nav, - }; - HybridNavigationModule.setNavOptions(this.state.nav); - } - componentWillUpdate() { - HybridNavigationModule.setNavOptions(this.state.nav); - } - dispatch = (action) => { - const {type} = this.props; - const ScreenView = ScreenRegistry[type].screen; - const {getStateForAction} = ScreenView.router; - const newNavState = getStateForAction(action, this.state.nav); - if (newNavState !== this.state.nav) { - this.setState({ nav: newNavState }); - return true; - } - if (action.type === 'URI') { - HybridNavigationModule.openURI(action.uri); - return true; - } - if (action.type === NavigationActions.BACK) { - HybridNavigationModule.goBack(); - return true; - } - HybridNavigationModule.openAction(action); - return true; - } - render() { - const {type} = this.props; - const ScreenView = ScreenRegistry[type].screen; - const navigation = { - dispatch: this.dispatch, - state: this.state.nav, - }; - return ; - } -} -``` - -## Setting title - -``` -MarketplaceScreen.router = { - getStateForAction(action, lastState) { - return lastState || {title: 'Marketplace Home'}; - }, -}; -``` -A HOC could be used to make this feel more elegant. - - -## Disabling/Enabling the right button - -``` -const TestScreen = ({ navigation }) => ( - - - Pressed {navigation.state} times - -); -TestScreen.router = { - getStateForAction(action, lastState = {}) { - let state = lastState || { - rightButtonEnabled: true, - rightButtonTitle: 'Tap Me', - pressCount: 0, - }; - if (action.type === 'ToggleMyButtonPressability') { - state = { - ...state, - rightButtonEnabled: !state.rightButtonEnabled, - }; - } else if (action.type === 'RightButtonPress') { - state = { - ...state, - pressCount: state.pressCount + 1, - }; - } - return state; - }, -}; -``` - - -## Before JS starts - -A JSON file could be defined for native to consume before JS spins up: - -``` -{ - "screens": [ - { - "type": "Profile", - "path": "/users/:id?name=:name", - "params": { - "name": "string", - "id": "number" - }, - "title": "%name%' s Profile", - "rightButtonTitle": "Message %name%" - }, - { - ... - } - ] -} -``` - -This seems like a pain to set up, so we can statically analyze our JS and autogenerate this JSON! If the JS in an app changes, there could be a way for JS to report the new routing configuration to native for use on the next cold start. diff --git a/docs/guides/Navigation-Actions.md b/docs/guides/Navigation-Actions.md deleted file mode 100644 index 2344606aba..0000000000 --- a/docs/guides/Navigation-Actions.md +++ /dev/null @@ -1,111 +0,0 @@ -# Navigation Actions - -All Navigation Actions return an object that can be sent to the router using `navigation.dispatch()` method. - -Note that if you want to dispatch react-navigation actions you should use the action creators provided in this library. - -The following actions are supported: -* [Navigate](#Navigate) - Navigate to another route -* [Reset](#Reset) - Replace current state with a new state -* [Back](#Back) - Go back to previous state -* [Set Params](#SetParams) - Set Params for given route -* [Init](#Init) - Used to initialize first state if state is undefined - -The action creator functions define `toString()` to return the action type, which enables easy usage with third-party Redux libraries, including redux-actions and redux-saga. - -### Navigate -The `Navigate` action will update the current state with the result of a `Navigate` action. - -- `routeName` - *String* - Required - A destination routeName that has been registered somewhere in the app's router -- `params` - *Object* - Optional - Params to merge into the destination route -- `action` - *Object* - Optional - (advanced) The sub-action to run in the child router, if the screen is a navigator. Any one of the actions described in this doc can be set as a sub-action. - -```js -import { NavigationActions } from 'react-navigation' - -const navigateAction = NavigationActions.navigate({ - - routeName: 'Profile', - - params: {}, - - action: NavigationActions.navigate({ routeName: 'SubProfileRoute'}) -}) - -this.props.navigation.dispatch(navigateAction) - -``` - - -### Reset - -The `Reset` action wipes the whole navigation state and replaces it with the result of several actions. - -- `index` - *number* - required - Index of the active route on `routes` array in navigation `state`. -- `actions` - *array* - required - Array of Navigation Actions that will replace the navigation state. -- `key` - *string or null* - optional - If set, the navigator with the given key will reset. If null, the root navigator will reset. - -```js -import { NavigationActions } from 'react-navigation' - -const resetAction = NavigationActions.reset({ - index: 0, - actions: [ - NavigationActions.navigate({ routeName: 'Profile'}) - ] -}) -this.props.navigation.dispatch(resetAction) - -``` -#### How to use the `index` parameter -The `index` param is used to specify the current active route. - -eg: given a basic stack navigation with two routes `Profile` and `Settings`. -To reset the state to a point where the active screen was `Settings` but have it stacked on top of a `Profile` screen, you would do the following: - -```js -import { NavigationActions } from 'react-navigation' - -const resetAction = NavigationActions.reset({ - index: 1, - actions: [ - NavigationActions.navigate({ routeName: 'Profile'}), - NavigationActions.navigate({ routeName: 'Settings'}) - ] -}) -this.props.navigation.dispatch(resetAction) - -``` - -### Back - -Go back to previous screen and close current screen. `back` action creator takes in one optional parameter: -- `key` - *string or null* - optional - If set, navigation will go back from the given key. If null, navigation will go back from the currently active route. - -```js -import { NavigationActions } from 'react-navigation' - -const backAction = NavigationActions.back({ - key: 'Profile' -}) -this.props.navigation.dispatch(backAction) - -``` - -### SetParams - -When dispatching `SetParams`, the router will produce a new state that has changed the params of a particular route, as identified by the key - -- `params` - *object* - required - New params to be merged into existing route params -- `key` - *string* - required - Route key that should get the new params - -```js -import { NavigationActions } from 'react-navigation' - -const setParamsAction = NavigationActions.setParams({ - params: { title: 'Hello' }, - key: 'screen-123', -}) -this.props.navigation.dispatch(setParamsAction) - -``` diff --git a/docs/guides/Redux-Integration.md b/docs/guides/Redux-Integration.md deleted file mode 100644 index 6a8b9af2bd..0000000000 --- a/docs/guides/Redux-Integration.md +++ /dev/null @@ -1,178 +0,0 @@ -# Redux Integration - -### Overview For Redux Integration -1. To handle your app's navigation state in Redux, you can pass your own `navigation` prop to a navigator. - -2. Once you pass your own navigation prop to the navigator, the default [`navigation`](https://reactnavigation.org/docs/navigators/navigation-prop) prop gets destroyed. You must construct your own `navigation` prop with [`state`](https://reactnavigation.org/docs/navigators/navigation-prop#state-The-screen's-current-stateroute), [`dispatch`](https://reactnavigation.org/docs/navigators/navigation-prop#dispatch-Send-an-action-to-the-router), and `addListener` properties. - -3. The `state` will be fed from the reducer assigned to handle navigation state and the `dispatch` will be Redux's default `dispatch`. Thus you will be able to dispatch normal redux actions using `this.props.navigation.dispatch(ACTION)`, reducer will update the navigation state on the basis of dispatched action, the new navigation state will then be passed to the navigator. - -4. A middleware is needed so that any events that mutate the navigation state properly trigger the event listeners. - -### Details Regarding Redux Integration -First, you need to add the `react-navigation-redux-helpers` package to your project. - - ```bash - yarn add react-navigation-redux-helpers - ``` - - or - - ```bash - npm install --save react-navigation-redux-helpers - ``` - -With Redux, your app's state is defined by a reducer. Each navigation router effectively has a reducer, called `getStateForAction`. The following is a minimal example of how you might use navigators within a Redux application: - -```es6 -import { - StackNavigator, - addNavigationHelpers, -} from 'react-navigation'; -import { - createStore, - applyMiddleware, - combineReducers, -} from 'redux'; -import { - createReduxBoundAddListener, - createReactNavigationReduxMiddleware, -} from 'react-navigation-redux-helpers'; -import { Provider, connect } from 'react-redux'; -import React from 'react'; - -const AppNavigator = StackNavigator(AppRouteConfigs); - -const initialState = AppNavigator.router.getStateForAction(AppNavigator.router.getActionForPathAndParams('Login')); - -const navReducer = (state = initialState, action) => { - const nextState = AppNavigator.router.getStateForAction(action, state); - - // Simply return the original `state` if `nextState` is null or undefined. - return nextState || state; -}; - -const appReducer = combineReducers({ - nav: navReducer, - ... -}); - -// Note: createReactNavigationReduxMiddleware must be run before createReduxBoundAddListener -const middleware = createReactNavigationReduxMiddleware( - "root", - state => state.nav, -); -const addListener = createReduxBoundAddListener("root"); - -class App extends React.Component { - render() { - return ( - - ); - } -} - -const mapStateToProps = (state) => ({ - nav: state.nav -}); - -const AppWithNavigationState = connect(mapStateToProps)(App); - -const store = createStore( - appReducer, - applyMiddleware(middleware), -); - -class Root extends React.Component { - render() { - return ( - - - - ); - } -} -``` - -Once you do this, your navigation state is stored within your Redux store, at which point you can fire navigation actions using your Redux dispatch function. - -Keep in mind that when a navigator is given a `navigation` prop, it relinquishes control of its internal state. That means you are now responsible for persisting its state, handling any deep linking, [Handling the Hardware Back Button in Android](#Handling-the-Hardware-Back-Button-in-Android), etc. - -Navigation state is automatically passed down from one navigator to another when you nest them. Note that in order for a child navigator to receive the state from a parent navigator, it should be defined as a `screen`. - -Applying this to the example above, you could instead define `AppNavigator` to contain a nested `TabNavigator` as follows: - -```es6 -const AppNavigator = StackNavigator({ - Home: { screen: MyTabNavigator }, -}); -``` - -In this case, once you `connect` `AppNavigator` to Redux as is done in `AppWithNavigationState`, `MyTabNavigator` will automatically have access to navigation state as a `navigation` prop. - -## Full example - -There's a working example app with Redux [here](https://github.com/react-community/react-navigation/tree/master/examples/ReduxExample) if you want to try it out yourself. - -## Mocking tests - -To make jest tests work with your react-navigation app, you need to change the jest preset in the `package.json`, see [here](https://facebook.github.io/jest/docs/tutorial-react-native.html#transformignorepatterns-customization): - - -```json -"jest": { - "preset": "react-native", - "transformIgnorePatterns": [ - "node_modules/(?!(jest-)?react-native|react-navigation)" - ] -} -``` - -## Handling the Hardware Back Button in Android - -By using the following snippet, your nav component will be aware of the back button press actions and will correctly interact with your stack. This is really useful on Android. - -```es6 -import React from "react"; -import { BackHandler } from "react-native"; -import { addNavigationHelpers, NavigationActions } from "react-navigation"; - -const AppNavigation = TabNavigator( - { - Home: { screen: HomeScreen }, - Settings: { screen: SettingScreen } - } -); - -class ReduxNavigation extends React.Component { - componentDidMount() { - BackHandler.addEventListener("hardwareBackPress", this.onBackPress); - } - componentWillUnmount() { - BackHandler.removeEventListener("hardwareBackPress", this.onBackPress); - } - onBackPress = () => { - const { dispatch, nav } = this.props; - if (nav.index === 0) { - return false; - } - dispatch(NavigationActions.back()); - return true; - }; - - render() { - const { dispatch, nav } = this.props; - const navigation = addNavigationHelpers({ - dispatch, - state: nav, - addListener, - }); - - return ; - } -} -``` diff --git a/docs/guides/Screen-Nav-Options.md b/docs/guides/Screen-Nav-Options.md deleted file mode 100644 index adb385b582..0000000000 --- a/docs/guides/Screen-Nav-Options.md +++ /dev/null @@ -1,104 +0,0 @@ - -# Screen Navigation Options - -Each screen can configure several aspects about how it gets presented in parent navigators. - -#### Two Ways to specify each option - -**Static configuration:** Each navigation option can either be directly assigned: - -```js -class MyScreen extends React.Component { - static navigationOptions = { - title: 'Great', - }; - ... -``` - -**Dynamic Configuration** - -Or, the options can be a function that takes the following arguments, and returns an object of navigation options that will override the route-defined and navigator-defined navigationOptions. - -- `props` - The same props that are available to the screen component - - `navigation` - The [navigation prop](/docs/navigators/navigation-prop) for the screen, with the screen's route at `navigation.state` - - `screenProps` - The props passing from above the navigator component - - `navigationOptions` - The default or previous options that would be used if new values are not provided - -```js -class ProfileScreen extends React.Component { - static navigationOptions = ({ navigation, screenProps }) => ({ - title: navigation.state.params.name + "'s Profile!", - headerRight: