diff --git a/docs/nativemodulesios.html b/docs/nativemodulesios.html index b67ae553006..022ff69cf3c 100644 --- a/docs/nativemodulesios.html +++ b/docs/nativemodulesios.html @@ -25,7 +25,7 @@ CalendarManager.: '4 Privet Drive, Surrey', time: date.toTime(), description: '...' -})

NOTE: About array and map

React Native doesn't provide any guarantees about the types of values in these structures. Your native module might expect array of strings, but if JavaScript calls your method with an array that contains number and string you'll get NSArray with NSNumber and NSString. It's developer's responsibility to check array/map values types (see RCTConvert for helper methods).

Callbacks #

WARNING

This section is even more experimental than others, we don't have a set of best practices around callbacks yet.

Native module also supports a special kind of argument - callback. In most cases it is used to provide function call result to JavaScript.

- (void)findEvents:(RCTResponseSenderBlock)callback +})

NOTE: About array and map

React Native doesn't provide any guarantees about the types of values in these structures. Your native module might expect array of strings, but if JavaScript calls your method with an array that contains number and string you'll get NSArray with NSNumber and NSString. It's developer's responsibility to check array/map values types (see RCTConvert for helper methods).

Callbacks #

WARNING

This section is even more experimental than others, we don't have a set of best practices around callbacks yet.

Native module also supports a special kind of argument - callback. In most cases it is used to provide function call result to JavaScript.

- (void)findEvents:(RCTResponseSenderBlock)callback { RCT_EXPORT(); NSArray *events = ... @@ -36,7 +36,7 @@ CalendarManager.} else { this.setState({events: events}); } -})

Native module is supposed to invoke callback only once. It can, however, store the callback as an ivar and invoke it later. This pattern is often used to wrap iOS APIs that require delegate. See RCTAlertManager.

If you want to pass error-like object to JavaScript, use RCTMakeError from RCTUtils.h.

Implementing native module #

The native module should not have any assumptions about what thread it is being called on. React Native invokes native modules methods on a separate serial GCD queue, but this is an implementation detail and might change. If the native module needs to call main-thread-only iOS API, it should schedule the operation on the main queue:

- (void)addEventWithName:(NSString *)name callback:(RCTResponseSenderBlock)callback +})

Native module is supposed to invoke callback only once. It can, however, store the callback as an ivar and invoke it later. This pattern is often used to wrap iOS APIs that require delegate. See RCTAlertManager.

If you want to pass error-like object to JavaScript, use RCTMakeError from RCTUtils.h.

Implementing native module #

The native module should not have any assumptions about what thread it is being called on. React Native invokes native modules methods on a separate serial GCD queue, but this is an implementation detail and might change. If the native module needs to call main-thread-only iOS API, it should schedule the operation on the main queue:

