Deprecate NavigationExperimental

Summary:
Docs change to encourage people to use React Navigation over other options.

Explains a bit of history about Navigator and NavigationExperimental.

Remove an intro guide that encourages use of Navigator. Hopefully the existing ReactNav guide fills this void.

Navigator docs are less emphasized but still present.

Reviewed By: mkonicek

Differential Revision: D4634452

fbshipit-source-id: 26763c2f02530009b3dfd20b0590fadcb5ea35ee
This commit is contained in:
Eric Vicenti 2017-03-01 11:34:27 -08:00 коммит произвёл Facebook Github Bot
Родитель d54c7f8282
Коммит 08dbc43fa6
4 изменённых файлов: 62 добавлений и 434 удалений

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

@ -5,7 +5,7 @@ layout: docs
category: The Basics
permalink: docs/more-resources.html
next: integration-with-existing-apps
previous: using-navigators
previous: networking
---
If you just read through this website, you should be able to build a pretty cool React Native app. But React Native isn't just a product made by one company - it's a community of thousands of developers. So if you're interested in React Native, here's some related stuff you might want to check out.

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

@ -8,15 +8,67 @@ next: performance
previous: javascript-environment
---
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`.
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 React Navigation.
If you are only targeting iOS and would like to stick to the native look and feel, check out `NavigatorIOS`. The `Navigator` component is older but has been thoroughly tested in production.
## React Navigation
The community solution to navigation is a standalone library that allows developers to set up the screens of an app with just a few lines of code.
The first step is to install in your app:
```
npm install --save react-navigation
```
Then you can quickly create an app with a home screen and a profile screen:
```
import {
StackNavigator,
} from 'react-navigation';
const App = StackNavigator({
Main: {screen: MainScreen},
Profile: {screen: ProfileScreen},
});
```
Each screen component can set navigation options such as the header title. It can use action creators on the `navigation` prop to link to other screens:
```
class MainScreen extends React.Component {
static navigationOptions = {
title: 'Welcome',
};
render() {
const { navigate } = this.props.navigation;
return (
<Button
title="Go to Jane's profile"
onPress={() =>
navigate('Profile', { name: 'Jane' });
}
/>
);
}
}
```
React Navigation routers make it easy to override navigation logic or integrate it into redux. Because routers can be nested inside eachother, developers can override navigation logic for one area of the app without making widespread changes.
The views in React Navigation use native components and the `Animated` library to deliver 60fps animations that are run on the native thread. Plus, the animations and gestures can be easily customized.
For a complete intro to React Navigation, follow the [getting started guide](https://reactnavigation.org/docs/intro/), or browse other docs such as the [intro to navigators](https://reactnavigation.org/docs/navigators/).
## Navigator
`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/using-navigators.html).
Like React Navigation, `Navigator` provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize. Navigator was released alongside React Native in 2015, so it predates the Animated library with native-thread animations.
![](img/NavigationStack-Navigator.gif)
`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.
`Navigator` can 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.
Check out the [Navigator API reference](docs/navigator.html) for specific examples that cover each of these scenarios.
@ -36,7 +88,7 @@ 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.
Like other navigation systems, `NavigatorIOS` uses routes to represent screens, 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.
@ -94,252 +146,10 @@ Check out the [`NavigatorIOS` reference docs](docs/navigatorios.html) to learn m
## 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.
Since early 2016, React Native has shipped with an experimental re-implementation of the original `Navigator` component called `CardStack`. The major benefit it had over `Navigator` is the smooth native-thread animations provided by the Animated library.
```javascript
<NavigationCardStack
onNavigateBack={onPopRouteFunc}
navigationState={myNavigationState}
renderScene={renderSceneFun}
/>
```
Because `NavigationExperimental` only included view components, it required a lot of boilerplate to use by itself. Several libraries sprung up around it, making it easier to use. Libraries such as `react-native-router-flux`, `ex-navigation`, and `react-router-native` all wrapped NavigationExperimental views in an easier-to-use API. Authors of many of these libraries now support React Navigation.
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`.
The `CardStack` and other NavigationExperimental views live on as a part of the React Navigation project. The new library aims to be easy to use, while continuing to enable the smooth and customizable animations that NavigationExperimental pioneered.
```javascript
import React, { Component } from 'react';
import { NavigationExperimental } from 'react-native';
const {
CardStack: NavigationCardStack,
StateUtils: NavigationStateUtils,
} = 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.
### 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:
```javascript
class BleedingEdgeApplication extends Component {
constructor(props, context) {
super(props, context);
this.state = {
// This defines the initial navigation state.
navigationState: {
index: 0, // Starts with first route focused.
routes: [{key: 'My Initial Scene'}], // Starts with only one route.
},
};
// We'll define this function later - hang on
this._onNavigationChange = this._onNavigationChange.bind(this);
}
_onNavigationChange(type) {
// It's literally the next step. We'll get to it!
}
render() {
return (
<Text>This is a placeholder. We will come back to this and render our navigation here later.</Text>
);
}
}
```
Alright, now we have a simple stateful component that doesn't do much at all. We can change that. Our initial state contains one route, and the current index. That looks suspiciously just like our initial route definition in Navigator. Do you remember which actions its navigator object provided?
Push and pop, of course. That seems pretty straightforward to implement. I promised you earlier we would be using reducers to manage state at the top-level object. Sit tight.
### Step 2. Reducing the Navigation State
NavigationExperimental comes built-in with some useful reducers, and they are all available as part of NavigationStateUtils. The two we will be using right now are called -- yep -- push and pop. They take a navigationState object, and return a new navigationState object.
We can use them to write our `_onNavigationChange` function which, given a "push" or "pop" action, will reduce the state accordingly.
```javascript
_onNavigationChange(type) {
// Extract the navigationState from the current state:
let {navigationState} = this.state;
switch (type) {
case 'push':
// Push a new route, which in our case is an object with a key value.
// I am fond of cryptic keys (but seriously, keys should be unique)
const route = {key: 'Route-' + Date.now()};
// Use the push reducer provided by NavigationStateUtils
navigationState = NavigationStateUtils.push(navigationState, route);
break;
case 'pop':
// Pop the current route using the pop reducer.
navigationState = NavigationStateUtils.pop(navigationState);
break;
}
// NavigationStateUtils gives you back the same `navigationState` if nothing
// has changed. We will only update state if it has changed.
if (this.state.navigationState !== navigationState) {
// Always use setState() when setting a new state!
this.setState({navigationState});
// If you are new to ES6, the above is equivalent to:
// this.setState({navigationState: navigationState});
}
}
```
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 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.
```javascript
class TappableRow extends Component {
render() {
return (
<TouchableHighlight
style={styles.row}
underlayColor="#D0D0D0"
onPress={this.props.onPress}>
<Text style={styles.buttonText}>
{this.props.text}
</Text>
</TouchableHighlight>
);
}
}
```
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.
```javascript
class MyVeryComplexScene extends Component {
render() {
return (
<ScrollView style={styles.scrollView}>
<Text style={styles.row}>
Route: {this.props.route.key}
</Text>
<TappableRow
text="Tap me to load the next scene"
onPress={this.props.onPushRoute}
/>
<TappableRow
text="Tap me to go back"
onPress={this.props.onPopRoute}
/>
</ScrollView>
);
}
}
```
### Step 4. Create a Navigation Stack
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.
```javascript
class MyVerySimpleNavigator extends Component {
// This sets up the methods (e.g. Pop, Push) for navigation.
constructor(props, context) {
super(props, context);
this._onPushRoute = this.props.onNavigationChange.bind(null, 'push');
this._onPopRoute = this.props.onNavigationChange.bind(null, 'pop');
this._renderScene = this._renderScene.bind(this);
}
// Now we finally get to use the `NavigationCardStack` to render the scenes.
render() {
return (
<NavigationCardStack
onNavigateBack={this._onPopRoute}
navigationState={this.props.navigationState}
renderScene={this._renderScene}
style={styles.navigator}
/>
);
}
// Render a scene for route.
// The detailed spec of `sceneProps` is defined at `NavigationTypeDefinition`
// as type `NavigationSceneRendererProps`.
// Here you could choose to render a different component for each route, but
// we'll keep it simple.
_renderScene(sceneProps) {
return (
<MyVeryComplexScene
route={sceneProps.scene.route}
onPushRoute={this._onPushRoute}
onPopRoute={this._onPopRoute}
onExit={this.props.onExit}
/>
);
}
}
```
That's it -- so close to the finish line I can smell it. Let's plug our new navigator into our top-level component:
```javascript
class BleedingEdgeApplication extends Component {
// constructor and other methods omitted for clarity
render() {
return (
<MyVerySimpleNavigator
navigationState={this.state.navigationState}
onNavigationChange={this._onNavigationChange}
onExit={this._exit}
/>
);
}
}
```
We're done! Bask in the glory of NavigationExperimental.
#### Hey -- I think you are missing something.
(Oh yes, sorry about that -- here's our missing imports and styles.)
```javascript
import { NavigationExperimental, PixelRatio, ScrollView, StyleSheet, Text, TouchableHighlight } from 'react-native';
const styles = StyleSheet.create({
navigator: {
flex: 1,
},
scrollView: {
marginTop: 64
},
row: {
padding: 15,
backgroundColor: 'white',
borderBottomWidth: 1 / PixelRatio.get(),
borderBottomColor: '#CDCDCD',
},
rowText: {
fontSize: 17,
},
buttonText: {
fontSize: 17,
fontWeight: '500',
},
});
```
### Homework
You are now an expert navigator. Take a look at [NavigationExperimental in UIExplorer](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/js/NavigationExperimental) to learn how to implement other types of navigation hierarchies, such as a tabbed application with multiple navigation stacks.
As of React Native 0.43, `NavigationExperimental` is deprecated. It will be removed from the codebase in a later version.

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

@ -4,7 +4,7 @@ title: Networking
layout: docs
category: The Basics
permalink: docs/network.html
next: using-navigators
next: more-resources
previous: using-a-listview
---

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

@ -1,182 +0,0 @@
---
id: using-navigators
title: Using Navigators
layout: docs
category: The Basics
permalink: docs/using-navigators.html
next: more-resources
previous: networking
---
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, Navigator } from 'react-native';
export default class MyScene extends Component {
static get defaultProps() {
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 { AppRegistry } 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) => {
return <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. Edit your index*.js file to look something like this:
```javascript
import React, { Component } from 'react';
import { AppRegistry, Navigator } from 'react-native';
import MyScene from './MyScene';
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();
}
}}
/>
}
/>
)
}
}
AppRegistry.registerComponent('SimpleNavigationApp', () => SimpleNavigationApp);
```
And your MyScene.js to match this:
```javascript
import React, { Component, PropTypes } from 'react';
import { View, Text, TouchableHighlight } from 'react-native';
export default class MyScene extends Component {
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>
)
}
}
MyScene.propTypes = {
title: PropTypes.string.isRequired,
onForward: PropTypes.func.isRequired,
onBack: PropTypes.func.isRequired,
};
```
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](docs/more-resources.html).