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
This commit is contained in:
Héctor Ramos 2016-06-30 17:44:34 -07:00 коммит произвёл Facebook Github Bot 9
Родитель ccd608a4b6
Коммит 7d3fbbdb68
4 изменённых файлов: 199 добавлений и 107 удалений

Просмотреть файл

@ -4,7 +4,7 @@ title: JavaScript Environment
layout: docs
category: Guides
permalink: docs/javascript-environment.html
next: navigator-comparison
next: navigation
---
## JavaScript Runtime

Просмотреть файл

@ -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
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) => {
<MyScene title={route.title} />
}}
/>
```
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 (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) =>
<MyScene
title={route.title}
// Function to call when a new scene should be displayed
onForward={ () => {
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 (
<View>
<Text>Current Scene: { this.props.title }</Text>
<TouchableHighlight onPress={this.props.onForward}>
<Text>Tap me to load the next scene</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.props.onBack}>
<Text>Tap me to go back</Text>
</TouchableHighlight>
</View>
)
}
}
```
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
<NavigatorIOS
initialRoute={{
component: MyScene,
@ -111,13 +35,11 @@ If you are targeting iOS only, you may also want to consider using [NavigatorIOS
/>
```
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
<NavigationCardStack
onNavigateBack={onPopRouteFunc}
navigationState={myNavigationState}
@ -179,9 +103,9 @@ Navigator and NavigatorIOS are both stateful components. If your app has multipl
/>
```
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({

167
docs/Navigators.md Normal file
Просмотреть файл

@ -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 (
<View>
<Text>Hi! My name is {this.props.title}.</Text>
</View>
)
}
}
```
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 (
<MyScene />
)
}
}
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 (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) => {
<MyScene title={route.title} />
}}
/>
);
}
```
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 (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) =>
<MyScene
title={route.title}
// Function to call when a new scene should be displayed
onForward={ () => {
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 (
<View>
<Text>Current Scene: { this.props.title }</Text>
<TouchableHighlight onPress={this.props.onForward}>
<Text>Tap me to load the next scene</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.props.onBack}>
<Text>Tap me to go back</Text>
</TouchableHighlight>
</View>
)
}
}
```
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).

Просмотреть файл

@ -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).