- (void)addEventWithName:(NSString *)name callback:(RCTResponseSenderBlock)callback { RCT_EXPORT(addEvent); dispatch_async(dispatch_get_main_queue(), ^{ diff --git a/docs/tutorial.html b/docs/tutorial.html index 10e0bc341e9..026127c4c26 100644 --- a/docs/tutorial.html +++ b/docs/tutorial.html @@ -1,6 +1,7 @@ -React Native | A framework for building native apps using React

Tutorial

Preface #

This tutorial aims to get you up to speed with writing iOS apps using React Native.

We assume you have experience writing websites with React. If not, you can learn about it on the React website.

Setup #

React Native requires OSX, Xcode, Homebrew, node, npm, and watchman. Flow is optional.

After installing these dependencies there are two simple commands to get a React Native project all set up for development.

  1. npm install -g react-native-cli

    react-native-cli is a command line interface that does the rest of the set up. It’s installable via npm. This will install react-nativeas a command in your terminal. You only ever need to do this once.

  2. react-native init AwesomeProject

    This command fetches the React Native source code and dependencies and then creates a new Xcode project in AwesomeProject/AwesomeProject.xcodeproj.

Development #

You can now open this new project (AwesomeProject/AwesomeProject.xcodeproj) in Xcode and simply build and run it with cmd+R. Doing so will also start a node server which enables live code reloading. With this you can see your changes by pressing cmd+R in the simulator rather than recompiling in Xcode.

For this tutorial we'll be building a simple version of the Movies app that fetches 25 movies that are in theaters and displays them in a ListView.

Hello World #

react-native init will copy Examples/SampleProject to whatever you named your project, in this case AwesomeProject. This is a simple hello world app. You can edit index.ios.js to make changes to the app and then press cmd+R in the simulator to see the changes.

Mocking data #

Before we write the code to fetch actual Rotten Tomatoes data let's mock some data so we can get our hands dirty with React Native. At Facebook we typically declare constants at the top of JS files, just below the requires, but feel free to add the following constant wherever you like:

var MOCKED_MOVIES_DATA = [ +React Native | A framework for building native apps using React

Tutorial

Preface #

This tutorial aims to get you up to speed with writing iOS apps using React Native.

We assume you have experience writing websites with React. If not, you can learn about it on the React website.

Setup #

React Native requires OSX, Xcode, Homebrew, node, npm, and watchman. Flow is optional.

After installing these dependencies there are two simple commands to get a React Native project all set up for development.

  1. npm install -g react-native-cli

    react-native-cli is a command line interface that does the rest of the set up. It’s installable via npm. This will install react-nativeas a command in your terminal. You only ever need to do this once.

  2. react-native init AwesomeProject

    This command fetches the React Native source code and dependencies and then creates a new Xcode project in AwesomeProject/AwesomeProject.xcodeproj.

Development #

You can now open this new project (AwesomeProject/AwesomeProject.xcodeproj) in Xcode and simply build and run it with cmd+R. Doing so will also start a node server which enables live code reloading. With this you can see your changes by pressing cmd+R in the simulator rather than recompiling in Xcode.

For this tutorial we'll be building a simple version of the Movies app that fetches 25 movies that are in theaters and displays them in a ListView.

Hello World #

react-native init will copy Examples/SampleProject to whatever you named your project, in this case AwesomeProject. This is a simple hello world app. You can edit index.ios.js to make changes to the app and then press cmd+R in the simulator to see the changes.

Mocking data #

Before we write the code to fetch actual Rotten Tomatoes data let's mock some data so we can get our hands dirty with React Native. At Facebook we typically declare constants at the top of JS files, just below the requires, but feel free to add the following constant wherever you like. In index.ios.js:

var MOCKED_MOVIES_DATA = [ {title: 'Title', year: '2015', posters: {thumbnail: 'http://i.imgur.com/UePbdph.jpg'}}, -];

Render a movie #

We're going to render the title, year, and thumbnail for the movie. Since thumbnail is an Image component in React Native, add Image to the list of React requires below.

var { +];

Render a movie #

gr +We're going to render the title, year, and thumbnail for the movie. Since thumbnail is an Image component in React Native, add Image to the list of React requires below.

var { AppRegistry, Image, StyleSheet, @@ -20,7 +21,8 @@ flex: 1, justifyContent: 'center', alignItems: 'center', - backgroundColor: '#F5FCFF', + backgroundColor: 'white', + paddingTop: 20, }, thumbnail: { width: 53, @@ -56,10 +58,11 @@ flexDirection: 'row', justifyContent: 'center', alignItems: 'center', - backgroundColor: '#F5FCFF', - },

For layout we use FlexBox which has great documentation.

We simply added flexDirection: 'row' which means that children are layed out horizontally instead of vertically.

rightContainer: { + backgroundColor: 'white', + paddingTop: 20, + },

We use FlexBox for layout - see this great guide to learn more about it.

In the above code snippet, we simply added flexDirection: 'row' that will make children of our main container to be layed out horizontally instead of vertically.

Now add another style to the JS style object:

rightContainer: { flex: 1, - },

This means that the rightContainer takes up the remaining space in the parent container that isn't taken up by the Image. If this doesn't make sense, add a backgroundColor to rightContainer and then try removing the flex: 1. You'll see that this causes the container's size to be the minimum size that fits its children.

Styling the text is pretty straightforward:

title: { + },

This means that the rightContainer takes up the remaining space in the parent container that isn't taken up by the Image. If this doesn't make sense, add a backgroundColor to rightContainer and then try removing the flex: 1. You'll see that this causes the container's size to be the minimum size that fits its children.

Styling the text is pretty straightforward:

title: { fontSize: 20, marginBottom: 8, textAlign: 'center', @@ -74,13 +77,13 @@ 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;

Add some initial state to our application so that we can check this.state.movies === null to determine whether the movies data has been loaded or not. We can set this data when the response comes back with this.setState({movies: moviesData}). Add this code just above the render function inside our React class.

getInitialState: function() { +var REQUEST_URL = API_URL + PARAMS;

Add some initial state to our application so that we can check this.state.movies === null to determine whether the movies data has been loaded or not. We can set this data when the response comes back with this.setState({movies: moviesData}). Add this code just above the render function inside our React class.

getInitialState: function() { return { movies: null, }; - },

We want to send off the request after the component has finished loading. componentDidMount is a function on React components that React will call exactly once just after the component has been loaded.

componentDidMount: function() { + },

We want to send off the request after the component has finished loading. componentDidMount is a function of React components that React will call exactly once, just after the component has been loaded.

componentDidMount: function() { this.fetchData(); - },

Implement our fetchData function to actually make the request and handle the response. All you need to do is call this.setState({movies: data}) after resolving the promise chain because the way React works is that setState actually triggers a re-render and then the render function will notice that this.state.movies is no longer null. Note that we call done() at the end of the promise chain - always make sure to call done() or any errors thrown will get swallowed.

fetchData: function() { + },

Now add fetchData function used above to our main component. This method will be respondible for handling data fetching. All you need to do is call this.setState({movies: data}) after resolving the promise chain because the way React works is that setState actually triggers a re-render and then the render function will notice that this.state.movies is no longer null. Note that we call done() at the end of the promise chain - always make sure to call done() or any errors thrown will get swallowed.

fetchData: function() { fetch(REQUEST_URL) .then((response) => response.json()) .then((responseData) => { @@ -125,7 +128,7 @@
-

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 native view hierarchy.

First thing's first, add the ListView require to the top of the file.

var { +

ListView #

Let's now modify this application to render all of this data in a ListView component, rather than just rendering 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 native view hierarchy.

First thing's first: add the ListView require to the top of the file.

var { AppRegistry, Image, ListView, @@ -143,14 +146,14 @@ renderRow={this.renderMovie} /> ); - },

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.

getInitialState: function() { + },

The DataSource is an interfacte that ListView is using to determine which rows have changed over the course of updates.

You'll notice we used dataSource from this.state. The next step is to add an empty dataSource to the object returned by getInitialState. Also, now that we're storing the data in dataSource, we should not longer use this.state.movies to avoid storing data twice. We can use boolean property of the state (this.state.loaded) to tell whether data fetching has finished.

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:

fetchData: function() { + },

And here is the modified fetchData method that updates the state accordingly:

fetchData: function() { fetch(REQUEST_URL) .then((response) => response.json()) .then((responseData) => { @@ -164,7 +167,7 @@
-

There's still some work to be done to make it a fully functional app such as adding navigation, search, infinite scroll loading, etc. Check the Movies Example to see it all working.

Final source code #

/** +

There's still some work to be done to make it a fully functional app such as: adding navigation, search, infinite scroll loading, etc. Check the Movies Example to see it all working.

Final source code #

/** * Sample React Native App * https://github.com/facebook/react-native */ @@ -257,7 +260,8 @@ flexDirection: 'row', justifyContent: 'center', alignItems: 'center', - backgroundColor: '#F5FCFF', + backgroundColor: 'white', + paddingTop: 20, }, rightContainer: { flex: 1,