diff --git a/Examples/Movies/SearchScreen.js b/Examples/Movies/SearchScreen.js index b845c03a829d18..f9ef67b7cd3a71 100644 --- a/Examples/Movies/SearchScreen.js +++ b/Examples/Movies/SearchScreen.js @@ -25,8 +25,6 @@ var TimerMixin = require('react-timer-mixin'); var MovieCell = require('./MovieCell'); var MovieScreen = require('./MovieScreen'); -var fetch = require('fetch'); - var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/'; var API_KEYS = ['7waqfqbprs7pajbz28mqf6vz', 'y4vwv8m33hed9ety83jmv52f']; diff --git a/docs/Tutorial.md b/docs/Tutorial.md index 7f7bc3a72791fa..bd6ff92defc7eb 100644 --- a/docs/Tutorial.md +++ b/docs/Tutorial.md @@ -11,7 +11,7 @@ next: videos This is a tutorial that aims to get you up to speed with writing iOS apps using React Native. If you want to learn what React Native is and why Facebook built it, check out this blog post: **[INSERT BLOG POST URL]**. -We assume you have experience writing websites with ReactJS. If not, you can learn about ReactJS [here](http://facebook.github.io/react/). +We assume you have experience writing websites with React. If not, you can learn about React [here](http://facebook.github.io/react/). ## Setup @@ -109,6 +109,10 @@ And lastly we need to apply this still to the Image component: Press cmd+R and the image should now render. +Screenshot: + +screenshot + ### Add some styling @@ -178,15 +182,13 @@ This is pretty straightforward if you've ever seen CSS before. Make the title la Go ahead and press cmd+R and you'll see the updated view. -### Fetching real data +Screenshot: -Fetching data from Rotten Tomatoes's API isn't really relevant to learning React Native so feel free to breeze through this section. +screenshot -Require the fetch module which is used to make an HTTP request to rotten tomatoes's API. +### Fetching real data -```javascript -var fetch = require('fetch'); -``` +Fetching data from Rotten Tomatoes's API isn't really relevant to learning React Native so feel free to breeze through this section. Add the following constants to the top of the file (typically below the requires) to create the REQUEST_URL used to request data with. @@ -203,7 +205,7 @@ Add some initial state to our application so that we can check this.state.movies ```javascript getInitialState: function() { return { - movies: null + movies: null, }; }, ``` @@ -272,6 +274,197 @@ Now modify the render function to render a loading view if we don't have any mov Now press cmd+R and you should see "Loading movies..." until the response comes back, then it will render the first movie it fetched from Rotten Tomatoes. +Screenshot: + +screenshot + ## ListView Let’s now modify this application to render all of this data in a ListView, rather than just the first movie. + +Why is a ListView better than just rendering all of these elements or putting them in a ScrollView? Despite React being fast, rendering a possibly infinite list of elements could be slow. ListView schedules rendering of views so that you only display the ones on screen and those already rendered but off screen are removed from the hierarchy. + +First thing's first, add the ListView require to the top of the file. + +```javascript +var { + AppRegistry, + Image, + ListView, + StyleSheet, + Text, + View, +} = React; +``` + +Now modify the render funtion so that once we have our data it renders a ListView of movies instead of a single movie. + +```javascript + render: function() { + if (!this.state.loaded) { + return this.renderLoadingView(); + } + + return ( + + ); + }, +``` + +What is this dataSource thing and why do we use it? This way we can very cheaply know which rows have changed between updates. + +You'll notice we added dataSource from this.state. The next step is to add an empty dataSource to getInitialState. Also, now that we're storing the data in dataSource, we should change this.state.movies to be this.state.loaded (boolean) so we aren't storing the data twice. + +```javascript + getInitialState: function() { + return { + dataSource: new ListView.DataSource({ + rowHasChanged: (row1, row2) => row1 !== row2, + }), + loaded: false, + }; + }, +``` + +And here's the modified this.setState in the response handler in fetchData: + +```javascript + fetchData: function() { + fetch(REQUEST_URL) + .then((response) => response.json()) + .then((responseData) => { + this.setState({ + dataSource: this.state.dataSource.cloneWithRows(responseData.movies), + loaded: true, + }); + }) + .done(); + }, +``` + +Screenshot: + +screenshot + + +### Final source code + +```javascript +/** + * Sample React Native App + * https://github.com/facebook/react-native + */ +'use strict'; + +var React = require('react-native'); +var { + AppRegistry, + Image, + ListView, + StyleSheet, + Text, + View, +} = React; + +var API_KEY = '7waqfqbprs7pajbz28mqf6vz'; +var API_URL = 'http://api.rottentomatoes.com/api/public/v1.0/lists/movies/in_theaters.json'; +var PAGE_SIZE = 25; +var PARAMS = '?apikey=' + API_KEY + '&page_limit=' + PAGE_SIZE; +var REQUEST_URL = API_URL + PARAMS; + +var SampleApp = React.createClass({ + getInitialState: function() { + return { + dataSource: new ListView.DataSource({ + rowHasChanged: (row1, row2) => row1 !== row2, + }), + loaded: false, + }; + }, + + componentDidMount: function() { + this.fetchData(); + }, + + fetchData: function() { + fetch(REQUEST_URL) + .then((response) => response.json()) + .then((responseData) => { + this.setState({ + dataSource: this.state.dataSource.cloneWithRows(responseData.movies), + loaded: true, + }); + }) + .done(); + }, + + render: function() { + if (!this.state.loaded) { + return this.renderLoadingView(); + } + + return ( + + ); + }, + + renderLoadingView: function() { + return ( + + + Loading movies... + + + ); + }, + + renderMovie: function(movie) { + return ( + + + + {movie.title} + {movie.year} + + + ); + }, +}); + +var styles = StyleSheet.create({ + container: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + rightContainer: { + flex: 1, + }, + title: { + fontSize: 20, + marginBottom: 8, + textAlign: 'center', + }, + year: { + textAlign: 'center', + }, + thumbnail: { + width: 53, + height: 81, + }, +}); + +AppRegistry.registerComponent('SampleApp', () => SampleApp); +``` + diff --git a/docs/images/TutorialFinal.png b/docs/images/TutorialFinal.png new file mode 100644 index 00000000000000..7f0ab5fda861f2 Binary files /dev/null and b/docs/images/TutorialFinal.png differ diff --git a/docs/images/TutorialMock.png b/docs/images/TutorialMock.png new file mode 100644 index 00000000000000..461a4ddfc84008 Binary files /dev/null and b/docs/images/TutorialMock.png differ diff --git a/docs/images/TutorialSingleFetched.png b/docs/images/TutorialSingleFetched.png new file mode 100644 index 00000000000000..3b223e52e0330b Binary files /dev/null and b/docs/images/TutorialSingleFetched.png differ diff --git a/docs/images/TutorialStyledMock.png b/docs/images/TutorialStyledMock.png new file mode 100644 index 00000000000000..ad097f3c2f312f Binary files /dev/null and b/docs/images/TutorialStyledMock.png differ