CLI: Update Navigation app template

Summary:
Update the template that will be used by `react-native init --template navigation`. The goal is to make it easier for people to get started by demonstrating a few very basic concepts such as navigation, lists and text input.

**Test plan (required)**

<img src="https://cloud.githubusercontent.com/assets/346214/22697898/ced66f52-ed4a-11e6-9b90-df6daef43199.gif" alt="Android Example" height="800" style="float: left"/>

<img src="https://cloud.githubusercontent.com/assets/346214/22697901/cfeab3e4-ed4a-11e6-8552-d76585317ac2.gif" alt="iOS Example" height="800"/>
Closes https://github.com/facebook/react-native/pull/12260

Differential Revision: D4521758

Pulled By: mkonicek

fbshipit-source-id: d7d9e481dd3373917ac68ec9169b9ac3267547a9
This commit is contained in:
Martin Konicek
2017-02-07 09:03:00 -08:00
committed by Facebook Github Bot
parent 016969df49
commit 4551e9347a
7 changed files with 216 additions and 37 deletions

View File

@@ -1,9 +1,4 @@
import React, { Component } from 'react';
import {
ListView,
Platform,
Text,
} from 'react-native';
import { TabNavigator } from 'react-navigation';
import ChatListScreen from './chat/ChatListScreen';

View File

@@ -1,16 +1,19 @@
import React, { Component } from 'react';
import {
ActivityIndicator,
Image,
ListView,
Platform,
StyleSheet,
View,
} from 'react-native';
import ListItem from '../../components/ListItem';
import Backend from '../../lib/Backend';
export default class ChatListScreen extends Component {
static navigationOptions = {
title: 'Friends',
title: 'Chats',
header: {
visible: Platform.OS === 'ios',
},
@@ -29,28 +32,48 @@ export default class ChatListScreen extends Component {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
'Claire', 'John'
])
isLoading: true,
dataSource: ds,
};
}
async componentDidMount() {
const chatList = await Backend.fetchChatList();
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState((prevState) => ({
dataSource: prevState.dataSource.cloneWithRows(chatList),
isLoading: false,
}));
}
// Binding the function so it can be passed to ListView below
// and 'this' works properly inside _renderRow
_renderRow = (name) => {
// and 'this' works properly inside renderRow
renderRow = (name) => {
return (
<ListItem
label={name}
onPress={() => this.props.navigation.navigate('Chat', {name: name})}
onPress={() => {
// Start fetching in parallel with animating
this.props.navigation.navigate('Chat', {
name: name,
});
}}
/>
)
}
render() {
if (this.state.isLoading) {
return (
<View style={styles.loadingScreen}>
<ActivityIndicator />
</View>
);
}
return (
<ListView
dataSource={this.state.dataSource}
renderRow={this._renderRow}
renderRow={this.renderRow}
style={styles.listView}
/>
);
@@ -58,6 +81,11 @@ export default class ChatListScreen extends Component {
}
const styles = StyleSheet.create({
loadingScreen: {
backgroundColor: 'white',
paddingTop: 8,
flex: 1,
},
listView: {
backgroundColor: 'white',
},

View File

@@ -1,14 +1,15 @@
import React, { Component } from 'react';
import {
ActivityIndicator,
Button,
ListView,
Platform,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
import KeyboardSpacer from '../../components/KeyboardSpacer';
import Backend from '../../lib/Backend';
export default class ChatScreen extends Component {
@@ -19,23 +20,59 @@ export default class ChatScreen extends Component {
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
const messages = [
{
name: props.navigation.state.params.name,
name: 'Claire',
text: 'I ❤️ React Native!',
},
];
this.state = {
messages: messages,
dataSource: ds.cloneWithRows(messages),
messages: [],
dataSource: ds,
myMessage: '',
isLoading: true,
};
}
async componentDidMount() {
let chat;
try {
chat = await Backend.fetchChat(this.props.navigation.state.params.name);
} catch (err) {
// Here we would handle the fact the request failed, e.g.
// set state to display "Messages could not be loaded".
// We should also check network connection first before making any
// network requests - maybe we're offline? See React Native's NetInfo
// module.
this.setState({
isLoading: false,
});
return;
}
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.setState((prevState) => ({
messages: chat.messages,
dataSource: prevState.dataSource.cloneWithRows(chat.messages),
isLoading: false,
}));
}
onAddMessage = async () => {
// Optimistically update the UI
this.addMessageLocal();
// Send the request
try {
await Backend.sendMessage({
name: this.props.navigation.state.params.name,
// TODO Is reading state like this outside of setState OK?
// Can it contain a stale value?
message: this.state.myMessage,
});
} catch (err) {
// Here we would handle the request failure, e.g. call setState
// to display a visual hint showing the message could not be sent.
}
}
addMessage = () => {
addMessageLocal = () => {
this.setState((prevState) => {
if (!prevState.myMessage) return prevState;
if (!prevState.myMessage) {
return prevState;
}
const messages = [
...prevState.messages, {
name: 'Me',
@@ -51,7 +88,7 @@ export default class ChatScreen extends Component {
this.refs.textInput.clear();
}
myMessageChange = (event) => {
onMyMessageChange = (event) => {
this.setState({myMessage: event.nativeEvent.text});
}
@@ -63,6 +100,13 @@ export default class ChatScreen extends Component {
)
render() {
if (this.state.isLoading) {
return (
<View style={styles.container}>
<ActivityIndicator />
</View>
);
}
return (
<View style={styles.container}>
<ListView
@@ -78,13 +122,13 @@ export default class ChatScreen extends Component {
style={styles.textInput}
placeholder='Type a message...'
text={this.state.myMessage}
onSubmitEditing={this.addMessage}
onChange={this.myMessageChange}
onSubmitEditing={this.onAddMessage}
onChange={this.onMyMessageChange}
/>
{this.state.myMessage !== '' && (
<Button
title="Send"
onPress={this.addMessage}
onPress={this.onAddMessage}
/>
)}
</View>
@@ -99,7 +143,6 @@ const styles = StyleSheet.create({
flex: 1,
padding: 8,
backgroundColor: 'white',
alignItems: 'flex-end',
},
listView: {
flex: 1,

View File

@@ -4,7 +4,6 @@ import {
Platform,
StyleSheet,
Text,
View,
} from 'react-native';
import ListItem from '../../components/ListItem';

View File

@@ -1,9 +1,8 @@
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
View,
} from 'react-native';
export default class WelcomeText extends Component {
@@ -22,8 +21,8 @@ export default class WelcomeText extends Component {
file views/welcome/WelcomeText.android.js.
</Text>
<Text style={styles.instructions}>
Press Cmd+R to reload,{'\n'}
Cmd+D or shake for dev menu.
Double tap R on your keyboard to reload,{'\n'}
Shake or press menu button for dev menu.
</Text>
</View>
);

View File

@@ -1,9 +1,8 @@
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View
View,
} from 'react-native';
export default class WelcomeText extends Component {