From 7d3fbbdb68e5015311bce60236e0ae06d62f17a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?H=C3=A9ctor=20Ramos?= Date: Thu, 30 Jun 2016 17:44:34 -0700 Subject: [PATCH] Introduce navigators in the tutorial Summary: Adds a new section to the tutorial. Covers the basics of scenes and navigators. The navigator comparison doc has been moved to docs/navigation.html in this PR. ![navigators](https://cloud.githubusercontent.com/assets/165856/16505919/37459e3a-3ed4-11e6-87e9-5fa7e6f792d3.png) Closes https://github.com/facebook/react-native/pull/8515 Differential Revision: D3507325 Pulled By: caabernathy fbshipit-source-id: e9ee5b2572868189af198cdf461b2728dfa84f9e --- docs/JavaScriptEnvironment.md | 2 +- .../{NavigatorComparison.md => Navigation.md} | 128 +++----------- docs/Navigators.md | 167 ++++++++++++++++++ docs/Networking.md | 9 +- 4 files changed, 199 insertions(+), 107 deletions(-) rename docs/{NavigatorComparison.md => Navigation.md} (62%) create mode 100644 docs/Navigators.md diff --git a/docs/JavaScriptEnvironment.md b/docs/JavaScriptEnvironment.md index 4e2e3c1f21..857a3fd71a 100644 --- a/docs/JavaScriptEnvironment.md +++ b/docs/JavaScriptEnvironment.md @@ -4,7 +4,7 @@ title: JavaScript Environment layout: docs category: Guides permalink: docs/javascript-environment.html -next: navigator-comparison +next: navigation --- ## JavaScript Runtime diff --git a/docs/NavigatorComparison.md b/docs/Navigation.md similarity index 62% rename from docs/NavigatorComparison.md rename to docs/Navigation.md index f61bec10b2..70d89ac42d 100644 --- a/docs/NavigatorComparison.md +++ b/docs/Navigation.md @@ -1,99 +1,23 @@ --- -id: navigator-comparison +id: navigation title: Navigation layout: docs category: Guides -permalink: docs/navigator-comparison.html +permalink: docs/navigation.html next: performance --- -Mobile apps rarely consist of just one scene (another word for screen). As soon as you add a second scene to your app, you will have to take into consideration how the user will navigate from one scene to the other. - -You can use navigators to transition between multiple scenes. These transitions can be typical side-to-side animations down a master/detail stack, or vertical modal popups. +This guide covers the various navigation components available in React Native. If you are just getting started with navigation, you will probably want to use `Navigator`. If you are only targeting iOS and would like to stick to the native look and feel, check out `NavigatorIOS`. If you are looking for greater control over your navigation stack, you can't go wrong with `NavigationExperimental`. ## Navigator -React Native has several built-in navigation components, but for your first app you will probably want to use `Navigator`. It provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize. +`Navigator` provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize. This is the same component you used to build your first navigation stack in the [navigators tutorial](docs/navigators.html). ![](img/NavigationStack-Navigator.gif) -Something you will encounter a lot when dealing with navigation is the concept of routes. A route is an object that contains information about a scene. It is used to provide all the context that the navigator's `renderScene` function needs to render a scene. A basic `Navigator` implementation may look like this: +`Navigator` can easily be adapted to render different components based on the current route in its `renderScene` function. It will transition new scenes onto the screen by sliding in from the right by default, but you can control this behavior by using the `configureScene` function. You can also configure a navigation bar through the `navigationBar` prop. -```js - { - - }} -/> -``` - -The above example will display a single scene, but in order to push a new scene onto screen you will need to learn about `push` and `pop`. These two methods are provided by the `navigator` object that is passed to your `renderScene` function. They can be used, as you may have realized, to push and pop routes into your navigation stack. - -A more complete example that demonstrates the pushing and popping of routes could therefore look something like this: - -```js -import React, { Component, PropTypes } from 'react'; -import { Navigator, Text, TouchableHighlight, View } from 'react-native'; - -export default class SimpleNavigationApp extends Component { - render() { - return ( - - { - const nextIndex = route.index + 1; - navigator.push({ - title: 'Scene ' + nextIndex, - index: nextIndex, - }); - }} - - // Function to call to go back to the previous scene - onBack={() => { - if (route.index > 0) { - navigator.pop(); - } - }} - /> - } - /> - ) - } -} - -class MyScene extends Component { - static propTypes = { - title: PropTypes.string.isRequired, - onForward: PropTypes.func.isRequired, - onBack: PropTypes.func.isRequired, - } - render() { - return ( - - Current Scene: { this.props.title } - - Tap me to load the next scene - - - Tap me to go back - - - ) - } -} -``` - -In this example, the `MyScene` component is passed the title of the current route via the `title` prop. It displays two tappable components that call the `onForward` and `onBack` functions passed through its props, which in turn will call `navigator.push()` and `navigator.pop()` as needed. - -While this is a very basic example, it can easily be adapted to render an entirely different component based on the route that is passed to the `renderScene` function. Navigator will push new scenes from the right by default, and you can control this behavior by using the `configureScene` function. You can also configure a navigation bar through the `navigationBar` prop. - -Check out the [Navigator API reference](docs/navigator.html) for more code samples. +Check out the [Navigator API reference](docs/navigator.html) for specific examples that cover each of these scenarios. ## NavigatorIOS @@ -101,7 +25,7 @@ If you are targeting iOS only, you may also want to consider using [NavigatorIOS ![](img/NavigationStack-NavigatorIOS.gif) -```js +```javascript ``` -Just like Navigator, NavigatorIOS uses routes to represent scenes, with some important differences. The actual component that will be rendered can be specified using the `component` key in the route, and any props that should be passed to this component can be specified in `passProps`. A "navigator" object is automatically passed as a prop to the component, allowing you to call `push` and `pop` as needed. +Just like `Navigator`, `NavigatorIOS` uses routes to represent scenes, with some important differences. The actual component that will be rendered can be specified using the `component` key in the route, and any props that should be passed to this component can be specified in `passProps`. A "navigator" object is automatically passed as a prop to the component, allowing you to call `push` and `pop` as needed. -As NavigatorIOS leverages native UIKit navigation, it will automatically render a navigation bar with a back button and title. +As `NavigatorIOS` leverages native UIKit navigation, it will automatically render a navigation bar with a back button and title. -Check out the [NavigatorIOS reference docs](docs/navigatorios.html) to learn more about this component. - -```js +```javascript import React, { Component, PropTypes } from 'react'; import { NavigatorIOS, Text, TouchableHighlight, View } from 'react-native'; @@ -165,13 +87,15 @@ class MyScene extends Component { } ``` +Check out the [`NavigatorIOS` reference docs](docs/navigatorios.html) to learn more about this component. + > You may also want to check out [react-native-navigation](https://github.com/wix/react-native-navigation), a component that aims to provide native navigation on both iOS and Android. ## NavigationExperimental -Navigator and NavigatorIOS are both stateful components. If your app has multiple of these, it can become tricky to coordinate navigation transitions between them. NavigationExperimental provides a different approach to navigation, allowing any view to act as a navigation view and using reducers to manipulate state at a top-level object. It is bleeding edge as the name implies, but you might want to check it out if you are craving greater control over your app's navigation. +`Navigator` and `NavigatorIOS` are both stateful components. If your app has multiple of these, it can become tricky to coordinate navigation transitions between them. NavigationExperimental provides a different approach to navigation, allowing any view to act as a navigation view and using reducers to manipulate state at a top-level object. It is bleeding edge as the name implies, but you might want to check it out if you are craving greater control over your app's navigation. -```js +```javascript ``` -You can import NavigationExperimental like any other component in React Native. Once you have that, you can deconstruct any additional components from NavigationExperimental that you may find useful. Since I am feeling like building navigation stacks today, I'll go ahead and pick out NavigationCardStack and NavigationStateUtils. +You can import `NavigationExperimental` like any other component in React Native. Once you have that, you can deconstruct any additional components from `NavigationExperimental` that you may find useful. Since I am feeling like building navigation stacks today, I'll go ahead and pick out `NavigationCardStack` and `NavigationStateUtils`. -```js +```javascript import React, { Component } from 'react'; import { NavigationExperimental } from 'react-native'; @@ -191,13 +115,13 @@ const { } = NavigationExperimental; ``` -As I said earlier, NavigationExperimental takes a different approach than Navigator and NavigatorIOS. Using it to build a navigation stack requires a few more steps than the stateful components, but the payoff is worth it. +As I said earlier, `NavigationExperimental` takes a different approach than `Navigator` and `NavigatorIOS`. Using it to build a navigation stack requires a few more steps than the stateful components, but the payoff is worth it. ### Step 1. Define Initial State and Top Level Component Create a new component for your application. This will be the top-level object, so we will define the initial state here. The navigation state will be defined in the `navigationState` key, where we define our initial route: -```js +```javascript class BleedingEdgeApplication extends Component { constructor(props, context) { super(props, context); @@ -236,7 +160,7 @@ NavigationExperimental comes built-in with a some useful reducers, and they are We can use them to write our `_onNavigationChange` function which, given a "push" or "pop" action, will reduce the state accordingly. -```js +```javascript _onNavigationChange(type) { // Extract the navigationState from the current state: let {navigationState} = this.state; @@ -270,13 +194,13 @@ _onNavigationChange(type) { Cool. I'm getting the hang of this. This is the heart of NavigationExperimental. We are only handling two actions here, but a more complex application could also take into account a "back" action (e.g. Android back button), as well as handle the transition between several tabs in a tabbed application. -I am still missing the initial scene that will be rendered (as well as the actual navigator that will wrap it, but lets not get ahead of ourselves). +I am still missing the initial scene that will be rendered (as well as the actual navigator that will wrap it, but let's not get ahead of ourselves). ### Step 3. Define Scenes First I want to define a Row component out of convenience. It displays some text and can call some function when pressed. -```js +```javascript class TappableRow extends Component { render() { return ( @@ -295,7 +219,7 @@ class TappableRow extends Component { Now I will define my actual scene. It uses a scroll view to display a vertical list of items. The first row displays the current route's key, and two more rows will call our theoretical navigator's push and pop functions. -```js +```javascript class MyVeryComplexScene extends Component { render() { return ( @@ -321,7 +245,7 @@ class MyVeryComplexScene extends Component { Now that I have defined the state and a function to manage it, I think I can go ahead and create a proper navigator component now. While I'm at it, I'll render my scene after configuring it with the current route's props. -```js +```javascript class MyVerySimpleNavigator extends Component { // This sets up the methods (e.g. Pop, Push) for navigation. @@ -364,9 +288,9 @@ class MyVerySimpleNavigator extends Component { } ``` -That's it -- so close to the finish line I can smell it. Lets plug our new navigator into our top-level component: +That's it -- so close to the finish line I can smell it. Let's plug our new navigator into our top-level component: -```js +```javascript class BleedingEdgeApplication extends Component { // constructor and other methods omitted for clarity @@ -389,7 +313,7 @@ We're done! Bask in the glory of NavigationExperimental. (Oh yes, sorry about that -- here's our missing imports and styles.) -```js +```javascript import { NavigationExperimental, PixelRatio, ScrollView, StyleSheet, Text, TouchableHighlight } from 'react-native'; const styles = StyleSheet.create({ diff --git a/docs/Navigators.md b/docs/Navigators.md new file mode 100644 index 0000000000..eb389f87d8 --- /dev/null +++ b/docs/Navigators.md @@ -0,0 +1,167 @@ +--- +id: navigators +title: Using Navigators +layout: docs +category: The Basics +permalink: docs/using-navigators.html +next: more-resources +--- + +Mobile apps rarely consist of just one screen. As soon as you add a second screen to your app, you will have to take into consideration how the user will navigate from one screen to the other. + +You can use navigators to transition between multiple screens. These transitions can be typical side-to-side animations down a master/detail stack, or vertical modal popups. + +## Navigator + +React Native has several built-in navigation components, but for your first app you will probably want to use `Navigator`. It provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize. + +![](img/NavigationStack-Navigator.gif) + +### Working with Scenes + +At this point you should feel comfortable rendering all sorts of components in your app, be it a simple `View` with `Text` inside, or a `ScrollView` with a list of `Image`s. Together, these components make up a scene (another word for screen) in your app. + +A scene is nothing other than a React component that is typically rendered full screen. This is in contrast to a `Text`, an `Image`, or even a custom `SpinningBeachball` component that is meant to be rendered as part of a screen. You may have already used one without realizing it - the ["HelloWorldApp"](docs/tutorial.html), the ["FlexDirectionBasics"](docs/flexbox.html), and the ["ListViewBasics"](docs/using-a-listview.html) components covered earlier in the tutorial are all examples of scenes. + +For simplicity's sake, let's define a simple scene that displays a bit of text. We will come back to this scene later as we add navigation to our app. Create a new file called "MyScene.js" with the following contents: + +```javascript +import React, { Component } from 'react'; +import { View, Text } from 'react-native'; + +export default class MyScene extends Component { + getDefaultProps() { + return { + title: 'MyScene' + }; + } + + render() { + return ( + + Hi! My name is {this.props.title}. + + ) + } +} +``` + +Notice the `export default` in front of the component declaration. This will _export_ the component, and in turn allow other components to _import_ it later on, like so: + +```javascript +import React, { Component } from 'react'; +import { View, Text } from 'react-native'; + +import MyScene from './MyScene'; + +class YoDawgApp extends Component { + render() { + return ( + + ) + } +} + +AppRegistry.registerComponent('YoDawgApp', () => YoDawgApp); +``` + +We now have a simple app that renders your scene and nothing else. In this case, `MyScene` is a simple example of a [reusable React component](https://facebook.github.io/react/docs/reusable-components.html). + +### Using Navigator + +Enough about scenes, let's start navigating. We will start by rendering a `Navigator`, and then let the `Navigator` render the scene for you by passing in your own render function to its `renderScene` prop. + +```javascript +render() { + return ( + { + + }} + /> + ); +} +``` + +Something you will encounter a lot when dealing with navigation is the concept of routes. A route is an object that contains information about a scene. It is used to provide all the context that the navigator's `renderScene` function needs to render a scene. It can have any number of keys to help distinguish your scene, and I happened to pick a single `title` key for the above example. + +#### Pushing scenes onto the stack + +In order to transition to a new scene, you will need to learn about `push` and `pop`. These two methods are provided by the `navigator` object that is passed to your `renderScene` function above. They can be used, as you may have realized, to push and pop routes into your navigation stack. + +```javascript +navigator.push({ + title: 'Next Scene', + index: 1, +}); + +navigator.pop(); +``` + +A more complete example that demonstrates the pushing and popping of routes could therefore look something like this: + +```javascript +import React, { Component, PropTypes } from 'react'; +import { Navigator, Text, TouchableHighlight, View } from 'react-native'; + +export default class SimpleNavigationApp extends Component { + render() { + return ( + + { + const nextIndex = route.index + 1; + navigator.push({ + title: 'Scene ' + nextIndex, + index: nextIndex, + }); + }} + + // Function to call to go back to the previous scene + onBack={() => { + if (route.index > 0) { + navigator.pop(); + } + }} + /> + } + /> + ) + } +} + +class MyScene extends Component { + static propTypes = { + title: PropTypes.string.isRequired, + onForward: PropTypes.func.isRequired, + onBack: PropTypes.func.isRequired, + } + render() { + return ( + + Current Scene: { this.props.title } + + Tap me to load the next scene + + + Tap me to go back + + + ) + } +} +``` + +In this example, the `MyScene` component is passed the title of the current route via the `title` prop. It displays two tappable components that call the `onForward` and `onBack` functions passed through its props, which in turn will call `navigator.push()` and `navigator.pop()` as needed. + +Check out the [Navigator API reference](docs/navigator.html) for more `Navigator` code samples, or read through the [Navigation guide](docs/navigation.html) for other examples of what you can do with navigators. + +## High Five! + +If you've gotten here by reading linearly through the tutorial, then you are a pretty impressive human being. Congratulations. Next, you might want to check out [all the cool stuff the community does with React Native](/react-native/docs/more-resources.html). diff --git a/docs/Networking.md b/docs/Networking.md index 798087fc27..23a8289778 100644 --- a/docs/Networking.md +++ b/docs/Networking.md @@ -4,7 +4,7 @@ title: Networking layout: docs category: The Basics permalink: docs/network.html -next: more-resources +next: navigators --- Many mobile apps need to load resources from a remote URL. You may want to make a POST request to a REST API, or you may simply need to fetch a chunk of static content from another server. @@ -100,14 +100,15 @@ request.send(); ## WebSocket Support -React Native supports [WebSocket](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), a protocol which provides full-duplex communication channels over a single TCP connection. +React Native also supports [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), a protocol which provides full-duplex communication channels over a single TCP connection. ```js var ws = new WebSocket('ws://host.com/path'); ws.onopen = () => { // connection opened - ws.send('something'); + + ws.send('something'); // send a message }; ws.onmessage = (e) => { @@ -126,4 +127,4 @@ ws.onclose = (e) => { }; ``` -If you've gotten here by reading linearly through the tutorial, then you are a pretty impressive human being. Congratulations. Next, you might want to check out [all the cool stuff the community does with React Native](/react-native/docs/more-resource.html). +Your app can now display all sorts of data and you may soon need to organize this content into several screens. To manage the transition between these screens, you will need to learn about [navigators](/react-native/docs/using-navigators.html).