diff --git a/README.md b/README.md index a5ea201..d5d54de 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # React Native Manual (.mobi, .epub) -Current version of React Native in the docs: **0.25.1** +Current version of React Native in the docs: **0.26.0** Based on the repo diff --git a/epub.js b/epub.js index a7ad63b..697ea73 100644 --- a/epub.js +++ b/epub.js @@ -24,18 +24,38 @@ const Applause = require('applause'); var options = { patterns: [ { - match: //g, + match: //g, replacement: function () { let file = arguments[1]; return `![${file}](./versions/${version}/${file})`; } + }, + { + match: //g, + replacement: '' + }, + { + match: //g, // inline block + replacement: '' + }, + { + match: /(<|<\/)block.*>/g, + replacement: '' + }, + { + match: /!\[(.*)\]\((.*)\)/g, + replacement: function () { + let description = arguments[1]; + let file = arguments[2]; + return `![${description}](./versions/${version}/${file})`; + } } ] }; var applause = Applause.create(options); let tocMarkdown = []; -function handleImages(data) { +function replaceOptions(data) { let result = applause.replace(data); if (result.content) { return result.content; @@ -47,7 +67,7 @@ function writeMdString(item, callback) { const filename = `.tmp/${item.file}.md`; let data = `# ${item.title}\n\n`; data += fs.readFileSync(`versions/${version}/docs/${item.file}.md`); - data = handleImages(data); + data = replaceOptions(data); fs.appendFile(filename, data, function(err) { if (err) throw err; @@ -70,7 +90,7 @@ async.forEach(toc, writeMdString, function(err) { -o epub/react-native-manual.epub \ --epub-cover-image=epub/cover.jpg \ --epub-stylesheet=epub/epub.css \ - epub/title.txt \ + versions/${version}/title.txt \ ${tocMdString}`, function(err, stdout, stderr) { if (err) console.log(err); diff --git a/epub/title.txt b/versions/v0.25.1/title.txt similarity index 100% rename from epub/title.txt rename to versions/v0.25.1/title.txt diff --git a/versions/v0.26.0/docs/Accessibility.md b/versions/v0.26.0/docs/Accessibility.md new file mode 100644 index 0000000..0c5f110 --- /dev/null +++ b/versions/v0.26.0/docs/Accessibility.md @@ -0,0 +1,168 @@ +--- +id: accessibility +title: Accessibility +layout: docs +category: Guides +permalink: docs/accessibility.html +next: direct-manipulation +--- + +## Native App Accessibility (iOS and Android) +Both iOS and Android provide APIs for making apps accessible to people with disabilities. In addition, both platforms provide bundled assistive technologies, like the screen readers VoiceOver (iOS) and TalkBack (Android) for the visually impaired. Similarly, in React Native we have included APIs designed to provide developers with support for making apps more accessible. Take note, iOS and Android differ slightly in their approaches, and thus the React Native implementations may vary by platform. + +## Making Apps Accessible + +### Accessibility properties + +#### accessible (iOS, Android) + +When `true`, indicates that the view is an accessibility element. When a view is an accessibility element, it groups its children into a single selectable component. By default, all touchable elements are accessible. + +On Android, ‘accessible={true}’ property for a react-native View will be translated into native ‘focusable={true}’. + +```javascript + + text one + text two + +``` + +In the above example, we can't get accessibility focus separately on 'text one' and 'text two'. Instead we get focus on a parent view with 'accessible' property. + + + +#### accessibilityLabel (iOS, Android) + +When a view is marked as accessible, it is a good practice to set an accessibilityLabel on the view, so that people who use VoiceOver know what element they have selected. VoiceOver will read this string when a user selects the associated element. + +To use, set the `accessibilityLabel` property to a custom string on your View: + +```javascript + + + Press me! + + +``` + +In the above example, the `accessibilityLabel` on the TouchableOpacity element would default to "Press me!". The label is constructed by concatenating all Text node children separated by spaces. + +#### accessibilityTraits (iOS) + +Accessibility traits tell a person using VoiceOver what kind of element they have selected. Is this element a label? A button? A header? These questions are answered by `accessibilityTraits`. + +To use, set the `accessibilityTraits` property to one of (or an array of) accessibility trait strings: + +* **none** Used when the element has no traits. +* **button** Used when the element should be treated as a button. +* **link** Used when the element should be treated as a link. +* **header** Used when an element acts as a header for a content section (e.g. the title of a navigation bar). +* **search** Used when the text field element should also be treated as a search field. +* **image** Used when the element should be treated as an image. Can be combined with button or link, for example. +* **selected** Used when the element is selected. For example, a selected row in a table or a selected button within a segmented control. +* **plays** Used when the element plays its own sound when activated. +* **key** Used when the element acts as a keyboard key. +* **text** Used when the element should be treated as static text that cannot change. +* **summary** Used when an element can be used to provide a quick summary of current conditions in the app when the app first launches. For example, when Weather first launches, the element with today's weather conditions is marked with this trait. +* **disabled** Used when the control is not enabled and does not respond to user input. +* **frequentUpdates** Used when the element frequently updates its label or value, but too often to send notifications. Allows an accessibility client to poll for changes. A stopwatch would be an example. +* **startsMedia** Used when activating an element starts a media session (e.g. playing a movie, recording audio) that should not be interrupted by output from an assistive technology, like VoiceOver. +* **adjustable** Used when an element can be "adjusted" (e.g. a slider). +* **allowsDirectInteraction** Used when an element allows direct touch interaction for VoiceOver users (for example, a view representing a piano keyboard). +* **pageTurn** Informs VoiceOver that it should scroll to the next page when it finishes reading the contents of the element. + +#### onAccessibilityTap (iOS) + +Use this property to assign a custom function to be called when someone activates an accessible element by double tapping on it while it's selected. + +#### onMagicTap (iOS) + +Assign this property to a custom function which will be called when someone performs the "magic tap" gesture, which is a double-tap with two fingers. A magic tap function should perform the most relevant action a user could take on a component. In the Phone app on iPhone, a magic tap answers a phone call, or ends the current one. If the selected element does not have an `onMagicTap` function, the system will traverse up the view hierarchy until it finds a view that does. + +#### accessibilityComponentType (Android) + +In some cases, we also want to alert the end user of the type of selected component (i.e., that it is a “button”). If we were using native buttons, this would work automatically. Since we are using javascript, we need to provide a bit more context for TalkBack. To do so, you must specify the ‘accessibilityComponentType’ property for any UI component. For instances, we support ‘button’, ‘radiobutton_checked’ and ‘radiobutton_unchecked’ and so on. + +```javascript + + + Press me! + + +``` + +In the above example, the TouchableWithoutFeedback is being announced by TalkBack as a native Button. + +#### accessibilityLiveRegion (Android) + +When components dynamically change, we want TalkBack to alert the end user. This is made possible by the ‘accessibilityLiveRegion’ property. It can be set to ‘none’, ‘polite’ and ‘assertive’: + +* **none** Accessibility services should not announce changes to this view. +* **polite** Accessibility services should announce changes to this view. +* **assertive** Accessibility services should interrupt ongoing speech to immediately announce changes to this view. + +```javascript + + + Click me + + + + Clicked {this.state.count} times + +``` + +In the above example method _addOne changes the state.count variable. As soon as an end user clicks the TouchableWithoutFeedback, TalkBack reads text in the Text view because of its 'accessibilityLiveRegion=”polite”' property. + +#### importantForAccessibility (Android) + +In the case of two overlapping UI components with the same parent, default accessibility focus can have unpredictable behavior. The ‘importantForAccessibility’ property will resolve this by controlling if a view fires accessibility events and if it is reported to accessibility services. It can be set to ‘auto’, ‘yes’, ‘no’ and ‘no-hide-descendants’ (the last value will force accessibility services to ignore the component and all of its children). + +```javascript + + + First layout + + + Second layout + + +``` + +In the above example, the yellow layout and its descendants are completely invisible to TalkBack and all other accessibility services. So we can easily use overlapping views with the same parent without confusing TalkBack. + + + +### Sending Accessibility Events (Android) + +Sometimes it is useful to trigger an accessibility event on a UI component (i.e. when a custom view appears on a screen or a custom radio button has been selected). Native UIManager module exposes a method ‘sendAccessibilityEvent’ for this purpose. It takes two arguments: view tag and a type of an event. + +```javascript +_onPress: function() { + this.state.radioButton = this.state.radioButton === “radiobutton_checked” ? + “radiobutton_unchecked” : “radiobutton_checked”; + if (this.state.radioButton === “radiobutton_checked”) { + RCTUIManager.sendAccessibilityEvent( + ReactNative.findNodeHandle(this), + RCTUIManager.AccessibilityEventTypes.typeViewClicked); + } +} + + +``` + +In the above example we've created a custom radio button that now behaves like a native one. More specifically, TalkBack now correctly announces changes to the radio button selection. + + +## Testing VoiceOver Support (iOS) + +To enable VoiceOver, go to the Settings app on your iOS device. Tap General, then Accessibility. There you will find many tools that people use to use to make their devices more usable, such as bolder text, increased contrast, and VoiceOver. + +To enable VoiceOver, tap on VoiceOver under "Vision" and toggle the switch that appears at the top. + +At the very bottom of the Accessibility settings, there is an "Accessibility Shortcut". You can use this to toggle VoiceOver by triple clicking the Home button. diff --git a/versions/v0.26.0/docs/AndroidBuildingFromSource.md b/versions/v0.26.0/docs/AndroidBuildingFromSource.md new file mode 100644 index 0000000..caf44f0 --- /dev/null +++ b/versions/v0.26.0/docs/AndroidBuildingFromSource.md @@ -0,0 +1,134 @@ +--- +id: android-building-from-source +title: Building React Native from source +layout: docs +category: Guides (Android) +permalink: docs/android-building-from-source.html +next: activityindicatorios +--- + +You will need to build React Native from source if you want to work on a new feature/bug fix, try out the latest features which are not released yet, or maintain your own fork with patches that cannot be merged to the core. + +## Prerequisites + +Assuming you have the Android SDK installed, run `android` to open the Android SDK Manager. + +Make sure you have the following installed: + +1. Android SDK version 23 (compileSdkVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)) +2. SDK build tools version 23.0.1 (buildToolsVersion in [`build.gradle`](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle)) +3. Local Maven repository for Support Libraries (formerly `Android Support Repository`) >= 17 (for Android Support Library) +4. Android NDK (download links and installation instructions below) + +Point Gradle to your Android SDK: either have `$ANDROID_SDK` and `$ANDROID_NDK ` defined, or create a local.properties file in the root of your react-native checkout with the following contents: + +``` +sdk.dir=absolute_path_to_android_sdk +ndk.dir=absolute_path_to_android_ndk +``` + +Example: + +``` +sdk.dir=/Users/your_unix_name/android-sdk-macosx +ndk.dir=/Users/your_unix_name/android-ndk/android-ndk-r10e +``` + +### Download links for Android NDK + +1. Mac OS (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-darwin-x86_64.zip +2. Linux (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-linux-x86_64.zip +3. Windows (64-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86_64.zip +4. Windows (32-bit) - http://dl.google.com/android/repository/android-ndk-r10e-windows-x86.zip + +You can find further instructions on the [official page](http://developer.android.com/ndk/downloads/index.html). + +## Building the source + +#### 1. Installing the fork + +First, you need to install `react-native` from your fork. For example, to install the master branch from the official repo, run the following: + +```sh +npm install --save github:facebook/react-native#master +``` + +Alternatively, you can clone the repo to your `node_modules` directory and run `npm install` inside the cloned repo. + +#### 2. Adding gradle dependencies + +Add `gradle-download-task` as dependency in `android/build.gradle`: + +```gradle +... + dependencies { + classpath 'com.android.tools.build:gradle:1.3.1' + classpath 'de.undercouch:gradle-download-task:2.0.0' + + // NOTE: Do not place your application dependencies here; they belong + // in the individual module build.gradle files + } +... +``` + +#### 3. Adding the `:ReactAndroid` project + +Add the `:ReactAndroid` project in `android/settings.gradle`: + +```gradle +... +include ':ReactAndroid' + +project(':ReactAndroid').projectDir = new File( + rootProject.projectDir, '../node_modules/react-native/ReactAndroid') +... +``` + +Modify your `android/app/build.gradle` to use the `:ReactAndroid` project instead of the pre-compiled library, e.g. - replace `compile 'com.facebook.react:react-native:0.16.+'` with `compile project(':ReactAndroid')`: + +```gradle +... +dependencies { + compile fileTree(dir: 'libs', include: ['*.jar']) + compile 'com.android.support:appcompat-v7:23.0.1' + + compile project(':ReactAndroid') + + ... +} +... +``` + +#### 4. Making 3rd-party modules use your fork + +If you use 3rd-party React Native modules, you need to override their dependencies so that they don't bundle the pre-compiled library. Otherwise you'll get an error while compiling - `Error: more than one library with package name 'com.facebook.react'`. + +Modify your `android/app/build.gradle` and replace `compile project(':react-native-custom-module')` with: + +```gradle +compile(project(':react-native-custom-module')) { + exclude group: 'com.facebook.react', module: 'react-native' +} +``` + +## Building from Android Studio + +From the Welcome screen of Android Studio choose "Import project" and select the `android` folder of your app. + +You should be able to use the _Run_ button to run your app on a device. Android Studio won't start the packager automatically, you'll need to start it by running `npm start` on the command line. + +## Additional notes + +Building from source can take a long time, especially for the first build, as it needs to download ~200 MB of artifacts and compile the native code. Every time you update the `react-native` version from your repo, the build directory may get deleted, and all the files are re-downloaded. To avoid this, you might want to change your build directory path by editing the `~/.gradle/init.gradle ` file: + +```gradle +gradle.projectsLoaded { + rootProject.allprojects { + buildDir = "/path/to/build/directory/${rootProject.name}/${project.name}" + } +} +``` + +## Troubleshooting + +Gradle build fails in `ndk-build`. See the section about `local.properties` file above. diff --git a/versions/v0.26.0/docs/AndroidUIPerformance.md b/versions/v0.26.0/docs/AndroidUIPerformance.md new file mode 100644 index 0000000..3dc5153 --- /dev/null +++ b/versions/v0.26.0/docs/AndroidUIPerformance.md @@ -0,0 +1,154 @@ +--- +id: android-ui-performance +title: Profiling Android UI Performance +layout: docs +category: Guides (Android) +permalink: docs/android-ui-performance.html +next: android-building-from-source +--- + +We try our best to deliver buttery-smooth UI performance by default, but sometimes that just isn't possible. Remember, Android supports 10k+ different phones and is generalized to support software rendering: the framework architecture and need to generalize across many hardware targets unfortunately means you get less for free relative to iOS. But sometimes, there are things you can improve (and many times it's not native code's fault at all!). + +The first step for debugging this jank is to answer the fundamental question of where your time is being spent during each 16ms frame. For that, we'll be using a standard Android profiling tool called systrace. But first... + +> Make sure that JS dev mode is OFF! +> +> You should see `__DEV__ === false, development-level warning are OFF, performance optimizations are ON` in your application logs (which you can view using `adb logcat`) + +## Profiling with Systrace + +Systrace is a standard Android marker-based profiling tool (and is installed when you install the Android platform-tools package). Profiled code blocks are surrounded by markers start/end markers which are then visualized in a colorful chart format. Both the Android SDK and React Native framework provide standard markers that you can visualize. + +### Collecting a trace + +> NOTE: +> +> Systrace support was added in react-native `v0.15`. You will need to build with that version to collect a trace. + +First, connect a device that exhibits the stuttering you want to investigate to your computer via USB and get it to the point right before the navigation/animation you want to profile. Run systrace as follows + +``` +$ /platform-tools/systrace/systrace.py --time=10 -o trace.html sched gfx view -a +``` + +A quick breakdown of this command: + +- `time` is the length of time the trace will be collected in seconds +- `sched`, `gfx`, and `view` are the android SDK tags (collections of markers) we care about: `sched` gives you information about what's running on each core of your phone, `gfx` gives you graphics info such as frame boundaries, and `view` gives you information about measure, layout, and draw passes +- `-a ` enables app-specific markers, specifically the ones built into the React Native framework. `your_package_name` can be found in the `AndroidManifest.xml` of your app and looks like `com.example.app` + +Once the trace starts collecting, perform the animation or interaction you care about. At the end of the trace, systrace will give you a link to the trace which you can open in your browser. + +## Reading the trace + +After opening the trace in your browser (preferably Chrome), you should see something like this: + +![Example](img/SystraceExample.png) + +**HINT**: Use the WASD keys to strafe and zoom + +### Enable VSync highlighting + +The first thing you should do is highlight the 16ms frame boundaries if you haven't already done that. Check this checkbox at the top right of the screen: + +![Enable VSync Highlighting](img/SystraceHighlightVSync.png) + +You should see zebra stripes as in the screenshot above. If you don't, try profiling on a different device: Samsung has been known to have issues displaying vsyncs while the Nexus series is generally pretty reliable. + +### Find your process + +Scroll until you see (part of) the name of your package. In this case, I was profiling `com.facebook.adsmanager`, which shows up as `book.adsmanager` because of silly thread name limits in the kernel. + +On the left side, you'll see a set of threads which correspond to the timeline rows on the right. There are three/four threads we care about for our purposes: the UI thread (which has your package name or the name UI Thread), `mqt_js` and `mqt_native_modules`. If you're running on Android 5+, we also care about the Render Thread. + +### UI Thread + +This is where standard android measure/layout/draw happens. The thread name on the right will be your package name (in my case book.adsmanager) or UI Thread. The events that you see on this thread should look something like this and have to do with `Choreographer`, `traversals`, and `DispatchUI`: + +![UI Thread Example](img/SystraceUIThreadExample.png) + +### JS Thread + +This is where JS is executed. The thread name will be either `mqt_js` or `<...>` depending on how cooperative the kernel on your device is being. To identify it if it doesn't have a name, look for things like `JSCall`, `Bridge.executeJSCall`, etc: + +![JS Thread Example](img/SystraceJSThreadExample.png) + +### Native Modules Thread + +This is where native module calls (e.g. the `UIManager`) are executed. The thread name will be either `mqt_native_modules` or `<...>`. To identify it in the latter case, look for things like `NativeCall`, `callJavaModuleMethod`, and `onBatchComplete`: + +![Native Modules Thread Example](img/SystraceNativeModulesThreadExample.png) + +### Bonus: Render Thread + +If you're using Android L (5.0) and up, you will also have a render thread in your application. This thread generates the actual OpenGL commands used to draw your UI. The thread name will be either `RenderThread` or `<...>`. To identify it in the latter case, look for things like `DrawFrame` and `queueBuffer`: + +![Render Thread Example](img/SystraceRenderThreadExample.png) + +## Identifying a culprit + +A smooth animation should look something like the following: + +![Smooth Animation](img/SystraceWellBehaved.png) + +Each change in color is a frame -- remember that in order to display a frame, all our UI work needs to be done by the end of that 16ms period. Notice that no thread is working close to the frame boundary. An application rendering like this is rendering at 60FPS. + +If you noticed chop, however, you might see something like this: + +![Choppy Animation from JS](img/SystraceBadJS.png) + +Notice that the JS thread is executing basically all the time, and across frame boundaries! This app is not rendering at 60FPS. In this case, **the problem lies in JS**. + +You might also see something like this: + +![Choppy Animation from UI](img/SystraceBadUI.png) + +In this case, the UI and render threads are the ones that have work crossing frame boundaries. The UI that we're trying to render on each frame is requiring too much work to be done. In this case, **the problem lies in the native views being rendered**. + +At this point, you'll have some very helpful information to inform your next steps. + +## JS Issues + +If you identified a JS problem, look for clues in the specific JS that you're executing. In the scenario above, we see `RCTEventEmitter` being called multiple times per frame. Here's a zoom-in of the JS thread from the trace above: + +![Too much JS](img/SystraceBadJS2.png) + +This doesn't seem right. Why is it being called so often? Are they actually different events? The answers to these questions will probably depend on your product code. And many times, you'll want to look into [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate). + +> **TODO**: Add more tools for profiling JS + +## Native UI Issues + +If you identified a native UI problem, there are usually two scenarios: + +1. the UI you're trying to draw each frame involves to much work on the GPU, or +2. You're constructing new UI during the animation/interaction (e.g. loading in new content during a scroll). + +### Too much GPU work + +In the first scenario, you'll see a trace that has the UI thread and/or Render Thread looking like this: + +![Overloaded GPU](img/SystraceBadUI.png) + +Notice the long amount of time spent in `DrawFrame` that crosses frame boundaries. This is time spent waiting for the GPU to drain its command buffer from the previous frame. + +To mitigate this, you should: + +- investigate using `renderToHardwareTextureAndroid` for complex, static content that is being animated/transformed (e.g. the `Navigator` slide/alpha animations) +- make sure that you are **not** using `needsOffscreenAlphaCompositing`, which is disabled by default, as it greatly increases the per-frame load on the GPU in most cases. + +If these don't help and you want to dig deeper into what the GPU is actually doing, you can check out [Tracer for OpenGL ES](http://developer.android.com/tools/help/gltracer.html). + +### Creating new views on the UI thread + +In the second scenario, you'll see something more like this: + +![Creating Views](img/SystraceBadCreateUI.png) + +Notice that first the JS thread thinks for a bit, then you see some work done on the native modules thread, followed by an expensive traversal on the UI thread. + +There isn't an easy way to mitigate this unless you're able to postpone creating new UI until after the interaction, or you are able to simplify the UI you're creating. The react native team is working on a infrastructure level solution for this that will allow new UI to be created and configured off the main thread, allowing the interaction to continue smoothly. + +## Still stuck? + +If you are confused or stuck, please post ask on [Stack Overflow with the react-native tag](http://stackoverflow.com/tags/react-native). If you are unable to get a response there, or find an issue with a core component, please [File a Github issue](https://github.com/facebook/react-native/issues). diff --git a/versions/v0.26.0/docs/Animations.md b/versions/v0.26.0/docs/Animations.md new file mode 100644 index 0000000..eed529f --- /dev/null +++ b/versions/v0.26.0/docs/Animations.md @@ -0,0 +1,577 @@ +--- +id: animations +title: Animations +layout: docs +category: Guides +permalink: docs/animations.html +next: accessibility +--- + +Fluid, meaningful animations are essential to the mobile user experience. Like +everything in React Native, Animation APIs for React Native are currently under +development, but have started to coalesce around two complementary systems: +`LayoutAnimation` for animated global layout transactions, and `Animated` for +more granular and interactive control of specific values. + +### Animated ### + +The `Animated` library is designed to make it very easy to concisely express a +wide variety of interesting animation and interaction patterns in a very +performant way. `Animated` focuses on declarative relationships between inputs +and outputs, with configurable transforms in between, and simple `start`/`stop` +methods to control time-based animation execution. For example, a complete +component with a simple spring bounce on mount looks like this: + +```javascript +class Playground extends React.Component { + constructor(props: any) { + super(props); + this.state = { + bounceValue: new Animated.Value(0), + }; + } + render(): ReactElement { + return ( + + ); + } + componentDidMount() { + this.state.bounceValue.setValue(1.5); // Start large + Animated.spring( // Base: spring, decay, timing + this.state.bounceValue, // Animate `bounceValue` + { + toValue: 0.8, // Animate to smaller size + friction: 1, // Bouncier spring + } + ).start(); // Start the animation + } +} +``` + +`bounceValue` is initialized as part of `state` in the constructor, and mapped +to the scale transform on the image. Behind the scenes, the numeric value is +extracted and used to set scale. When the component mounts, the scale is set to +1.5 and then a spring animation is started on `bounceValue` which will update +all of its dependent mappings on each frame as the spring animates (in this +case, just the scale). This is done in an optimized way that is faster than +calling `setState` and re-rendering. Because the entire configuration is +declarative, we will be able to implement further optimizations that serialize +the configuration and runs the animation on a high-priority thread. + +#### Core API + +Most everything you need hangs directly off the `Animated` module. This +includes two value types, `Value` for single values and `ValueXY` for vectors, +three animation types, `spring`, `decay`, and `timing`, and three component +types, `View`, `Text`, and `Image`. You can make any other component animated with +`Animated.createAnimatedComponent`. + +The three animation types can be used to create almost any animation curve you +want because each can be customized: + +* `spring`: Simple single-spring physics model that matches [Origami](https://facebook.github.io/origami/). + * `friction`: Controls "bounciness"/overshoot. Default 7. + * `tension`: Controls speed. Default 40. +* `decay`: Starts with an initial velocity and gradually slows to a stop. + * `velocity`: Initial velocity. Required. + * `deceleration`: Rate of decay. Default 0.997. +* `timing`: Maps time range to easing value. + * `duration`: Length of animation (milliseconds). Default 500. + * `easing`: Easing function to define curve. See `Easing` module for several + predefined functions. iOS default is `Easing.inOut(Easing.ease)`. + * `delay`: Start the animation after delay (milliseconds). Default 0. + +Animations are started by calling `start`. `start` takes a completion callback +that will be called when the animation is done. If the animation is done +because it finished running normally, the completion callback will be invoked +with `{finished: true}`, but if the animation is done because `stop` was called +on it before it could finish (e.g. because it was interrupted by a gesture or +another animation), then it will receive `{finished: false}`. + +#### Composing Animations + +Animations can also be composed with `parallel`, `sequence`, `stagger`, and +`delay`, each of which simply take an array of animations to execute and +automatically calls start/stop as appropriate. For example: + +```javascript +Animated.sequence([ // spring to start and twirl after decay finishes + Animated.decay(position, { // coast to a stop + velocity: {x: gestureState.vx, y: gestureState.vy}, // velocity from gesture release + deceleration: 0.997, + }), + Animated.parallel([ // after decay, in parallel: + Animated.spring(position, { + toValue: {x: 0, y: 0} // return to start + }), + Animated.timing(twirl, { // and twirl + toValue: 360, + }), + ]), +]).start(); // start the sequence group +``` + +By default, if one animation is stopped or interrupted, then all other +animations in the group are also stopped. Parallel has a `stopTogether` option +that can be set to `false` to disable this. + +#### Interpolation + +Another powerful part of the `Animated` API is the `interpolate` function. It +allows input ranges to map to different output ranges. For example, a simple +mapping to convert a 0-1 range to a 0-100 range would be + +```javascript +value.interpolate({ + inputRange: [0, 1], + outputRange: [0, 100], +}); +``` + +`interpolate` supports multiple range segments as well, which is handy for +defining dead zones and other handy tricks. For example, to get an negation +relationship at -300 that goes to 0 at -100, then back up to 1 at 0, and then +back down to zero at 100 followed by a dead-zone that remains at 0 for +everything beyond that, you could do: + +```javascript +value.interpolate({ + inputRange: [-300, -100, 0, 100, 101], + outputRange: [300, 0, 1, 0, 0], +}); +``` + +Which would map like so: + +Input | Output +------|------- + -400| 450 + -300| 300 + -200| 150 + -100| 0 + -50| 0.5 + 0| 1 + 50| 0.5 + 100| 0 + 101| 0 + 200| 0 + +`interpolation` also supports arbitrary easing functions, many of which are +already implemented in the +[`Easing`](https://github.com/facebook/react-native/blob/master/Libraries/Animation/Animated/Easing.js) +class including quadratic, exponential, and bezier curves as well as functions +like step and bounce. `interpolation` also has configurable behavior for +extrapolating the `outputRange`. You can set the extrapolation by setting the `extrapolate`, +`extrapolateLeft` or `extrapolateRight` options. The default value is +`extend` but you can use `clamp` to prevent the output value from exceeding +`outputRange`. + +#### Tracking Dynamic Values + +Animated values can also track other values. Just set the `toValue` of an +animation to another animated value instead of a plain number, for example with +spring physics for an interaction like "Chat Heads", or via `timing` with +`duration: 0` for rigid/instant tracking. They can also be composed with +interpolations: + +```javascript +Animated.spring(follower, {toValue: leader}).start(); +Animated.timing(opacity, { + toValue: pan.x.interpolate({ + inputRange: [0, 300], + outputRange: [1, 0], + }), +}).start(); +``` + +`ValueXY` is a handy way to deal with 2D interactions, such as panning/dragging. +It is a simple wrapper that basically just contains two `Animated.Value` +instances and some helper functions that call through to them, making `ValueXY` +a drop-in replacement for `Value` in many cases. For example, in the code +snippet above, `leader` and `follower` could both be of type `ValueXY` and the x +and y values will both track as you would expect. + +#### Input Events + +`Animated.event` is the input side of the Animated API, allowing gestures and +other events to map directly to animated values. This is done with a structured +map syntax so that values can be extracted from complex event objects. The +first level is an array to allow mapping across multiple args, and that array +contains nested objects. In the example, you can see that `scrollX` maps to +`event.nativeEvent.contentOffset.x` (`event` is normally the first arg to the +handler), and `pan.x` and `pan.y` map to `gestureState.dx` and `gestureState.dy`, +respectively (`gestureState` is the second arg passed to the `PanResponder` handler). + +```javascript +onScroll={Animated.event( + // scrollX = e.nativeEvent.contentOffset.x + [{nativeEvent: {contentOffset: {x: scrollX}}}] +)} +onPanResponderMove={Animated.event([ + null, // ignore the native event + // extract dx and dy from gestureState + // like 'pan.x = gestureState.dx, pan.y = gestureState.dy' + {dx: pan.x, dy: pan.y} +]); +``` + +#### Responding to the Current Animation Value + +You may notice that there is no obvious way to read the current value while +animating - this is because the value may only be known in the native runtime +due to optimizations. If you need to run JavaScript in response to the current +value, there are two approaches: + +- `spring.stopAnimation(callback)` will stop the animation and invoke `callback` +with the final value - this is useful when making gesture transitions. +- `spring.addListener(callback)` will invoke `callback` asynchronously while the +animation is running, providing a recent value. This is useful for triggering +state changes, for example snapping a bobble to a new option as the user drags +it closer, because these larger state changes are less sensitive to a few frames +of lag compared to continuous gestures like panning which need to run at 60fps. + +#### Future Work + +As previously mentioned, we're planning on optimizing Animated under the hood to +make it even more performant. We would also like to experiment with more +declarative and higher level gestures and triggers, such as horizontal vs. +vertical panning. + +The above API gives a powerful tool for expressing all sorts of animations in a +concise, robust, and performant way. Check out more example code in +[UIExplorer/AnimationExample](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/AnimatedGratuitousApp). Of course there may still be times where `Animated` +doesn't support what you need, and the following sections cover other animation +systems. + +### LayoutAnimation + +`LayoutAnimation` allows you to globally configure `create` and `update` +animations that will be used for all views in the next render/layout cycle. +This is useful for doing flexbox layout updates without bothering to measure or +calculate specific properties in order to animate them directly, and is +especially useful when layout changes may affect ancestors, for example a "see +more" expansion that also increases the size of the parent and pushes down the +row below which would otherwise require explicit coordination between the +components in order to animate them all in sync. + +Note that although `LayoutAnimation` is very powerful and can be quite useful, +it provides much less control than `Animated` and other animation libraries, so +you may need to use another approach if you can't get `LayoutAnimation` to do +what you want. + +Note that in order to get this to work on **Android** you need to set the following flags via `UIManager`: + +```javascript +UIManager.setLayoutAnimationEnabledExperimental && UIManager.setLayoutAnimationEnabledExperimental(true); +``` + +![](img/LayoutAnimationExample.gif) + +```javascript +class App extends React.Component { + constructor(props) { + super(props); + this.state = { w: 100, h: 100 }; + this._onPress = this._onPress.bind(this); + } + + componentWillMount() { + // Animate creation + LayoutAnimation.spring(); + }, + + _onPress() { + // Animate the update + LayoutAnimation.spring(); + this.setState({w: this.state.w + 15, h: this.state.h + 15}) + } + + render() { + return ( + + + + + Press me! + + + + ); + } +}; +``` +[Run this example](https://rnplay.org/apps/uaQrGQ) + +This example uses a preset value, you can customize the animations as +you need, see [LayoutAnimation.js](https://github.com/facebook/react-native/blob/master/Libraries/LayoutAnimation/LayoutAnimation.js) +for more information. + +### requestAnimationFrame + +`requestAnimationFrame` is a polyfill from the browser that you might be +familiar with. It accepts a function as its only argument and calls that +function before the next repaint. It is an essential building block for +animations that underlies all of the JavaScript-based animation APIs. In +general, you shouldn't need to call this yourself - the animation APIs will +manage frame updates for you. + +### react-tween-state (Not recommended - use [Animated](#animated) instead) + +[react-tween-state](https://github.com/chenglou/react-tween-state) is a +minimal library that does exactly what its name suggests: it *tweens* a +value in a component's state, starting at a **from** value and ending at +a **to** value. This means that it generates the values in between those +two values, and it sets the state on every `requestAnimationFrame` with +the intermediary value. + +> Tweening definition from [Wikipedia](https://en.wikipedia.org/wiki/Inbetweening) +> +> "... tweening is the process of generating intermediate frames between two +> images to give the appearance that the first image evolves smoothly +> into the second image. [Tweens] are the drawings between the key +> frames which help to create the illusion of motion." + +The most obvious way to animate from one value to another is linearly: +you subtract the end value from the start value and divide the result by +the number of frames over which the animation occurs, and then add that +value to the current value on each frame until the end value is reached. +Linear easing often looks awkward and unnatural, so react-tween-state +provides a selection of popular [easing functions](http://easings.net/) +that can be applied to make your animations more pleasing. + +This library does not ship with React Native - in order to use it on +your project, you will need to install it with `npm i react-tween-state +--save` from your project directory. + +```javascript +import tweenState from 'react-tween-state'; +import reactMixin from 'react-mixin'; // https://github.com/brigand/react-mixin + +class App extends React.Component { + constructor(props) { + super(props); + this.state = { opacity: 1 }; + this._animateOpacity = this._animateOpacity.bind(this); + } + + _animateOpacity() { + this.tweenState('opacity', { + easing: tweenState.easingTypes.easeOutQuint, + duration: 1000, + endValue: this.state.opacity === 0.2 ? 1 : 0.2, + }); + } + + render() { + return ( + + + this._box = component} + style={{width: 200, height: 200, backgroundColor: 'red', + opacity: this.getTweeningValue('opacity')}} /> + + + ) + } +} + +reactMixin.onClass(App, tweenState.Mixin); +``` +[Run this example](https://rnplay.org/apps/4FUQ-A) + +![](img/TweenState.gif) + +Here we animated the opacity, but as you might guess, we can animate any +numeric value. Read more about react-tween-state in its +[README](https://github.com/chenglou/react-tween-state). + +### Rebound (Not recommended - use [Animated](docs/animation.html) instead) + +[Rebound.js](https://github.com/facebook/rebound-js) is a JavaScript port of +[Rebound for Android](https://github.com/facebook/rebound). It is +similar in concept to react-tween-state: you have an initial value and +set an end value, then Rebound generates intermediate values that you can +use for your animation. Rebound is modeled after spring physics; we +don't provide a duration when animating with springs, it is +calculated for us depending on the spring tension, friction, current +value and end value. Rebound [is used +internally](https://github.com/facebook/react-native/search?utf8=%E2%9C%93&q=rebound) +by React Native on `Navigator` and `WarningBox`. + +![](img/ReboundImage.gif) + +Notice that Rebound animations can be interrupted - if you release in +the middle of a press, it will animate back from the current state to +the original value. + +```javascript +import rebound from 'rebound'; + +class App extends React.Component { + constructor(props) { + super(props); + this._onPressIn = this._onPressIn.bind(this); + this._onPressOut = this._onPressOut.bind(this); + } + // First we initialize the spring and add a listener, which calls + // setState whenever it updates + componentWillMount() { + // Initialize the spring that will drive animations + this.springSystem = new rebound.SpringSystem(); + this._scrollSpring = this.springSystem.createSpring(); + var springConfig = this._scrollSpring.getSpringConfig(); + springConfig.tension = 230; + springConfig.friction = 10; + + this._scrollSpring.addListener({ + onSpringUpdate: () => { + this.setState({scale: this._scrollSpring.getCurrentValue()}); + }, + }); + + // Initialize the spring value at 1 + this._scrollSpring.setCurrentValue(1); + } + + _onPressIn() { + this._scrollSpring.setEndValue(0.5); + } + + _onPressOut() { + this._scrollSpring.setEndValue(1); + } + + render() { + var imageStyle = { + width: 250, + height: 200, + transform: [{scaleX: this.state.scale}, {scaleY: this.state.scale}], + }; + + var imageUri = "img/ReboundExample.png"; + + return ( + + + + + + ); + } +} +``` +[Run this example](https://rnplay.org/apps/NNI5eA) + +You can also clamp the spring values so that they don't overshoot and +oscillate around the end value. In the above example, we would add +`this._scrollSpring.setOvershootClampingEnabled(true)` to change this. +See the below gif for an example of where in your interface you might +use this. + +![](img/Rebound.gif) Screenshot from +[react-native-scrollable-tab-view](https://github.com/brentvatne/react-native-scrollable-tab-view). +You can run a similar example [here](https://rnplay.org/apps/qHU_5w). + +#### A sidenote about setNativeProps + +As mentioned [in the Direction Manipulation section](docs/direct-manipulation.html), +`setNativeProps` allows us to modify properties of native-backed +components (components that are actually backed by native views, unlike +composite components) directly, without having to `setState` and +re-render the component hierarchy. + +We could use this in the Rebound example to update the scale - this +might be helpful if the component that we are updating is deeply nested +and hasn't been optimized with `shouldComponentUpdate`. + +```javascript +// Back inside of the App component, replace the scrollSpring listener +// in componentWillMount with this: +this._scrollSpring.addListener({ + onSpringUpdate: () => { + if (!this._photo) { return } + var v = this._scrollSpring.getCurrentValue(); + var newProps = {style: {transform: [{scaleX: v}, {scaleY: v}]}}; + this._photo.setNativeProps(newProps); + }, +}); + +// Lastly, we update the render function to no longer pass in the +// transform via style (avoid clashes when re-rendering) and to set the +// photo ref +render() { + return ( + + + this._photo = component} + source={{uri: "img/ReboundExample.png"}} + style={{width: 250, height: 200}} /> + + + ); +} +``` +[Run this example](https://rnplay.org/apps/fUqjAg) + +It would not make sense to use `setNativeProps` with react-tween-state +because the updated tween values are set on the state automatically by +the library - Rebound on the other hand gives us an updated value for +each frame with the `onSpringUpdate` function. + +If you find your animations with dropping frames (performing below 60 +frames per second), look into using `setNativeProps` or +`shouldComponentUpdate` to optimize them. You may also want to defer any +computationally intensive work until after animations are complete, +using the +[InteractionManager](docs/interactionmanager.html). You +can monitor the frame rate by using the In-App Developer Menu "FPS +Monitor" tool. + +### Navigator Scene Transitions + +As mentioned in the [Navigator +Comparison](docs/navigator-comparison.html#content), +`Navigator` is implemented in JavaScript and `NavigatorIOS` is a wrapper +around native functionality provided by `UINavigationController`, so +these scene transitions apply only to `Navigator`. In order to re-create +the various animations provided by `UINavigationController` and also +make them customizable, React Native exposes a +[NavigatorSceneConfigs](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js) API which is then handed over to the [Navigator](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/Navigator.js) `configureScene` prop. + +```javascript +import { Dimensions } from 'react-native'; +var SCREEN_WIDTH = Dimensions.get('window').width; +var BaseConfig = Navigator.SceneConfigs.FloatFromRight; + +var CustomLeftToRightGesture = Object.assign({}, BaseConfig.gestures.pop, { + // Make it snap back really quickly after canceling pop + snapVelocity: 8, + + // Make it so we can drag anywhere on the screen + edgeHitWidth: SCREEN_WIDTH, +}); + +var CustomSceneConfig = Object.assign({}, BaseConfig, { + // A very tightly wound spring will make this transition fast + springTension: 100, + springFriction: 1, + + // Use our custom gesture defined above + gestures: { + pop: CustomLeftToRightGesture, + } +}); +``` +[Run this example](https://rnplay.org/apps/HPy6UA) + +For further information about customizing scene transitions, [read the +source](https://github.com/facebook/react-native/blob/master/Libraries/CustomComponents/Navigator/NavigatorSceneConfigs.js). diff --git a/versions/v0.26.0/docs/Colors.md b/versions/v0.26.0/docs/Colors.md new file mode 100644 index 0000000..aba2690 --- /dev/null +++ b/versions/v0.26.0/docs/Colors.md @@ -0,0 +1,173 @@ +--- +id: colors +title: Colors +layout: docs +category: Polyfills +permalink: docs/colors.html +--- + +The following formats are supported: + + - `'#f0f'` (#rgb) + - `'#f0fc'` (#rgba) + - `'#ff00ff'` (#rrggbb) + - `'#ff00ff00'` (#rrggbbaa) + - `'rgb(255, 255, 255)'` + - `'rgba(255, 255, 255, 1.0)'` + - `'hsl(360, 100%, 100%)'` + - `'hsla(360, 100%, 100%, 1.0)'` + - `'transparent'` + - `'red'` + - `0xff00ff00` (0xrrggbbaa) + + +For the named colors, React Native follows the [CSS3 specification](http://www.w3.org/TR/css3-color/#svg-color): + +- aliceblue (#f0f8ff) +- antiquewhite (#faebd7) +- aqua (#00ffff) +- aquamarine (#7fffd4) +- azure (#f0ffff) +- beige (#f5f5dc) +- bisque (#ffe4c4) +- black (#000000) +- blanchedalmond (#ffebcd) +- blue (#0000ff) +- blueviolet (#8a2be2) +- brown (#a52a2a) +- burlywood (#deb887) +- cadetblue (#5f9ea0) +- chartreuse (#7fff00) +- chocolate (#d2691e) +- coral (#ff7f50) +- cornflowerblue (#6495ed) +- cornsilk (#fff8dc) +- crimson (#dc143c) +- cyan (#00ffff) +- darkblue (#00008b) +- darkcyan (#008b8b) +- darkgoldenrod (#b8860b) +- darkgray (#a9a9a9) +- darkgreen (#006400) +- darkgrey (#a9a9a9) +- darkkhaki (#bdb76b) +- darkmagenta (#8b008b) +- darkolivegreen (#556b2f) +- darkorange (#ff8c00) +- darkorchid (#9932cc) +- darkred (#8b0000) +- darksalmon (#e9967a) +- darkseagreen (#8fbc8f) +- darkslateblue (#483d8b) +- darkslategray (#2f4f4f) +- darkslategrey (#2f4f4f) +- darkturquoise (#00ced1) +- darkviolet (#9400d3) +- deeppink (#ff1493) +- deepskyblue (#00bfff) +- dimgray (#696969) +- dimgrey (#696969) +- dodgerblue (#1e90ff) +- firebrick (#b22222) +- floralwhite (#fffaf0) +- forestgreen (#228b22) +- fuchsia (#ff00ff) +- gainsboro (#dcdcdc) +- ghostwhite (#f8f8ff) +- gold (#ffd700) +- goldenrod (#daa520) +- gray (#808080) +- green (#008000) +- greenyellow (#adff2f) +- grey (#808080) +- honeydew (#f0fff0) +- hotpink (#ff69b4) +- indianred (#cd5c5c) +- indigo (#4b0082) +- ivory (#fffff0) +- khaki (#f0e68c) +- lavender (#e6e6fa) +- lavenderblush (#fff0f5) +- lawngreen (#7cfc00) +- lemonchiffon (#fffacd) +- lightblue (#add8e6) +- lightcoral (#f08080) +- lightcyan (#e0ffff) +- lightgoldenrodyellow (#fafad2) +- lightgray (#d3d3d3) +- lightgreen (#90ee90) +- lightgrey (#d3d3d3) +- lightpink (#ffb6c1) +- lightsalmon (#ffa07a) +- lightseagreen (#20b2aa) +- lightskyblue (#87cefa) +- lightslategray (#778899) +- lightslategrey (#778899) +- lightsteelblue (#b0c4de) +- lightyellow (#ffffe0) +- lime (#00ff00) +- limegreen (#32cd32) +- linen (#faf0e6) +- magenta (#ff00ff) +- maroon (#800000) +- mediumaquamarine (#66cdaa) +- mediumblue (#0000cd) +- mediumorchid (#ba55d3) +- mediumpurple (#9370db) +- mediumseagreen (#3cb371) +- mediumslateblue (#7b68ee) +- mediumspringgreen (#00fa9a) +- mediumturquoise (#48d1cc) +- mediumvioletred (#c71585) +- midnightblue (#191970) +- mintcream (#f5fffa) +- mistyrose (#ffe4e1) +- moccasin (#ffe4b5) +- navajowhite (#ffdead) +- navy (#000080) +- oldlace (#fdf5e6) +- olive (#808000) +- olivedrab (#6b8e23) +- orange (#ffa500) +- orangered (#ff4500) +- orchid (#da70d6) +- palegoldenrod (#eee8aa) +- palegreen (#98fb98) +- paleturquoise (#afeeee) +- palevioletred (#db7093) +- papayawhip (#ffefd5) +- peachpuff (#ffdab9) +- peru (#cd853f) +- pink (#ffc0cb) +- plum (#dda0dd) +- powderblue (#b0e0e6) +- purple (#800080) +- rebeccapurple (#663399) +- red (#ff0000) +- rosybrown (#bc8f8f) +- royalblue (#4169e1) +- saddlebrown (#8b4513) +- salmon (#fa8072) +- sandybrown (#f4a460) +- seagreen (#2e8b57) +- seashell (#fff5ee) +- sienna (#a0522d) +- silver (#c0c0c0) +- skyblue (#87ceeb) +- slateblue (#6a5acd) +- slategray (#708090) +- slategrey (#708090) +- snow (#fffafa) +- springgreen (#00ff7f) +- steelblue (#4682b4) +- tan (#d2b48c) +- teal (#008080) +- thistle (#d8bfd8) +- tomato (#ff6347) +- turquoise (#40e0d0) +- violet (#ee82ee) +- wheat (#f5deb3) +- white (#ffffff) +- whitesmoke (#f5f5f5) +- yellow (#ffff00) +- yellowgreen (#9acd32) diff --git a/versions/v0.26.0/docs/CommunicationIOS.md b/versions/v0.26.0/docs/CommunicationIOS.md new file mode 100644 index 0000000..1e11156 --- /dev/null +++ b/versions/v0.26.0/docs/CommunicationIOS.md @@ -0,0 +1,219 @@ +--- +id: communication-ios +title: Communication between native and React Native +layout: docs +category: Guides (iOS) +permalink: docs/communication-ios.html +next: native-modules-android +--- + +In [Integrating with Existing Apps guide](docs/embedded-app-ios.html) and [Native UI Components guide](docs/native-components-ios.html) we learn how to embed React Native in a native component and vice versa. When we mix native and React Native components, we'll eventually find a need to communicate between these two worlds. Some ways to achieve that have been already mentioned in other guides. This article summarizes available techniques. + +## Introduction + +React Native is inspired by React, so the basic idea of the information flow is similar. The flow in React is one-directional. We maintain a hierarchy of components, in which each component depends only on its parent and own internal state. We do this with properties: data is passed from a parent to its children in a top-down manner. If we have an ancestor component that rely on the state of its descendant, the recommended solution would be to pass down a callback that would be used by the descendant to update the ancestor. + +The same concept applies to React Native. As long as we are building our application purely within the framework, we can drive our app with properties and callbacks. But, when we mix React Native and native components, we need some special, cross-language mechanisms that would allow us to pass information between them. + +## Properties + +Properties are the simplest way of cross-component communication. So we need a way to pass properties both from native to React Native, and from React Native to native. + +### Passing properties from native to React Native + +In order to embed a React Native view in a native component, we use `RCTRootView`. `RCTRootView` is a `UIView` that holds a React Native app. It also provides an interface between native side and the hosted app. + +`RCTRootView` has an initializer that allows you to pass arbitrary properties down to the React Native app. The `initialProperties` parameter has to be an instance of `NSDictionary`. The dictionary is internally converted into a JSON object that the top-level JS component can reference. + +``` +NSArray *imageList = @[@"http://foo.com/bar1.png", + @"http://foo.com/bar2.png"]; + +NSDictionary *props = @{@"images" : imageList}; + +RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge + moduleName:@"ImageBrowserApp" + initialProperties:props]; +``` + +``` +'use strict'; + +import React from 'react'; +import { + AppRegistry, + View, + Image +} from 'react-native'; + +class ImageBrowserApp extends React.Component { + renderImage(imgURI) { + return ( + + ); + } + render() { + return ( + + {this.props.images.map(this.renderImage)} + + ); + } +} + +AppRegistry.registerComponent('ImageBrowserApp', () => ImageBrowserApp); +``` + +`RCTRootView` also provides a read-write property `appProperties`. After `appProperties` is set, the React Native app is re-rendered with new properties. The update is only performed when the new updated properties differ from the previous ones. + +``` +NSArray *imageList = @[@"http://foo.com/bar3.png", + @"http://foo.com/bar4.png"]; + +rootView.appProperties = @{@"images" : imageList}; +``` + +It is fine to update properties anytime. However, updates have to be performed on the main thread. You use the getter on any thread. + +There is no way to update only a few properties at a time. We suggest that you build it into your own wrapper instead. + +> ***Note:*** +> Currently, JS functions `componentWillReceiveProps` and `componentWillUpdateProps` of the top level RN component will not be called after a prop update. However, you can access the new props in `componentWillMount` function. + +### Passing properties from React Native to native +The problem exposing properties of native components is covered in detail in [this article](docs/native-components-ios.html#properties). In short, export properties with `RCT_CUSTOM_VIEW_PROPERTY` macro in your custom native component, then just use them in React Native as if the component was an ordinary React Native component. + +### Limits of properties + +The main drawback of cross-language properties is that they do not support callbacks, which would allow us to handle bottom-up data bindings. Imagine you have a small RN view that you want to be removed from the native parent view as a result of a JS action. There is no way to do that with props, as the information would need to go bottom-up. + +Although we have a flavor of cross-language callbacks ([described here](docs/native-modules-ios.html#callbacks)), these callbacks are not always the thing we need. The main problem is that they are not intended to be passed as properties. Rather, this mechanism allows us to trigger a native action from JS, and handle the result of that action in JS. + +## Other ways of cross-language interaction (events and native modules) + +As stated in the previous chapter, using properties comes with some limitations. Sometimes properties are not enough to drive the logic of our app and we need a solution that gives more flexibility. This chapter covers other communication techniques available in React Native. They can be used for internal communication (between JS and native layers in RN) as well as for external communication (between RN and the 'pure native' part of your app). + +React Native enables you to perform cross-language function calls. You can execute custom native code from JS and vice versa. Unfortunately, depending on the side we are working on, we achieve the same goal in different ways. For native - we use events mechanism to schedule an execution of a handler function in JS, while for React Native we directly call methods exported by native modules. + +### Calling React Native functions from native (events) + +Events are described in detail in [this article](docs/native-components-ios.html#events). Note that using events gives us no guarantees about execution time, as the event is handled on a separate thread. + +Events are powerful, because they allow us to change React Native components without needing a reference to them. However, there are some pitfalls that you can fall into while using them: + +* As events can be sent from anywhere, they can introduce spaghetti-style dependencies into your project. +* Events share namespace, which means that you may encounter some name collisions. Collisions will not be detected statically, what makes them hard to debug. +* If you use several instances of the same React Native component and you want to distinguish them from the perspective of your event, you'll likely need to introduce some kind of identifiers and pass them along with events (you can use the native view's `reactTag` as an identifier). + +The common pattern we use when embedding native in React Native is to make the native component's RCTViewManager a delegate for the views, sending events back to JavaScript via the bridge. This keeps related event calls in one place. + +### Calling native functions from React Native (native modules) + +Native modules are Objective-C classes that are available in JS. Typically one instance of each module is created per JS bridge. They can export arbitrary functions and constants to React Native. They have been covered in detail in [this article](docs/native-modules-ios.html#content). + +The fact that native modules are singletons limits the mechanism in context of embedding. Let's say we have a React Native component embedded in a native view and we want to update the native, parent view. Using the native module mechanism, we would export a function that not only takes expected arguments, but also an identifier of the parent native view. The identifier would be used to retrieve a reference to the parent view to update. That said, we would need to keep a mapping from identifiers to native views in the module. + +Although this solution is complex, it is used in `RCTUIManager`, which is an internal React Native class that manages all React Native views. + +Native modules can also be used to expose existing native libraries to JS. [Geolocation library](https://github.com/facebook/react-native/tree/master/Libraries/Geolocation) is a living example of the idea. + +> ***Warning***: +> All native modules share the same namespace. Watch out for name collisions when creating new ones. + +## Layout computation flow + +When integrating native and React Native, we also need a way to consolidate two different layout systems. This section covers common layouting problems and provides a brief description of mechanisms that are intended to address them. + +### Layout of a native component embedded in React Native + +This case is covered in [this article](docs/native-components-ios.html#styles). Basically, as all our native react views are subclasses of `UIView`, most style and size attributes will work like you would expect out of the box. + +### Layout of a React Native component embedded in native + +#### React Native content with fixed size +The simplest scenario is when we have a React Native app with a fixed size, which is known to the native side. In particular, a full-screen React Native view falls into this case. If we want a smaller root view, we can explicitly set RCTRootView's frame. + +For instance, to make an RN app 200 (logical) pixels high, and the hosting view's width wide, we could do: + +``` +// SomeViewController.m + +- (void)viewDidLoad +{ + [...] + RCTRootView *rootView = [[RCTRootView alloc] initWithBridge:bridge + moduleName:appName + initialProperties:props]; + rootView.frame = CGMakeRect(0, 0, self.view.width, 200); + [self.view addSubview:rootView]; +} +``` + +When we have a fixed size root view, we need to respect its bounds on the JS side. In other words, we need to ensure that the React Native content can be contained within the fixed-size root view. The easiest way to ensure this is to use flexbox layout. If you use absolute positioning, and React components are visible outside the root view's bounds, you'll get overlap with native views, causing some features to behave unexpectedly. For instance, 'TouchableHighlight' will not highlight your touches outside the root view's bounds. + +It's totally fine to update root view's size dynamically by re-setting its frame property. React Native will take care of the content's layout. + +#### React Native content with flexible size + +In some cases we'd like to render content of initially unknown size. Let's say the size will be defined dynamically in JS. We have two solutions to this problem. + + +1. You can wrap your React Native view in `ScrollView` component. This guarantees that your content will always be available and it won't overlap with native views. +2. React Native allows you to determine, in JS, the size of the RN app and provide it to the owner of the hosting `RCTRootView`. The owner is then responsible for re-laying out the subviews and keeping the UI consistent. We achieve this with `RCTRootView`'s flexibility modes. + + +`RCTRootView` supports 4 different size flexibility modes: + +``` +// RCTRootView.h + +typedef NS_ENUM(NSInteger, RCTRootViewSizeFlexibility) { + RCTRootViewSizeFlexibilityNone = 0, + RCTRootViewSizeFlexibilityWidth, + RCTRootViewSizeFlexibilityHeight, + RCTRootViewSizeFlexibilityWidthAndHeight, +}; +``` + +`RCTRootViewSizeFlexibilityNone` is the default value, which makes a root view's size fixed (but it still can be updated with `setFrame:`). The other three modes allow us to track React Native content's size updates. For instance, setting mode to `RCTRootViewSizeFlexibilityHeight` will cause React Native to measure the content's height and pass that information back to `RCTRootView`'s delegate. An arbitrary action can be performed within the delegate, including setting the root view's frame, so the content fits. The delegate is called only when the size of the content has changed. + +> ***Warning:*** +> Making a dimension flexible in both JS and native leads to undefined behavior. For example - don't make a top-level React component's width flexible (with `flexbox`) while you're using `RCTRootViewSizeFlexibilityWidth` on the hosting `RCTRootView`. + +Let's look at an example. + +``` +// FlexibleSizeExampleView.m + +- (instancetype)initWithFrame:(CGRect)frame +{ + [...] + + _rootView = [[RCTRootView alloc] initWithBridge:bridge + moduleName:@"FlexibilityExampleApp" + initialProperties:@{}]; + + _rootView.delegate = self; + _rootView.sizeFlexibility = RCTRootViewSizeFlexibilityHeight; + _rootView.frame = CGRectMake(0, 0, self.frame.size.width, 0); +} + +#pragma mark - RCTRootViewDelegate +- (void)rootViewDidChangeIntrinsicSize:(RCTRootView *)rootView +{ + CGRect newFrame = rootView.frame; + newFrame.size = rootView.intrinsicSize; + + rootView.frame = newFrame; +} +``` + +In the example we have a `FlexibleSizeExampleView` view that holds a root view. We create the root view, initialize it and set the delegate. The delegate will handle size updates. Then, we set the root view's size flexibility to `RCTRootViewSizeFlexibilityHeight`, which means that `rootViewDidChangeIntrinsicSize:` method will be called every time the React Native content changes its height. Finally, we set the root view's width and position. Note that we set there height as well, but it has no effect as we made the height RN-dependent. + +You can checkout full source code of the example [here](https://phabricator.fb.com/diffusion/FBOBJC/browse/master/Libraries/FBReactKit/js/react-native-github/Examples/UIExplorer/UIExplorer/NativeExampleViews/FlexibleSizeExampleView.m). + +It's fine to change root view's size flexibility mode dynamically. Changing flexibility mode of a root view will schedule a layout recalculation and the delegate `rootViewDidChangeIntrinsicSize:` method will be called once the content size is known. + +> ***Note:*** React Native layout calculation is performed on a special thread, while native UI view updates are done on the main thread. This may cause temporary UI inconsistencies between native and React Native. This is a known problem and our team is working on synchronizing UI updates coming from different sources. + +> ***Note:*** React Native does not perform any layout calculations until the root view becomes a subview of some other views. If you want to hide React Native view until its dimensions are known, add the root view as a subview and make it initially hidden (use `UIView`'s `hidden` property). Then change its visibility in the delegate method. diff --git a/versions/v0.26.0/docs/Debugging.md b/versions/v0.26.0/docs/Debugging.md new file mode 100644 index 0000000..e9378c6 --- /dev/null +++ b/versions/v0.26.0/docs/Debugging.md @@ -0,0 +1,65 @@ +--- +id: debugging +title: Debugging +layout: docs +category: Guides +permalink: docs/debugging.html +next: testing +--- + +## Debugging React Native Apps +To access the in-app developer menu: + +1. On iOS shake the device or press `control + ⌘ + z` in the simulator. +2. On Android shake the device or press hardware menu button (available on older devices and in most of the emulators, e.g. in [genymotion](https://www.genymotion.com) you can press `⌘ + m` or `F2` to simulate hardware menu button click). You can also install [Frappé](http://getfrappe.com), a tool for OS X, which allows you to emulate shaking of devices remotely. You can use `⌘ + Shift + R` as a shortcut to trigger a **shake** from Frappé. + +> Hint + +> To disable the developer menu for production builds: +> +> 1. For iOS open your project in Xcode and select `Product` → `Scheme` → `Edit Scheme...` (or press `⌘ + <`). Next, select `Run` from the menu on the left and change the Build Configuration to `Release`. +> 2. For Android, by default, developer menu will be disabled in release builds done by gradle (e.g with gradle `assembleRelease` task). Although this behavior can be customized by passing proper value to `ReactInstanceManager#setUseDeveloperSupport`. + +### Android logging +Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your Android app's logs. + +### Reload +Selecting `Reload` (or pressing `⌘ + r` in the iOS simulator) will reload the JavaScript that powers your application. If you have added new resources (such as an image to `Images.xcassets` on iOS or to `res/drawable` folder on Android) or modified any native code (Objective-C/Swift code on iOS or Java/C++ code on Android), you will need to re-build the app for the changes to take effect. + +### YellowBox/RedBox +Using `console.warn` will display an on-screen log on a yellow background. Click on this warning to show more information about it full screen and/or dismiss the warning. + +You can use `console.error` to display a full screen error on a red background. + +By default, the warning box is enabled in `__DEV__`. Set the following flag to disable it: +```js +console.disableYellowBox = true; +console.warn('YellowBox is disabled.'); +``` +Specific warnings can be ignored programmatically by setting the array: +```js +console.ignoredYellowBox = ['Warning: ...']; +``` +Strings in `console.ignoredYellowBox` can be a prefix of the warning that should be ignored. + +### Chrome Developer Tools +To debug the JavaScript code in Chrome, select `Debug JS Remotely` from the developer menu. This will open a new tab at [http://localhost:8081/debugger-ui](http://localhost:8081/debugger-ui). + +In Chrome, press `⌘ + option + i` or select `View` → `Developer` → `Developer Tools` to toggle the developer tools console. Enable [Pause On Caught Exceptions](http://stackoverflow.com/questions/2233339/javascript-is-there-a-way-to-get-chrome-to-break-on-all-errors/17324511#17324511) for a better debugging experience. + +To debug on a real device: + +1. On iOS - open the file [`RCTWebSocketExecutor.m`](https://github.com/facebook/react-native/blob/master/Libraries/WebSocket/RCTWebSocketExecutor.m) and change `localhost` to the IP address of your computer. Shake the device to open the development menu with the option to start debugging. +2. On Android, if you're running Android 5.0+ device connected via USB you can use `adb` command line tool to setup port forwarding from the device to your computer. For that run: `adb reverse tcp:8081 tcp:8081` (see [this link](http://developer.android.com/tools/help/adb.html) for help on `adb` command). Alternatively, you can [open dev menu](#debugging-react-native-apps) on the device and select `Dev Settings`, then update `Debug server host for device` setting to the IP address of your computer. + +### Custom JavaScript debugger +To use a custom JavaScript debugger define the `REACT_DEBUGGER` environment variable to a command that will start your custom debugger. That variable will be read from the Packager process. If that environment variable is set, selecting `Debug JS Remotely` from the developer menu will execute that command instead of opening Chrome. The exact command to be executed is the contents of the REACT_DEBUGGER environment variable followed by the space separated paths of all project roots (e.g. If you set REACT_DEBUGGER="node /path/to/launchDebugger.js --port 2345 --type ReactNative" then the command "node /path/to/launchDebugger.js --port 2345 --type ReactNative /path/to/reactNative/app" will end up being executed). Custom debugger commands executed this way should be short-lived processes, and they shouldn't produce more than 200 kilobytes of output. + +### Live Reload +This option allows for your JS changes to trigger automatic reload on the connected device/emulator. To enable this option: + +1. On iOS, select `Enable Live Reload` via the developer menu to have the application automatically reload when changes are made to the JavaScript. +2. On Android, [launch dev menu](#debugging-react-native-apps), go to `Dev Settings` and select `Auto reload on JS change` option + +### FPS (Frames per Second) Monitor +On `0.5.0-rc` and higher versions, you can enable a FPS graph overlay in the developers menu in order to help you debug performance problems. diff --git a/versions/v0.26.0/docs/DirectManipulation.md b/versions/v0.26.0/docs/DirectManipulation.md new file mode 100644 index 0000000..f705eda --- /dev/null +++ b/versions/v0.26.0/docs/DirectManipulation.md @@ -0,0 +1,211 @@ +--- +id: direct-manipulation +title: Direct Manipulation +layout: docs +category: Guides +permalink: docs/direct-manipulation.html +next: debugging +--- + +It is sometimes necessary to make changes directly to a component +without using state/props to trigger a re-render of the entire subtree. +When using React in the browser for example, you sometimes need to +directly modify a DOM node, and the same is true for views in mobile +apps. `setNativeProps` is the React Native equivalent to setting +properties directly on a DOM node. + +> Use setNativeProps when frequent re-rendering creates a performance bottleneck +> +> Direct manipulation will not be a tool that you reach for +> frequently; you will typically only be using it for creating +> continuous animations to avoid the overhead of rendering the component +> hierarchy and reconciling many views. `setNativeProps` is imperative +> and stores state in the native layer (DOM, UIView, etc.) and not +> within your React components, which makes your code more difficult to +> reason about. Before you use it, try to solve your problem with `setState` +> and [shouldComponentUpdate](http://facebook.github.io/react/docs/advanced-performance.html#shouldcomponentupdate-in-action). + +## setNativeProps with TouchableOpacity + +[TouchableOpacity](https://github.com/facebook/react-native/blob/master/Libraries/Components/Touchable/TouchableOpacity.js) +uses `setNativeProps` internally to update the opacity of its child +component: + +```javascript +setOpacityTo: function(value) { + // Redacted: animation related code + this.refs[CHILD_REF].setNativeProps({ + opacity: value + }); +}, +``` + +This allows us to write the following code and know that the child will +have its opacity updated in response to taps, without the child having +any knowledge of that fact or requiring any changes to its implementation: + +```javascript + + + Press me! + + +``` + +Let's imagine that `setNativeProps` was not available. One way that we +might implement it with that constraint is to store the opacity value +in the state, then update that value whenever `onPress` is fired: + +```javascript +getInitialState() { + return { myButtonOpacity: 1, } +}, + +render() { + return ( + this.setState({myButtonOpacity: 0.5})} + onPressOut={() => this.setState({myButtonOpacity: 1})}> + + Press me! + + + ) +} +``` + +This is computationally intensive compared to the original example - +React needs to re-render the component hierarchy each time the opacity +changes, even though other properties of the view and its children +haven't changed. Usually this overhead isn't a concern but when +performing continuous animations and responding to gestures, judiciously +optimizing your components can improve your animations' fidelity. + +If you look at the implementation of `setNativeProps` in +[NativeMethodsMixin.js](https://github.com/facebook/react-native/blob/master/Libraries/ReactIOS/NativeMethodsMixin.js) +you will notice that it is a wrapper around `RCTUIManager.updateView` - +this is the exact same function call that results from re-rendering - +see [receiveComponent in +ReactNativeBaseComponent.js](https://github.com/facebook/react-native/blob/master/Libraries/ReactNative/ReactNativeBaseComponent.js). + +## Composite components and setNativeProps + +Composite components are not backed by a native view, so you cannot call +`setNativeProps` on them. Consider this example: + +```javascript +var MyButton = React.createClass({ + render() { + return ( + + {this.props.label} + + ) + }, +}); + +var App = React.createClass({ + render() { + return ( + + + + ) + }, +}); +``` +[Run this example](https://rnplay.org/apps/JXkgmQ) + +If you run this you will immediately see this error: `Touchable child +must either be native or forward setNativeProps to a native component`. +This occurs because `MyButton` isn't directly backed by a native view +whose opacity should be set. You can think about it like this: if you +define a component with `React.createClass` you would not expect to be +able to set a style prop on it and have that work - you would need to +pass the style prop down to a child, unless you are wrapping a native +component. Similarly, we are going to forward `setNativeProps` to a +native-backed child component. + +#### Forward setNativeProps to a child + +All we need to do is provide a `setNativeProps` method on our component +that calls `setNativeProps` on the appropriate child with the given +arguments. + +```javascript +var MyButton = React.createClass({ + setNativeProps(nativeProps) { + this._root.setNativeProps(nativeProps); + }, + + render() { + return ( + this._root = component} {...this.props}> + {this.props.label} + + ) + }, +}); +``` +[Run this example](https://rnplay.org/apps/YJxnEQ) + +You can now use `MyButton` inside of `TouchableOpacity`! A sidenote for +clarity: we used the [ref callback](https://facebook.github.io/react/docs/more-about-refs.html#the-ref-callback-attribute) syntax here, rather than the traditional string-based ref. + +You may have noticed that we passed all of the props down to the child +view using `{...this.props}`. The reason for this is that +`TouchableOpacity` is actually a composite component, and so in addition +to depending on `setNativeProps` on its child, it also requires that the +child perform touch handling. To do this, it passes on [various +props](docs/view.html#onmoveshouldsetresponder) +that call back to the `TouchableOpacity` component. +`TouchableHighlight`, in contrast, is backed by a native view and only +requires that we implement `setNativeProps`. + +## setNativeProps to clear TextInput value + +Another very common use case of `setNativeProps` is to clear the value +of a TextInput. The `controlled` prop of TextInput can sometimes drop +characters when the `bufferDelay` is low and the user types very +quickly. Some developers prefer to skip this prop entirely and instead +use `setNativeProps` to directly manipulate the TextInput value when +necessary. For example, the following code demonstrates clearing the +input when you tap a button: + +```javascript +var App = React.createClass({ + clearText() { + this._textInput.setNativeProps({text: ''}); + }, + + render() { + return ( + + this._textInput = component} + style={styles.textInput} /> + + Clear text + + + ); + } +}); +``` +[Run this example](https://rnplay.org/plays/pOI9bA) + +## Avoiding conflicts with the render function + +If you update a property that is also managed by the render function, +you might end up with some unpredictable and confusing bugs because +anytime the component re-renders and that property changes, whatever +value was previously set from `setNativeProps` will be completely +ignored and overridden. [See this example](https://rnplay.org/apps/bp1DvQ) +for a demonstration of what can happen if these two collide - notice +the jerky animation each 250ms when `setState` triggers a re-render. + +## setNativeProps & shouldComponentUpdate + +By [intelligently applying +`shouldComponentUpdate`](https://facebook.github.io/react/docs/advanced-performance.html#avoiding-reconciling-the-dom) +you can avoid the unnecessary overhead involved in reconciling unchanged +component subtrees, to the point where it may be performant enough to +use `setState` instead of `setNativeProps`. diff --git a/versions/v0.26.0/docs/EmbeddedAppAndroid.md b/versions/v0.26.0/docs/EmbeddedAppAndroid.md new file mode 100644 index 0000000..e62a405 --- /dev/null +++ b/versions/v0.26.0/docs/EmbeddedAppAndroid.md @@ -0,0 +1,175 @@ +--- +id: embedded-app-android +title: Integrating with Existing Apps +layout: docs +category: Guides (Android) +permalink: docs/embedded-app-android.html +next: signed-apk-android +--- + +Since React makes no assumptions about the rest of your technology stack, it's easily embeddable within an existing non-React Native app. + +## Requirements + +* an existing, gradle-based Android app +* Node.js, see Getting Started for setup instructions + +## Prepare your app + +In your app's `build.gradle` file add the React Native dependency: + + compile 'com.facebook.react:react-native:0.20.+' + +You can find the latest version of the react-native library on [Maven Central](http://search.maven.org/#search%7Cgav%7C1%7Cg%3A%22com.facebook.react%22%20AND%20a%3A%22react-native%22). Next, make sure you have the Internet permission in your `AndroidManifest.xml`: + + + +This is only really used in dev mode when reloading JavaScript from the development server, so you can strip this in release builds if you need to. + +## Add native code + +You need to add some native code in order to start the React Native runtime and get it to render something. To do this, we're going to create an `Activity` that creates a `ReactRootView`, starts a React application inside it and sets it as the main content view. + +```java +public class MyReactActivity extends Activity implements DefaultHardwareBackBtnHandler { + private ReactRootView mReactRootView; + private ReactInstanceManager mReactInstanceManager; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + + mReactRootView = new ReactRootView(this); + mReactInstanceManager = ReactInstanceManager.builder() + .setApplication(getApplication()) + .setBundleAssetName("index.android.bundle") + .setJSMainModuleName("index.android") + .addPackage(new MainReactPackage()) + .setUseDeveloperSupport(BuildConfig.DEBUG) + .setInitialLifecycleState(LifecycleState.RESUMED) + .build(); + mReactRootView.startReactApplication(mReactInstanceManager, "MyAwesomeApp", null); + + setContentView(mReactRootView); + } + + @Override + public void invokeDefaultOnBackPressed() { + super.onBackPressed(); + } +} +``` + +Next, we need to pass some activity lifecycle callbacks down to the `ReactInstanceManager`: + +```java +@Override +protected void onPause() { + super.onPause(); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onPause(); + } +} + +@Override +protected void onResume() { + super.onResume(); + + if (mReactInstanceManager != null) { + mReactInstanceManager.onResume(this, this); + } +} +``` + +We also need to pass back button events to React Native: + +```java +@Override + public void onBackPressed() { + if (mReactInstanceManager != null) { + mReactInstanceManager.onBackPressed(); + } else { + super.onBackPressed(); + } +} +``` + + This allows JavaScript to control what happens when the user presses the hardware back button (e.g. to implement navigation). When JavaScript doesn't handle a back press, your `invokeDefaultOnBackPressed` method will be called. By default this simply finishes your `Activity`. +Finally, we need to hook up the dev menu. By default, this is activated by (rage) shaking the device, but this is not very useful in emulators. So we make it show when you press the hardware menu button: + +```java +@Override +public boolean onKeyUp(int keyCode, KeyEvent event) { + if (keyCode == KeyEvent.KEYCODE_MENU && mReactInstanceManager != null) { + mReactInstanceManager.showDevOptionsDialog(); + return true; + } + return super.onKeyUp(keyCode, event); +} +``` + +That's it, your activity is ready to run some JavaScript code. + +## Add JS to your app + +In your project's root folder, run: + + $ npm init + $ npm install --save react-native + $ curl -o .flowconfig https://raw.githubusercontent.com/facebook/react-native/master/.flowconfig + +This creates a node module for your app and adds the `react-native` npm dependency. Now open the newly created `package.json` file and add this under `scripts`: + + "start": "node node_modules/react-native/local-cli/cli.js start" + +Copy & paste the following code to `index.android.js` in your root folder — it's a barebones React Native app: + +```js +'use strict'; + +import React from 'react'; +import { + AppRegistry, + StyleSheet, + Text, + View +} from 'react-native'; + +class MyAwesomeApp extends React.Component { + render() { + return ( + + Hello, World + + ) + } +} +var styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + }, + hello: { + fontSize: 20, + textAlign: 'center', + margin: 10, + }, +}); + +AppRegistry.registerComponent('MyAwesomeApp', () => MyAwesomeApp); +``` + +## Run your app + +To run your app, you need to first start the development server. To do this, simply run the following command in your root folder: + + $ npm start + +Now build and run your Android app as normal (e.g. `./gradlew installDebug`). Once you reach your React-powered activity inside the app, it should load the JavaScript code from the development server and display: + +![Screenshot](img/EmbeddedAppAndroid.png) + +## Sharing a ReactInstance across multiple Activities / Fragments in your app + +You can have multiple Activities or Fragments that use the same `ReactInstanceManager`. You'll want to make your own "ReactFragment" or "ReactActivity" and have a singleton "holder" that holds a `ReactInstanceManager`. When you need the `ReactInstanceManager` / hook up the `ReactInstanceManager` to the lifecycle of those Activities or Fragments, use the one provided by the singleton. diff --git a/versions/v0.26.0/docs/EmbeddedAppIOS.md b/versions/v0.26.0/docs/EmbeddedAppIOS.md new file mode 100644 index 0000000..3a1b8c9 --- /dev/null +++ b/versions/v0.26.0/docs/EmbeddedAppIOS.md @@ -0,0 +1,228 @@ +--- +id: embedded-app-ios +title: Integrating with Existing Apps +layout: docs +category: Guides (iOS) +permalink: docs/embedded-app-ios.html +next: communication-ios +--- + +Since React makes no assumptions about the rest of your technology stack – it’s commonly noted as simply the `V` in `MVC` – it’s easily embeddable within an existing non-React Native app. In fact, it integrates with other best practice community tools like [CocoaPods](http://cocoapods.org/). + +## Requirements + +- [CocoaPods](http://cocoapods.org/) – `gem install cocoapods` +- [Node.js](http://nodejs.org) + - Install **nvm** with [its setup instructions here](https://github.com/creationix/nvm#installation). Then run `nvm install node && nvm alias default node`, which installs the latest version of Node.js and sets up your terminal so you can run it by typing `node`. With nvm you can install multiple versions of Node.js and easily switch between them. +- Install the `react-native` package from npm by running the following command in the root directory of your project: + - `npm install react-native` + +At this point you should have the React Native package installed under a directory named `node_modules` as a sibling to your `.xcodeproj` file. + + +## Install React Native Using CocoaPods + +[CocoaPods](http://cocoapods.org/) is a package management tool for iOS/Mac development. We need to use it to download React Native. If you haven't installed CocoaPods yet, check out [this tutorial](http://guides.cocoapods.org/using/getting-started.html). + +When you are ready to work with CocoaPods, add the following lines to `Podfile`. If you don't have one, then create it under the root directory of your project. + +```ruby +# Depending on how your project is organized, your node_modules directory may be +# somewhere else; tell CocoaPods where you've installed react-native from npm +pod 'React', :path => './node_modules/react-native', :subspecs => [ + 'Core', + 'RCTImage', + 'RCTNetwork', + 'RCTText', + 'RCTWebSocket', + # Add any other subspecs you want to use in your project +] +``` + +Remember to install all subspecs you need. The `` element cannot be used without the `RCTText` subspec, for example. + +Then install your pods: + +``` +$ pod install +``` + +## Create Your React Native App + +There are two pieces you’ll need to set up: + +1. The root JavaScript file that will contain your actual React Native app and other components +- Wrapper Objective-C code that will load up your script and create a `RCTRootView` to display and manage your React Native components + +First, create a directory for your app’s React code and create a simple `index.ios.js` file: + +``` +$ mkdir ReactComponent +$ touch ReactComponent/index.ios.js +``` + +Copy & paste following starter code for `index.ios.js` – it’s a barebones React Native app: + +``` +'use strict'; + +import React from 'react'; +import { + AppRegistry, + StyleSheet, + Text, + View +} from 'react-native'; + +var styles = StyleSheet.create({ + container: { + flex: 1, + backgroundColor: 'red' + } +}); + +class SimpleApp extends React.Component { + render() { + return ( + + This is a simple application. + + ) + } +} + +AppRegistry.registerComponent('SimpleApp', () => SimpleApp); +``` + +`SimpleApp` will be your **module name**, which will be used later on. + +## Add Container View To Your App + +You should now add a container view for the React Native component. It can be any `UIView` in your app. + +![Container view example](img/EmbeddedAppContainerViewExample.png) + +However, let's subclass `UIView` for the sake of clean code. Let's name it `ReactView`. Open up `Yourproject.xcworkspace` and create a new class `ReactView` (You can name it whatever you like :)). + +``` +// ReactView.h + +#import +@interface ReactView : UIView +@end +``` + +In a view controller that wants to manage this view, go ahead and add an outlet and wire it up: + +``` +// ViewController.m + +@interface ViewController () +@property (weak, nonatomic) IBOutlet ReactView *reactView; +@end +``` +__NOTE__ For Swift apps there is no need for that. + +Here I disabled **AutoLayout** for simplicity. In real production world, you should turn on AutoLayout and setup constraints by yourself. + +## Add RCTRootView To Container View + +Ready for the most interesting part? Now we shall create the `RCTRootView`, where your React Native app lives. + +In `ReactView.m`, we need to first initiate `RCTRootView` with the URI of your `index.ios.bundle`. `index.ios.bundle` will be created by packager and served by React Native server, which will be discussed later on. + +``` +NSURL *jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios"]; +// For production use, this `NSURL` could instead point to a pre-bundled file on disk: +// +// NSURL *jsCodeLocation = [[NSBundle mainBundle] URLForResource:@"main" withExtension:@"jsbundle"]; +// +// To generate that file, run the curl command and add the output to your main Xcode build target: +// +// curl http://localhost:8081/index.ios.bundle -o main.jsbundle +RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation + moduleName: @"SimpleApp" + initialProperties:nil + launchOptions:nil]; +``` + +Then add it as a subview of the `ReactView`. + +``` +[self addSubview:rootView]; +rootView.frame = self.bounds; +``` + +### Swift apps + +Add the following to ReactView.swift file: + +``` +import UIKit +import React + +class ReactView: UIView { + + let rootView: RCTRootView = RCTRootView(bundleURL: NSURL(string: "http://localhost:8081/index.ios.bundle?platform=ios"), + moduleName: "SimpleApp", initialProperties: nil, launchOptions: nil) + + override func layoutSubviews() { + super.layoutSubviews() + + loadReact() + } + + func loadReact () { + addSubview(rootView) + rootView.frame = self.bounds + } +} +``` + +And then make sure your view is added in a ViewContainer or story board file. + +## Start Development Server + +In root directory, we need to start React Native development server. + +``` +(JS_DIR=`pwd`/ReactComponent; cd node_modules/react-native; npm run start -- --root $JS_DIR) +``` + +This command will start up a React Native development server within our CocoaPods dependency to build our bundled script. The `--root` option indicates the root of your React Native apps – this will be our `ReactComponent` directory containing the single `index.ios.js` file. This running server will package up the `index.ios.bundle` file accessible via `http://localhost:8081/index.ios.bundle`. + +## Update App Transport Security + +On iOS 9 and above the app won't be a able to connect over http to localhost unless specifically told so. See this thread for alternatives and instructions: http://stackoverflow.com/questions/31254725/transport-security-has-blocked-a-cleartext-http. + +It is recommended that you add an App Transport Security exception for `localhost` in your app's `Info.plist` file: + +```xml +NSAppTransportSecurity + + NSExceptionDomains + + localhost + + NSTemporaryExceptionAllowsInsecureHTTPLoads + + + + +``` + +If you don't do this, you will see the error - `Could not connect to development server.` when connecting to your server over http. + +## Compile And Run + +Now compile and run your app. You shall now see your React Native app running inside of the `ReactView`. + +![Example](img/EmbeddedAppExample.png) + +Live reload and all of the debugging tools will work from the simulator (make sure that DEBUG=1 is set under Build Settings -> Preprocessor Macros). You've got a simple React component totally encapsulated behind an Objective-C `UIView` subclass. + +## Conclusion + +So under the hood, when `RCTRootView` is initialized, it will try to download, parse and run the bundle file from React Native development server. This means all you need to do is to implement your own container view or view controller for the `RCTRootView` – the `RCTRootView` ingests your bundled JS and renders your React components. Bravo! + +You can checkout full source code of a sample application [here](https://github.com/hfossli/ReactNativeIntegration). diff --git a/versions/v0.26.0/docs/GestureResponderSystem.md b/versions/v0.26.0/docs/GestureResponderSystem.md new file mode 100644 index 0000000..b7c8dbc --- /dev/null +++ b/versions/v0.26.0/docs/GestureResponderSystem.md @@ -0,0 +1,71 @@ +--- +id: gesture-responder-system +title: Gesture Responder System +layout: docs +category: Guides +permalink: docs/gesture-responder-system.html +next: animations +--- + +Gesture recognition on mobile devices is much more complicated than web. A touch can go through several phases as the app determines what the user's intention is. For example, the app needs to determine if the touch is scrolling, sliding on a widget, or tapping. This can even change during the duration of a touch. There can also be multiple simultaneous touches. + +The touch responder system is needed to allow components to negotiate these touch interactions without any additional knowledge about their parent or child components. This system is implemented in `ResponderEventPlugin.js`, which contains further details and documentation. + +### Best Practices + +Users can feel huge differences in the usability of web apps vs. native, and this is one of the big causes. Every action should have the following attributes: + +- Feedback/highlighting- show the user what is handling their touch, and what will happen when they release the gesture +- Cancel-ability- when making an action, the user should be able to abort it mid-touch by dragging their finger away + +These features make users more comfortable while using an app, because it allows people to experiment and interact without fear of making mistakes. + +### TouchableHighlight and Touchable* + +The responder system can be complicated to use. So we have provided an abstract `Touchable` implementation for things that should be "tappable". This uses the responder system and allows you to easily configure tap interactions declaratively. Use `TouchableHighlight` anywhere where you would use a button or link on web. + + +## Responder Lifecycle + +A view can become the touch responder by implementing the correct negotiation methods. There are two methods to ask the view if it wants to become responder: + + - `View.props.onStartShouldSetResponder: (evt) => true,` - Does this view want to become responder on the start of a touch? + - `View.props.onMoveShouldSetResponder: (evt) => true,` - Called for every touch move on the View when it is not the responder: does this view want to "claim" touch responsiveness? + +If the View returns true and attempts to become the responder, one of the following will happen: + + - `View.props.onResponderGrant: (evt) => {}` - The View is now responding for touch events. This is the time to highlight and show the user what is happening + - `View.props.onResponderReject: (evt) => {}` - Something else is the responder right now and will not release it + +If the view is responding, the following handlers can be called: + + - `View.props.onResponderMove: (evt) => {}` - The user is moving their finger + - `View.props.onResponderRelease: (evt) => {}` - Fired at the end of the touch, ie "touchUp" + - `View.props.onResponderTerminationRequest: (evt) => true` - Something else wants to become responder. Should this view release the responder? Returning true allows release + - `View.props.onResponderTerminate: (evt) => {}` - The responder has been taken from the View. Might be taken by other views after a call to `onResponderTerminationRequest`, or might be taken by the OS without asking (happens with control center/ notification center on iOS) + +`evt` is a synthetic touch event with the following form: + + - `nativeEvent` + + `changedTouches` - Array of all touch events that have changed since the last event + + `identifier` - The ID of the touch + + `locationX` - The X position of the touch, relative to the element + + `locationY` - The Y position of the touch, relative to the element + + `pageX` - The X position of the touch, relative to the root element + + `pageY` - The Y position of the touch, relative to the root element + + `target` - The node id of the element receiving the touch event + + `timestamp` - A time identifier for the touch, useful for velocity calculation + + `touches` - Array of all current touches on the screen + +### Capture ShouldSet Handlers + +`onStartShouldSetResponder` and `onMoveShouldSetResponder` are called with a bubbling pattern, where the deepest node is called first. That means that the deepest component will become responder when multiple Views return true for `*ShouldSetResponder` handlers. This is desirable in most cases, because it makes sure all controls and buttons are usable. + +However, sometimes a parent will want to make sure that it becomes responder. This can be handled by using the capture phase. Before the responder system bubbles up from the deepest component, it will do a capture phase, firing `on*ShouldSetResponderCapture`. So if a parent View wants to prevent the child from becoming responder on a touch start, it should have a `onStartShouldSetResponderCapture` handler which returns true. + + - `View.props.onStartShouldSetResponderCapture: (evt) => true,` + - `View.props.onMoveShouldSetResponderCapture: (evt) => true,` + +### PanResponder + +For higher-level gesture interpretation, check out [PanResponder](docs/panresponder.html). diff --git a/versions/v0.26.0/docs/GettingStarted.md b/versions/v0.26.0/docs/GettingStarted.md new file mode 100644 index 0000000..a5a04f1 --- /dev/null +++ b/versions/v0.26.0/docs/GettingStarted.md @@ -0,0 +1,731 @@ +--- +id: getting-started +title: Getting Started +layout: docs +category: Quick Start +permalink: docs/getting-started.html +next: tutorial +--- + +## Installation + +### Required Prerequisites + +#### Homebrew + +[Homebrew](http://brew.sh/), in order to install the required NodeJS, in addition to some +recommended installs. + +``` +/usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)" +``` + +#### Node + +Use Homebrew to install [Node.js](https://nodejs.org/). + +> NodeJS 4.0 or greater is required for React Native. The default Homebrew package for Node is +> currently 6.0, so that is not an issue. + +``` +brew install node +``` + +#### React Native Command Line Tools + +The React Native command line tools allow you to easily create and initialize projects, etc. + +``` +npm install -g react-native-cli +``` + +> If you see the error, `EACCES: permission denied`, please run the command: +> `sudo npm install -g react-native-cli`. + + + +#### Xcode + +[Xcode](https://developer.apple.com/xcode/downloads/) 7.0 or higher. Open the App Store or go to https://developer.apple.com/xcode/downloads/. This will also install `git` as well. + + + +#### Android Studio + +[Android Studio](http://developer.android.com/sdk/index.html) 2.0 or higher. + +> Android Studio requires the Java Development Kit [JDK] 1.8 or higher. You can type +> `javac -version` to see what version you have, if any. If you do not meet the JDK requirement, +> you can +> [download it](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html). + +Android Studio will provide you the Android SDK and emulator required to run and test your React +Native apps. + +> Unless otherwise mentioned, keep all the setup defaults intact. For example, the +> `Android Support Repository` is installed automatically with Android Studio, and we need that +> for React Native. + +You will need to customize your installation: + +- Choose a `Custom` installation + +![custom installation](img/react-native-android-studio-custom-install.png) + +- Choose both `Performance` and `Android Virtual Device` + +![additional installs](img/react-native-android-studio-additional-installs.png) + +- After installation, choose `Configure | SDK Manager` from the Android Studio welcome window. + +![configure sdk](img/react-native-android-studio-configure-sdk.png) + +- In the `SDK Platforms` window, choose `Show Package Details` and under `Android 6.0 (Marshmallow)`, make sure that `Google APIs`, `Intel x86 Atom System Image`, `Intel x86 Atom_64 System Image`, and `Google APIs Intel x86 Atom_64 System Image` are checked. + +![platforms](img/react-native-android-studio-android-sdk-platforms.png) + +- In the `SDK Tools` window, choose `Show Package Details` and under `Android SDK Build Tools`, make sure that `Android SDK Build-Tools 23.0.1` is selected. + +![build tools](img/react-native-android-studio-android-sdk-build-tools.png) + +#### ANDROID_HOME Environment Variable + +Ensure the `ANDROID_HOME` environment variable points to your existing Android SDK. To do that, add +this to your `~/.bashrc`, `~/.bash_profile` (or whatever your shell uses) and re-open your terminal: + +``` +# If you installed the SDK without Android Studio, then it may be something like: +# /usr/local/opt/android-sdk +export ANDROID_HOME=~/Library/Android/sdk +``` + + + +### Highly Recommended Installs + +#### Watchman + +[Watchman](https://facebook.github.io/watchman/docs/install.html) is a tool by Facebook for watching +changes in the filesystem. It is recommended you install it for better performance. + +``` +brew install watchman +``` + +#### Flow + +[Flow](http://www.flowtype.org), for static typechecking of your React Native code (when using +Flow as part of your codebase). + + +``` +brew install flow +``` + + + +#### Add Android Tools Directory to your `PATH` + +You can add the Android tools directory on your `PATH` in case you need to run any of the Android +tools from the command line such as `android avd`. In your `~/.bash` or `~/.bash_profile`: + +``` +# Your exact string here may be different. +PATH="~/Library/Android/sdk/tools:~/Library/Android/sdk/platform-tools:${PATH}" +export PATH +``` + +#### Gradle Daemon + +Enable [Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) which greatly improves incremental build times for changes in java code. + +### Other Optional Installs + +#### Git + +Git version control. If you have installed [Xcode](https://developer.apple.com/xcode/), Git is +already installed, otherwise run the following: + +``` +brew install git +``` + + + +#### Nuclide + +[Nuclide](http://nuclide.io) is an IDE from Facebook providing a first-class development environment +for writing, [running](http://nuclide.io/docs/platforms/react-native/#running-applications) and +[debugging](http://nuclide.io/docs/platforms/react-native/#debugging) +[React Native](http://nuclide.io/docs/platforms/react-native/) applications. + +Get started with Nuclide [here](http://nuclide.io/docs/quick-start/getting-started/). + + + +#### Genymotion + +Genymotion is an alternative to the stock Google emulator that comes with Android Studio. +However, it's only free for personal use. If you want to use the stock Google emulator, see below. + +1. Download and install [Genymotion](https://www.genymotion.com/). +2. Open Genymotion. It might ask you to install VirtualBox unless you already have it. +3. Create a new emulator and start it. +4. To bring up the developer menu press ⌘+M + +### Troubleshooting + +#### Virtual Device Not Created When Installing Android Studio + +There is a [known bug](https://code.google.com/p/android/issues/detail?id=207563) on some versions +of Android Studio where a virtual device will not be created, even though you selected it in the +installation sequence. You may see this at the end of the installation: + +``` +Creating Android virtual device +Unable to create a virtual device: Unable to create Android virtual device +``` + +If you see this, run `android avd` and create the virtual device manually. + +![avd](img/react-native-android-studio-avd.png) + +Then select the new device in the AVD Manager window and click `Start...`. + +#### Shell Command Unresponsive Exception + +If you encounter: + +``` +Execution failed for task ':app:installDebug'. + com.android.builder.testing.api.DeviceException: com.android.ddmlib.ShellCommandUnresponsiveException +``` + +try downgrading your Gradle version to 1.2.3 in `/android/build.gradle` (https://github.com/facebook/react-native/issues/2720) + + + + + + +## Installation + +### Required Prerequisites + + + +#### Chocolatey + +[Chocolatey](https://chocolatey.org) is a package manager for Windows similar to `yum` and +`apt-get`. See the [website](https://chocolatey.org) for updated instructions, but installing from +the Terminal should be something like: + +``` +@powershell -NoProfile -ExecutionPolicy Bypass -Command "iex ((new-object net.webclient).DownloadString('https://chocolatey.org/install.ps1'))" && SET PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin +``` + +> Normally when you run Chocolatey to install a package, you should run your Terminal as +> Administrator. + +#### Python 2 + +Fire up the Termimal and use Chocolatey to install Python 2. + +> Python 3 will currently not work when initializing a React Native project. + +``` +choco install python2 +``` + + + +#### Node + + + +Fire up the Terminal and type the following commands to install NodeJS from the NodeSource +repository: + +``` +sudo apt-get install -y build-essential +curl -sL https://deb.nodesource.com/setup_4.x | sudo -E bash - +sudo apt-get install -y nodejs +sudo ln -s /usr/bin/nodejs /usr/bin/node +``` + + + +Fire up the Termimal and use Chocolatey to install NodeJS. + +``` +choco install nodejs.install +``` + + + +#### React Native Command Line Tools + +The React Native command line tools allow you to easily create and initialize projects, etc. + +``` +npm install -g react-native-cli +``` + +> If you see the error, `EACCES: permission denied`, please run the command: +> `sudo npm install -g react-native-cli`. + +#### Android Studio + +[Android Studio](http://developer.android.com/sdk/index.html) 2.0 or higher. + +> Android Studio requires the Java Development Kit [JDK] 1.8 or higher. You can type +> `javac -version` to see what version you have, if any. If you do not meet the JDK requirement, +> you can +> [download it](http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html), +> or use a pacakage manager to install it (e.g. `choco install jdk8`, +> `apt-get install default-jdk`). + +Android Studio will provide you the Android SDK and emulator required to run and test your React +Native apps. + +> Unless otherwise mentioned, keep all the setup defaults intact. For example, the +> `Android Support Repository` is installed automatically with Android Studio, and we need that +> for React Native. + + + +You will need to customize your installation: + +- Choose a `Custom` installation + +![custom installation](img/react-native-android-studio-custom-install-linux.png) + +- Choose `Android Virtual Device` + +![additional installs](img/react-native-android-studio-additional-installs-linux.png) + + + +- Make sure all components are checked for the install, particularly the `Android SDK` and `Android Device Emulator`. + +- After the initial install, choose a `Custom` installation. + +![custom installation](img/react-native-android-studio-custom-install-windows.png) + +- Verify installed components, particularly the emulator and the HAXM accelerator. They should be checked. + +![verify installs](img/react-native-android-studio-verify-installs-windows.png) + + + +- After installation, choose `Configure | SDK Manager` from the Android Studio welcome window. + + + +![configure sdk](img/react-native-android-studio-configure-sdk-linux.png) + + + +![configure sdk](img/react-native-android-studio-configure-sdk-windows.png) + + + +- In the `SDK Platforms` window, choose `Show Package Details` and under `Android 6.0 (Marshmallow)`, make sure that `Google APIs`, `Intel x86 Atom System Image`, `Intel x86 Atom_64 System Image`, and `Google APIs Intel x86 Atom_64 System Image` are checked. + + + +![platforms](img/react-native-android-studio-android-sdk-platforms-linux.png) + + + +![platforms](img/react-native-android-studio-android-sdk-platforms-windows.png) + + + +- In the `SDK Tools` window, choose `Show Package Details` and under `Android SDK Build Tools`, make sure that `Android SDK Build-Tools 23.0.1` is selected. + + + +![build tools](img/react-native-android-studio-android-sdk-build-tools-linux.png) + + + +![build tools](img/react-native-android-studio-android-sdk-build-tools-windows.png) + + + +#### ANDROID_HOME Environment Variable + +Ensure the `ANDROID_HOME` environment variable points to your existing Android SDK. + + + +To do that, add this to your `~/.bashrc`, `~/.bash_profile` (or whatever your shell uses) and +re-open your terminal: + +``` +# If you installed the SDK without Android Studio, then it may be something like: +# /usr/local/opt/android-sdk; Generally with Android Studio, the SDK is installed here... +export ANDROID_HOME=~/Android/Sdk +``` + +> You need to restart the Terminal to apply the new environment variables (or `source` the relevant +> bash file). + + + +Go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> +`Advanced System Settings` -> `Environment variables` -> `New` + +> Your path to the SDK will vary to the one shown below. + +![env variable](img/react-native-android-sdk-environment-variable-windows.png) + +> You need to restart the Command Prompt (Windows) to apply the new environment variables. + + + +### Highly Recommended Installs + + + +#### Watchman + +Watchman is a tool by Facebook for watching changes in the filesystem. It is recommended you install +it for better performance. + +> This also helps avoid a node file-watching bug. + +Type the following into your terminal to compile watchman from source and install it: + +``` +git clone https://github.com/facebook/watchman.git +cd watchman +git checkout v4.5.0 # the latest stable release +./autogen.sh +./configure +make +sudo make install +``` + +#### Flow + +[Flow](http://www.flowtype.org), for static typechecking of your React Native code (when using +Flow as part of your codebase). + +Type the following in the terminal: + +``` +npm install -g flow-bin +``` + + + +#### Gradle Daemon + +Enable [Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) which greatly +improves incremental build times for changes in java code. + + + +``` +touch ~/.gradle/gradle.properties && echo "org.gradle.daemon=true" >> ~/.gradle/gradle.properties +``` + + + +``` +(if not exist "%USERPROFILE%/.gradle" mkdir "%USERPROFILE%/.gradle") && (echo org.gradle.daemon=true >> "%USERPROFILE%/.gradle/gradle.properties") +``` + + + +#### Android Emulator Accelerator + +You may have seen the following screen when installing Android Studio. + +![accelerator](img/react-native-android-studio-kvm-linux.png) + +If your system supports KVM, you should install the +[Intel Android Emulator Accelerator](https://software.intel.com/en-us/android/articles/speeding-up-the-android-emulator-on-intel-architecture#_Toc358213272). + + + +#### Add Android Tools Directory to your `PATH` + +You can add the Android tools directory on your `PATH` in case you need to run any of the Android +tools from the command line such as `android avd`. + + + +In your `~/.bashrc` or `~/.bash_profile`: + +``` +# Your exact string here may be different. +PATH="~/Android/Sdk/tools:~/Android/Sdk/platform-tools:${PATH}" +export PATH +``` + + + +Go to `Control Panel` -> `System and Security` -> `System` -> `Change settings` -> +`Advanced System Settings` -> `Environment variables` -> highlight `PATH` -> `Edit...` + +> The location of your Android tools directories will vary. + +![env variable](img/react-native-android-tools-environment-variable-windows.png) + + + +### Other Optional Installs + +#### Git + + + +Install Git [via your package manager](https://git-scm.com/download/linux) +(e.g., `sudo apt-get install git-all`). + + + +You can use Chocolatey to install `git` via: + +``` +choco install git +``` + +Alternatively, you can download and install [Git for Windows](https://git-for-windows.github.io/). +During the setup process, choose "Run Git from Windows Command Prompt", which will add `git` to your +`PATH` environment variable. + + + +#### Nuclide + +[Nuclide] is an IDE from Facebook providing a first-class development environment for writing, +[running](http://nuclide.io/docs/platforms/react-native/#running-applications) and +[debugging](http://nuclide.io/docs/platforms/react-native/#debugging) +[React Native](http://nuclide.io/docs/platforms/react-native/) applications. + +Get started with Nuclide [here](http://nuclide.io/docs/quick-start/getting-started/). + + + +#### Genymotion + +Genymotion is an alternative to the stock Google emulator that comes with Android Studio. +However, it's only free for personal use. If you want to use the stock Google emulator, see below. + +1. Download and install [Genymotion](https://www.genymotion.com/). +2. Open Genymotion. It might ask you to install VirtualBox unless you already have it. +3. Create a new emulator and start it. +4. To bring up the developer menu press ⌘+M + + + +#### Visual Studio Emulator for Android + +The [Visual Studio Emulator for Android](https://www.visualstudio.com/en-us/features/msft-android-emulator-vs.aspx) +is a free android emulator that is hardware accelerated via Hyper-V. It is an alternative to the +stock Google emulator that comes with Android Studio. It doesn't require you to install Visual +Studio at all. + +To use it with react-native you just have to add a key and value to your registry: + +1. Open the Run Command (Windows+R) +2. Enter `regedit.exe` +3. In the Registry Editor navigate to `HKEY_LOCAL_MACHINE\SOFTWARE\Wow6432Node\Android SDK Tools` +4. Right Click on `Android SDK Tools` and choose `New > String Value` +5. Set the name to `Path` +6. Double Click the new `Path` Key and set the value to `C:\Program Files\Android\sdk`. The path value might be different on your machine. + +You will also need to run the command `adb reverse tcp:8081 tcp:8081` with this emulator. + +Then restart the emulator and when it runs you can just do `react-native run-android` as usual. + + + +### Troubleshooting + +#### Unable to run mksdcard SDK Tool + +When installing Android Studio, if you get the error: + +``` +Unable to run mksdcard SDK tool +``` + +then install the standard C++ library: + +``` +sudo apt-get install lib32stdc++6 +``` + +#### Virtual Device Not Created When Installing Android Studio + +There is a [known bug](https://code.google.com/p/android/issues/detail?id=207563) on some versions +of Android Studio where a virtual device will not be created, even though you selected it in the +installation sequence. You may see this at the end of the installation: + + + +``` +Creating Android virtual device +Unable to create a virtual device: Unable to create Android virtual device +``` + + + +![no virtual device](img/react-native-android-studio-no-virtual-device-windows.png) + + + +If you see this, run `android avd` and create the virtual device manually. + + + +![avd](img/react-native-android-studio-avd-linux.png) + + + +![avd](img/react-native-android-studio-avd-windows.png) + + + +Then select the new device in the AVD Manager window and click `Start...`. + + + +#### Shell Command Unresponsive Exception + +In case you encounter + +``` +Execution failed for task ':app:installDebug'. + com.android.builder.testing.api.DeviceException: com.android.ddmlib.ShellCommandUnresponsiveException +``` + +try downgrading your Gradle version to 1.2.3 in `/android/build.gradle` (https://github.com/facebook/react-native/issues/2720) + + + +## Testing Installation + + + +``` +react-native init AwesomeProject +cd AwesomeProject +react-native run-ios +``` + +> You can also +> [open the `AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project) +> folder in [Nuclide](http://nuclide.io) and +> [run the application](http://nuclide.io/docs/platforms/react-native/#command-line), or open +> `ios/AwesomeProject.xcodeproj` and hit the `Run` button in Xcode. + + + +``` +react-native init AwesomeProject +cd AwesomeProject +react-native run-android +``` + +> You can also +> [open the `AwesomeProject`](http://nuclide.io/docs/quick-start/getting-started/#adding-a-project) +> folder in [Nuclide](http://nuclide.io) and +> [run the application](http://nuclide.io/docs/platforms/react-native/#command-line). + + + +### Modifying Project + +Now that you successfully started the project, let's modify it: + + + +- Open `index.ios.js` in your text editor of choice (e.g. [Nuclide](http://nuclide.io/docs/platforms/react-native/)) and edit some lines. +- Hit ⌘-R in your iOS simulator to reload the app and see your change! + + + +- Open `index.android.js` in your text editor of choice (e.g. [Nuclide](http://nuclide.io/docs/platforms/react-native/)) and edit some lines. +- Press the `R` key twice **OR** open the menu (F2 by default, or ⌘-M in Genymotion) and select Reload JS to see your change! +- Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your app's logs + + + +### That's It + +Congratulations! You've successfully run and modified your first React Native app. + +
+ + + +## Testing Installation + +``` +react-native init AwesomeProject +cd AwesomeProject +react-native run-android +``` + + + +### Troubleshooting Run + +A common issue is that the packager is not started automatically when you run +`react-native run-android`. You can start it manually using: + +``` +cd AwesomeProject +react-native start +``` + + + +Or if you hit a `ERROR Watcher took too long to load` on Windows, try increasing the timeout in [this file](https://github.com/facebook/react-native/blob/5fa33f3d07f8595a188f6fe04d6168a6ede1e721/packager/react-packager/src/DependencyResolver/FileWatcher/index.js#L16) (under your `node_modules/react-native/`). + + + +### Modifying Project + +Now that you successfully started the project, let's modify it: + +- Open `index.android.js` in your text editor of choice (e.g. [Nuclide](http://nuclide.io/docs/platforms/react-native/)) and edit some lines. +- Press the `R` key twice **OR** open the menu (F2 by default, or ctrl-M in the emulator) and select Reload JS to see your change! +- Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to see your app's logs + +### That's It + +Congratulations! You've successfully run and modified your first React Native app. + +
+ + + +## Common Followups + + + +- If you want to run on a physical device, see the [Running on iOS Device page](docs/running-on-device-ios.html#content). + + + +- If you want to run on a physical device, see the [Running on Android Device page](docs/running-on-device-android.html#content). + + + +- If you run into any issues getting started, see the [Troubleshooting page](docs/troubleshooting.html#content). + + + + +## Common Followups + +- If you want to run on a physical device, see the [Running on Android Device page](docs/running-on-device-android.html#content). + +- If you run into any issues getting started, see the [Troubleshooting page](docs/troubleshooting.html#content). diff --git a/versions/v0.26.0/docs/Images.md b/versions/v0.26.0/docs/Images.md new file mode 100644 index 0000000..89c8d44 --- /dev/null +++ b/versions/v0.26.0/docs/Images.md @@ -0,0 +1,140 @@ +--- +id: images +title: Images +layout: docs +category: Guides +permalink: docs/images.html +next: gesture-responder-system +--- + +## Static Image Resources + +As of 0.14 release, React Native provides a unified way of managing images in your iOS and Android apps. To add a static image to your app, place it somewhere in your source code tree and reference it like this: + +```javascript + +``` + +The image name is resolved the same way JS modules are resolved. In the example above the packager will look for `my-icon.png` in the same folder as the component that requires it. Also if you have `my-icon.ios.png` and `my-icon.android.png`, the packager will pick the file depending on the platform you are running on. + +You can also use `@2x`, `@3x`, etc. suffix in the file name to provide images for different screen densities. For example, if you have the following file structure: + +``` +. +├── button.js +└── img + ├── check@2x.png + └── check@3x.png +``` + +And `button.js` code contains + +```javascript + +``` + +Packager will bundle and serve the image corresponding to device's screen density, e.g. on iPhone 5s `check@2x.png` will be used, on Nexus 5 – `check@3x.png`. If there is no image matching the screen density, the closest best option will be selected. + +On Windows, you might need to restart the packager if you add new images to your project. + +Here are some benefits that you get: + +1. Same system on iOS and Android. +2. Images live in the same folder as your JS code. Components are self-contained. +3. No global namespace, i.e. you don't have worry about name collisions. +4. Only the images that are actually used will be packaged into your app. +5. Adding and changing images doesn't require app recompilation, just refresh the simulator as you normally do. +6. The packager knows the image dimensions, no need to duplicate it in the code. +7. Images can be distributed via [npm](https://www.npmjs.com/) packages. + +Note that in order for this to work, the image name in `require` has to be known statically. + +```javascript +// GOOD + + +// BAD +var icon = this.props.active ? 'my-icon-active' : 'my-icon-inactive'; + + +// GOOD +var icon = this.props.active ? require('./my-icon-active.png') : require('./my-icon-inactive.png'); + +``` + +Note that image sources required this way include size (width, height) info for the Image. If you need to scale the image dynamically (i.e. via flex), you may need to manually set { width: undefined, height: undefined } on the style attribute. + +**Available React Native 0.14+**. If you've generated your project with 0.13 or earlier, read this. The new asset system relies on build hooks for [Xcode](https://github.com/facebook/react-native/pull/3523) and [Gradle](https://github.com/facebook/react-native/commit/9dc036d2b99e6233297c55a3490bfc308e34e75f) that are included in new projects generated with `react-native init`. If you generated your projects before that, you'll have to manually add them to your projects to use the new images asset system. See [Upgrading](/react-native/docs/upgrading.html) for instructions on how to do this. + +## Images From Hybrid App's Resources + +If you are building a hybrid app (some UIs in React Native, some UIs in platform code) you can still use images that are already bundled into the app (via Xcode asset catalogs or Android drawable folder): + +```javascript + +``` + +Note that this approach provides no safety checks. It's up to you to guarantee that those images are available in the application. Also you have to specify image dimensions manually. + + +## Network Images + +Many of the images you will display in your app will not be available at compile time, or you will want to load some dynamically to keep the binary size down. Unlike with static resources, *you will need to manually specify the dimensions of your image.* + +```javascript +// GOOD + + +// BAD + +``` + +## Local Filesystem Images + +See [CameraRoll](docs/cameraroll.html) for an example of +using local resources that are outside of `Images.xcassets`. + +### Best Camera Roll Image + +iOS saves multiple sizes for the same image in your Camera Roll, it is very important to pick the one that's as close as possible for performance reasons. You wouldn't want to use the full quality 3264x2448 image as source when displaying a 200x200 thumbnail. If there's an exact match, React Native will pick it, otherwise it's going to use the first one that's at least 50% bigger in order to avoid blur when resizing from a close size. All of this is done by default so you don't have to worry about writing the tedious (and error prone) code to do it yourself. + +## Why Not Automatically Size Everything? + +*In the browser* if you don't give a size to an image, the browser is going to render a 0x0 element, download the image, and then render the image based with the correct size. The big issue with this behavior is that your UI is going to jump all around as images load, this makes for a very bad user experience. + +*In React Native* this behavior is intentionally not implemented. It is more work for the developer to know the dimensions (or aspect ratio) of the remote image in advance, but we believe that it leads to a better user experience. Static images loaded from the app bundle via the `require('./my-icon.png')` syntax *can be automatically sized* because their dimensions are available immediately at the time of mounting. + +For example, the result of `require('./my-icon.png')` might be: + +```javascript +{"__packager_asset":true,"path":"/Users/react/HelloWorld/my-icon.png","uri":"my-icon.png","width":591,"height":573} +``` + +## Source as an object + +In React Native, one interesting decision is that the `src` attribute is named `source` and doesn't take a string but an object with an `uri` attribute. + +```javascript + +``` + +On the infrastructure side, the reason is that it allows us to attach metadata to this object. For example if you are using `require('./my-icon.png')`, then we add information about its actual location and size (don't rely on this fact, it might change in the future!). This is also future proofing, for example we may want to support sprites at some point, instead of outputting `{uri: ...}`, we can output `{uri: ..., crop: {left: 10, top: 50, width: 20, height: 40}}` and transparently support spriting on all the existing call sites. + +On the user side, this lets you annotate the object with useful attributes such as the dimension of the image in order to compute the size it's going to be displayed in. Feel free to use it as your data structure to store more information about your image. + +## Background Image via Nesting + +A common feature request from developers familiar with the web is `background-image`. To handle this use case, simply create a normal `` component and add whatever children to it you would like to layer on top of it. + +```javascript +return ( + + Inside + +); +``` + +## Off-thread Decoding + +Image decoding can take more than a frame-worth of time. This is one of the major source of frame drops on the web because decoding is done in the main thread. In React Native, image decoding is done in a different thread. In practice, you already need to handle the case when the image is not downloaded yet, so displaying the placeholder for a few more frames while it is decoding does not require any code change. diff --git a/versions/v0.26.0/docs/IssueGuidelines.md b/versions/v0.26.0/docs/IssueGuidelines.md new file mode 100644 index 0000000..5f95c91 --- /dev/null +++ b/versions/v0.26.0/docs/IssueGuidelines.md @@ -0,0 +1,48 @@ +## Tips on managing GitHub issues efficiently + +### An issue is a duplicate of another issue +Comment e.g. `@facebook-github-bot duplicate #123`. This will add a comment and close the issue. +Example: [#5977](https://github.com/facebook/react-native/issues/5977) + +### An issue is a question +Questions should absolutely be asked on StackOverflow rather than GitHub. +Comment `@facebook-github-bot stack-overflow` to close the issue. +Examples: [#6378](https://github.com/facebook/react-native/issues/6378), [#6015](https://github.com/facebook/react-native/issues/6015), [#6059](https://github.com/facebook/react-native/issues/6059), [#6062](https://github.com/facebook/react-native/issues/6062). +Feel free to also answer some [SO questions](stackoverflow.com/questions/tagged/react-native), you'll get rep :) + +### An issue is a question that's been answered +Sometimes and issue has been resolved in the comments. +Comment `@facebook-github-bot answered` to close it. +Example: [#6045](https://github.com/facebook/react-native/issues/6045) + +### An issue needs more information +It is impossible to understand and reproduce the issue without more information, e.g. a short code sample, screenshot. +Do the following: +- Explain what additional info you need to understand the issue +- Comment `@facebook-github-bot label Needs more information` +Examples: [#6056](https://github.com/facebook/react-native/issues/6056), [#6008](https://github.com/facebook/react-native/issues/6008), [#5491](https://github.com/facebook/react-native/issues/5491) + +### An issue with label 'Needs more information' has been open for more than a week +Comment mentioning the author asking if they plan to provide the additional information. If they don't come back close the issue using `@facebook-github-bot no-reply`. +Example: [#6056](https://github.com/facebook/react-native/issues/6056) + +### An issue is a valid bug report +Valid bug reports with good repro steps are some of the best issues! Thank the author for finding it, explain that React Native is a community project and **ask them if they would be up for sending a fix**. + +### An issue is a feature request. The feature shouldn't be in the code and don't want to maintain it. +This especially includes **new modules** Facebook doesn't use in production. Explain that those modules should be released to npm separately and that everyone will still be able to use the module super easily that way. + +### An issue is a feature request, you're pretty sure we should maintain this feature as part of RN +This should be rare - adding a new feature means maintaining it. +Tell the author something like: "Pull requests are welcome. In case you're not up for sending a PR, you should post to [Product Pains](https://productpains.com/product/react-native/?tab=top). It has a voting system and if the feature gets upvoted enough it might get implemented." + +### How to add a label +Add any relevant labels, for example 'Android', 'iOS'. +Comment e.g. `@facebook-github-bot label Android` + +### How to reopen a closed issue +For example an issue was closed waiting for the author, the author replied and it turns out this is indeed a bug. +Comment `@facebook-github-bot reopen` + +### What are all the available commands for the bot? +When you mention the bot, it follows the commands defined in [IssueCommands.txt](https://github.com/facebook/react-native/blob/master/bots/IssueCommands.txt). diff --git a/versions/v0.26.0/docs/JavaScriptEnvironment.md b/versions/v0.26.0/docs/JavaScriptEnvironment.md new file mode 100644 index 0000000..988604f --- /dev/null +++ b/versions/v0.26.0/docs/JavaScriptEnvironment.md @@ -0,0 +1,84 @@ +--- +id: javascript-environment +title: JavaScript Environment +layout: docs +category: Guides +permalink: docs/javascript-environment.html +next: navigator-comparison +--- + +## JavaScript Runtime + +When using React Native, you're going to be running your JavaScript code in two environments: + +* On iOS simulators and devices, Android emulators and devices React Native uses [JavaScriptCore](http://trac.webkit.org/wiki/JavaScriptCore) which is the JavaScript engine that powers Safari. On iOS JSC doesn't use JIT due to the absence of writable executable memory in iOS apps. +* When using Chrome debugging, it runs all the JavaScript code within Chrome itself and communicates with native code via WebSocket. So you are using [V8](https://code.google.com/p/v8/). + +While both environments are very similar, you may end up hitting some inconsistencies. We're likely going to experiment with other JS engines in the future, so it's best to avoid relying on specifics of any runtime. + +## JavaScript Syntax Transformers + +Syntax transformers make writing code more enjoyable by allowing you to use new JavaScript syntax without having to wait for support on all interpreters. + +As of version 0.5.0, React Native ships with the [Babel JavaScript compiler](https://babeljs.io). Check [Babel documentation](https://babeljs.io/docs/plugins/#transform-plugins) on its supported transformations for more details. + +Here's a full list of React Native's [enabled transformations](https://github.com/facebook/react-native/blob/master/babel-preset/configs/main.js#L16). + +ES5 + +* Reserved Words: `promise.catch(function() { });` + +ES6 + +* [Arrow functions](http://babeljs.io/docs/learn-es2015/#arrows): ` this.setState({pressed: true})}` +* [Block scoping](https://babeljs.io/docs/learn-es2015/#let-const): `let greeting = 'hi';` +* [Call spread](http://babeljs.io/docs/learn-es2015/#default-rest-spread): `Math.max(...array);` +* [Classes](http://babeljs.io/docs/learn-es2015/#classes): `class C extends React.Component { render() { return ; } }` +* [Constants](https://babeljs.io/docs/learn-es2015/#let-const): `const answer = 42;` +* [Destructuring](http://babeljs.io/docs/learn-es2015/#destructuring): `var {isActive, style} = this.props;` +* [for...of](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...of): `for (var num of [1, 2, 3]) {}` +* [Modules](http://babeljs.io/docs/learn-es2015/#modules): `import React, { Component } from 'react';` +* [Computed Properties](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var key = 'abc'; var obj = {[key]: 10};` +* Object Consise Method: `var obj = { method() { return 10; } };` +* [Object Short Notation](http://babeljs.io/docs/learn-es2015/#enhanced-object-literals): `var name = 'vjeux'; var obj = { name };` +* [Rest Params](https://github.com/sebmarkbage/ecmascript-rest-spread): `function(type, ...args) { }` +* [Template Literals](http://babeljs.io/docs/learn-es2015/#template-strings): ``var who = 'world'; var str = `Hello ${who}`;`` + +ES7 + +* [Object Spread](https://github.com/sebmarkbage/ecmascript-rest-spread): `var extended = { ...obj, a: 10 };` +* [Function Trailing Comma](https://github.com/jeffmo/es-trailing-function-commas): `function f(a, b, c,) { }` +* [Async Functions](https://github.com/tc39/ecmascript-asyncawait): `async function doStuffAsync() { const foo = await doOtherStuffAsync(); }`; + +Specific + +* [JSX](https://facebook.github.io/react/docs/jsx-in-depth.html): `` +* [Flow](http://flowtype.org/): `function foo(x: ?number): string {}` + + +## Polyfills + +Many standards functions are also available on all the supported JavaScript runtimes. + +Browser + +* [console.{log, warn, error, info, trace, table}](https://developer.chrome.com/devtools/docs/console-api) +* [CommonJS require](https://nodejs.org/docs/latest/api/modules.html) +* [XMLHttpRequest, fetch](/react-native/docs/network.html#content) +* [{set, clear}{Timeout, Interval, Immediate}, {request, cancel}AnimationFrame](/react-native/docs/timers.html#content) +* [navigator.geolocation](/react-native/docs/geolocation.html#content) + +ES6 + +* [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) +* String.prototype.{[startsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/startsWith), [endsWith](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/endsWith), [repeat](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeats), [includes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/includes)} +* [Array.from](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/from) +* Array.prototype.{[find](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/find), [findIndex](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/findIndex)} + +ES7 + +* Object.{[entries](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/entries), [values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/values)} + +Specific + +* `__DEV__` diff --git a/versions/v0.26.0/docs/KnownIssues.md b/versions/v0.26.0/docs/KnownIssues.md new file mode 100644 index 0000000..c2ce26b --- /dev/null +++ b/versions/v0.26.0/docs/KnownIssues.md @@ -0,0 +1,73 @@ +--- +id: known-issues +title: Known Issues +layout: docs +category: Guides +permalink: docs/known-issues.html +next: performance +--- + +### Devtools "React" Tab Does Not Work + +It's [currently not possible](https://github.com/facebook/react-devtools/issues/229) to use the "React" tab in the devtools to inspect app widgets. This is due to a change in how the application scripts are evaluated in the devtools plugin; they are now run inside a Web Worker, and the plugin is unaware of this and so unable to communicate properly with React Native. + +However, you can still use the Console feature of the devtools, and debugging JavaScript with breakpoints works too. To use the console, make sure to select the `⚙debuggerWorker.js` entry in the devtools dropdown that by default is set to ``. + +### Missing Android Modules and Views + +The work on React Native for Android started later than React Native for iOS. Most views and modules are now available on Android, with the following exceptions: + +#### Views + +- Maps - Please use Leland Richardson's [react-native-maps](https://github.com/lelandrichardson/react-native-maps) as it is more feature-complete than our internal implementation. + +#### Modules + +- Android Push Notifications - Please use a [3rd party module](https://js.coach/react-native?filters=android&search=gcm). + +### Some props are only supported on one platform + +There are properties that work on one platform only, either because they can inherently only be supported on that platform or because they haven't been implemented on the other platforms yet. All of these are annotated with `@platform` in JS docs and have a small badge next to them on the website. See e.g. [Image](docs/image.html). + +### Platform parity + +There are known cases where the APIs could be made more consistent across iOS and Android: + +- `` and `` on iOS do a similar thing. We might want to unify them to ``. +- `ActivityIndicator` could render a native spinning indicator on both platforms (currently this is done using `ActivityIndicatorIOS` on iOS and `ProgressBarAndroid` on Android). +- `ProgressBar` could render a horizontal progress bar on both platforms (on iOS this is `ProgressViewIOS`, on Android it's `ProgressBarAndroid`). + +### The `overflow` style property defaults to `hidden` and cannot be changed on Android + +This is a result of how Android rendering works. This feature is not being worked on as it would be a significant undertaking and there are many more important tasks. + +Another issue with `overflow: 'hidden'` on Android: a view is not clipped by the parent's `borderRadius` even if the parent has `overflow: 'hidden'` enabled – the corners of the inner view will be visible outside of the rounded corners. This is only on Android; it works as expected on iOS. See a [demo of the bug](https://rnplay.org/apps/BlGjdQ) and the [corresponding issue](https://github.com/facebook/react-native/issues/3198). + +### View shadows + +The `shadow*` [view styles](docs/view.html#style) apply on iOS, and the `elevation` view prop is available on Android. Setting `elevation` on Android is equivalent to using the [native elevation API](https://developer.android.com/training/material/shadows-clipping.html#Elevation), and has the same limitations (most significantly, it only works on Android 5.0+). Setting `elevation` on Android also affects the z-order for overlapping views. + +### Android M permissions + +The open source version of React Native doesn't yet support the [Android M permission model](http://developer.android.com/training/permissions/requesting.html). + +### Layout-only nodes on Android + +An optimization feature of the Android version of React Native is for views which only contribute to the layout to not have a native view, only their layout properties are propagated to their children views. This optimization is to provide stability in deep view hierarchies for React Native and is therefore enabled by default. Should you depend on a view being present or internal tests incorrectly detect a view is layout only it will be necessary to turn off this behavior. To do this, set `collapsable` to false as in this example: +``` + + ... + +``` + +### Memory issues with PNG images + +React Native Android depends on [Fresco](https://github.com/facebook/fresco) for loading and displaying images. Currently we have disabled downsampling because it is experimental, so you may run into memory issues when loading large PNG images. + +### react-native init hangs + +Try running `react-native init` with `--verbose` and see [#2797](https://github.com/facebook/react-native/issues/2797) for common causes. + +### Text Input Border + +The text input has by default a border at the bottom of its view. This border has its padding set by the background image provided by the system, and it cannot be changed. Solutions to avoid this is to either not set height explicitly, case in which the system will take care of displaying the border in the correct position, or to not display the border by setting underlineColorAndroid to transparent. diff --git a/versions/v0.26.0/docs/LinkingLibraries.md b/versions/v0.26.0/docs/LinkingLibraries.md new file mode 100644 index 0000000..0ce0849 --- /dev/null +++ b/versions/v0.26.0/docs/LinkingLibraries.md @@ -0,0 +1,100 @@ +--- +id: linking-libraries-ios +title: Linking Libraries +layout: docs +category: Guides (iOS) +permalink: docs/linking-libraries-ios.html +next: running-on-device-ios +--- + +Not every app uses all the native capabilities, and including the code to support +all those features would impact the binary size... But we still want to make it +easy to add these features whenever you need them. + +With that in mind we exposed many of these features as independent static libraries. + +For most of the libs it will be as simple as dragging two files, sometimes a third +step will be necessary, but no more than that. + +_All the libraries we ship with React Native live on the `Libraries` folder in +the root of the repository. Some of them are pure JavaScript, and you only need +to `require` it. Other libraries also rely on some native code, in that case +you'll have to add these files to your app, otherwise the app will throw an +error as soon as you try to use the library._ + +## Here the few steps to link your libraries that contain native code + +### Automatic linking + +"[rnpm](http://github.com/rnpm/rnpm)" is a community project that allows linking of native dependencies automatically: + +#### Step 1 + +Install `rnpm`: +```bash +$ npm install rnpm -g +``` + +**Note:** _`rnpm` requires `node` version 4.1 or higher_ + +#### Step 2 + +Install a library with native dependencies: +```bash +$ npm install --save +``` + +**Note:** _`--save` or `--save-dev` flag is very important for this step. `rnpm` will link +your libs based on `dependencies` and `devDependencies` in your `package.json` file._ + +#### Step 3 + +Link your native dependencies: +```bash +$ rnpm link +``` + +Done! All libraries with a native dependencies should be successfully linked to your iOS/Android project. + +### Manual linking + +#### Step 1 + +If the library has native code, there must be a `.xcodeproj` file inside it's +folder. +Drag this file to your project on Xcode (usually under the `Libraries` group +on Xcode); + +![](img/AddToLibraries.png) + +#### Step 2 + +Click on your main project file (the one that represents the `.xcodeproj`) +select `Build Phases` and drag the static library from the `Products` folder +inside the Library you are importing to `Link Binary With Libraries` + +![](img/AddToBuildPhases.png) + +#### Step 3 + +Not every library will need this step, what you need to consider is: + +_Do I need to know the contents of the library at compile time?_ + +What that means is, are you using this library on the native side or only in +JavaScript? If you are only using it in JavaScript, you are good to go! + +This step is not necessary for libraries that we ship with React Native with the +exception of `PushNotificationIOS` and `LinkingIOS`. + +In the case of the `PushNotificationIOS` for example, you have to call a method +on the library from your `AppDelegate` every time a new push notification is +received. + +For that we need to know the library's headers. To achieve that you have to go +to your project's file, select `Build Settings` and search for `Header Search +Paths`. There you should include the path to your library (if it has relevant +files on subdirectories remember to make it `recursive`, like `React` on the +example). + +![](img/AddToSearchPaths.png) diff --git a/versions/v0.26.0/docs/MoviesExample.json b/versions/v0.26.0/docs/MoviesExample.json new file mode 100644 index 0000000..da7c333 --- /dev/null +++ b/versions/v0.26.0/docs/MoviesExample.json @@ -0,0 +1 @@ +{"total":24,"movies":[{"id":"11494","title":"Chain Reaction","year":1996,"mpaa_rating":"PG-13","runtime":106,"release_dates":{"theater":"1996-08-02","dvd":"2001-05-22"},"ratings":{"critics_rating":"Rotten","critics_score":16,"audience_rating":"Spilled","audience_score":27},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg","profile":"http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg","detailed":"http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg","original":"http://resizing.flixster.com/DeLpPTAwX3O2LszOpeaMHjbzuAw=/53x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/16/47/11164719_ori.jpg"},"abridged_cast":[{"name":"Keanu Reeves","id":"162654049","characters":["Eddie Kasalivich"]},{"name":"Morgan Freeman","id":"162652224","characters":["Paul Shannon"]},{"name":"Rachel Weisz","id":"162653682","characters":["Dr. Lily Sinclair"]},{"name":"Fred Ward","id":"162667867","characters":["Agt. Leon Ford"]},{"name":"Kevin Dunn","id":"162664658","characters":["Agt. Doyle"]}],"alternate_ids":{"imdb":"0115857"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/11494.json","alternate":"http://www.rottentomatoes.com/m/1072457-chain_reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/11494/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/11494/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/11494/similar.json"}},{"id":"770920361","title":"React! A Woman's Guide to Safety and Basic Self-Defense","year":1996,"mpaa_rating":"Unrated","runtime":"","release_dates":{"dvd":"1996-07-29"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/m7G-weBZPYfnoqSiF59LIPPYOuM=/44x81/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/47/10974721_ori.jpg","profile":"http://resizing.flixster.com/m7G-weBZPYfnoqSiF59LIPPYOuM=/44x81/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/47/10974721_ori.jpg","detailed":"http://resizing.flixster.com/m7G-weBZPYfnoqSiF59LIPPYOuM=/44x81/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/47/10974721_ori.jpg","original":"http://resizing.flixster.com/m7G-weBZPYfnoqSiF59LIPPYOuM=/44x81/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/47/10974721_ori.jpg"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770920361.json","alternate":"http://www.rottentomatoes.com/m/react_a_womans_guide_to_safety_and_basic_selfdefense/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770920361/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770920361/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770920361/similar.json"}},{"id":"770819043","title":"Reaction","year":"","mpaa_rating":"Unrated","runtime":13,"release_dates":{},"ratings":{"critics_score":-1,"audience_score":100},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770819043.json","alternate":"http://www.rottentomatoes.com/m/reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770819043/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770819043/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770819043/similar.json"}},{"id":"771364188","title":"Reactor","year":2013,"mpaa_rating":"Unrated","runtime":34,"release_dates":{},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[],"alternate_ids":{"imdb":"2828874"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/771364188.json","alternate":"http://www.rottentomatoes.com/m/reactor_2013/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/771364188/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/771364188/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/771364188/similar.json"}},{"id":"391535485","title":"Chain Reaction (House of Blood)","year":2006,"mpaa_rating":"NC-17","runtime":105,"release_dates":{"dvd":"2006-10-03"},"ratings":{"critics_score":-1,"audience_rating":"Spilled","audience_score":22},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/Q8IBqX3b-nhEAEYokJ_aH6jO6lE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941373_ori.jpg","profile":"http://resizing.flixster.com/Q8IBqX3b-nhEAEYokJ_aH6jO6lE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941373_ori.jpg","detailed":"http://resizing.flixster.com/Q8IBqX3b-nhEAEYokJ_aH6jO6lE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941373_ori.jpg","original":"http://resizing.flixster.com/Q8IBqX3b-nhEAEYokJ_aH6jO6lE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941373_ori.jpg"},"abridged_cast":[{"name":"Christopher Kriesa","id":"391535486"},{"name":"Jurgen Prochnow","id":"162693957"},{"name":"Dan van Husen","id":"391535498"},{"name":"Mehmet Yilmaz","id":"391535499"},{"name":"Lisa Sachsenweger","id":"770770690"}],"alternate_ids":{"imdb":"0460742"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/391535485.json","alternate":"http://www.rottentomatoes.com/m/house_of_blood/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/391535485/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/391535485/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/391535485/similar.json"}},{"id":"17962","title":"The Chain Reaction","year":1995,"mpaa_rating":"Unrated","runtime":72,"release_dates":{"dvd":"1999-12-14"},"ratings":{"critics_score":-1,"audience_rating":"Spilled","audience_score":33},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/e3AKmyWuh1Wr4qMAM_vQ0vtN9AA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941368_ori.jpg","profile":"http://resizing.flixster.com/e3AKmyWuh1Wr4qMAM_vQ0vtN9AA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941368_ori.jpg","detailed":"http://resizing.flixster.com/e3AKmyWuh1Wr4qMAM_vQ0vtN9AA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941368_ori.jpg","original":"http://resizing.flixster.com/e3AKmyWuh1Wr4qMAM_vQ0vtN9AA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/10/94/13/10941368_ori.jpg"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/17962.json","alternate":"http://www.rottentomatoes.com/m/the-chain-reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/17962/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/17962/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/17962/similar.json"}},{"id":"23108","title":"The Fifth Reaction","year":2003,"mpaa_rating":"Unrated","runtime":106,"release_dates":{"theater":"2003-01-01","dvd":"2005-11-22"},"ratings":{"critics_score":-1,"audience_rating":"Upright","audience_score":92},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/1FxtmlxCqRb0EPdHFrFDGpZ45CE=/54x75/dkpu1ddg7pbsk.cloudfront.net/movie/31/16/311623_ori.jpg","profile":"http://resizing.flixster.com/1FxtmlxCqRb0EPdHFrFDGpZ45CE=/54x75/dkpu1ddg7pbsk.cloudfront.net/movie/31/16/311623_ori.jpg","detailed":"http://resizing.flixster.com/1FxtmlxCqRb0EPdHFrFDGpZ45CE=/54x75/dkpu1ddg7pbsk.cloudfront.net/movie/31/16/311623_ori.jpg","original":"http://resizing.flixster.com/1FxtmlxCqRb0EPdHFrFDGpZ45CE=/54x75/dkpu1ddg7pbsk.cloudfront.net/movie/31/16/311623_ori.jpg"},"abridged_cast":[{"name":"Niki Karimi","id":"405588976"},{"name":"Jamshid Hashempour","id":"771029092"},{"name":"Merila Zareie","id":"770833361"},{"name":"Shahab Hosseini","id":"770830873"},{"name":"Soghra Abisi","id":"771029093"}],"alternate_ids":{"imdb":"0386843"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/23108.json","alternate":"http://www.rottentomatoes.com/m/the-fifth-reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/23108/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/23108/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/23108/similar.json"}},{"id":"770924192","title":"Chain Reaction","year":1995,"mpaa_rating":"Unrated","runtime":72,"release_dates":{},"ratings":{"critics_score":-1,"audience_score":100},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/yFgYWViboAAdHG99EoF3VULEblc=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/67/10976773_ori.jpg","profile":"http://resizing.flixster.com/yFgYWViboAAdHG99EoF3VULEblc=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/67/10976773_ori.jpg","detailed":"http://resizing.flixster.com/yFgYWViboAAdHG99EoF3VULEblc=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/67/10976773_ori.jpg","original":"http://resizing.flixster.com/yFgYWViboAAdHG99EoF3VULEblc=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/10/97/67/10976773_ori.jpg"},"abridged_cast":[{"name":"Johan Paulik","id":"364601611"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770924192.json","alternate":"http://www.rottentomatoes.com/m/chain_reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770924192/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770924192/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770924192/similar.json"}},{"id":"770795709","title":"The Chain Reaction (Nuclear Run)","year":1980,"mpaa_rating":"R","runtime":87,"release_dates":{"theater":"1980-09-25"},"ratings":{"critics_score":-1,"audience_rating":"Spilled","audience_score":29},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[{"name":"Ross Thompson","id":"770816985","characters":["Heinrich"]},{"name":"Steve Bisley","id":"391393048","characters":["Larry"]},{"name":"David Bracks","id":"770932042","characters":["Spray painter"]},{"name":"Tim Burns","id":"391393049","characters":["Survey driver"]},{"name":"Ralph Cotterill","id":"770686983","characters":["Gray"]}],"alternate_ids":{"imdb":"0080513"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770795709.json","alternate":"http://www.rottentomatoes.com/m/1003826-chain_reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770795709/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770795709/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770795709/similar.json"}},{"id":"770815970","title":"A Chemical Reaction","year":2009,"mpaa_rating":"Unrated","runtime":79,"release_dates":{"theater":"2009-01-01"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/d7ZWFBXpcaqXbOJ-W57_b8B2TR0=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/10/92/85/10928519_ori.jpg","profile":"http://resizing.flixster.com/d7ZWFBXpcaqXbOJ-W57_b8B2TR0=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/10/92/85/10928519_ori.jpg","detailed":"http://resizing.flixster.com/d7ZWFBXpcaqXbOJ-W57_b8B2TR0=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/10/92/85/10928519_ori.jpg","original":"http://resizing.flixster.com/d7ZWFBXpcaqXbOJ-W57_b8B2TR0=/54x80/dkpu1ddg7pbsk.cloudfront.net/movie/10/92/85/10928519_ori.jpg"},"abridged_cast":[{"name":"Paul Tukey","id":"770801638"}],"alternate_ids":{"imdb":"1469852"},"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770815970.json","alternate":"http://www.rottentomatoes.com/m/a-chemical-reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770815970/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770815970/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770815970/similar.json"}},{"id":"770827338","title":"Juno Reactor: Live in Tokyo","year":2002,"mpaa_rating":"Unrated","runtime":"","release_dates":{"theater":"2002-12-31","dvd":"2005-06-21"},"ratings":{"critics_score":-1,"audience_rating":"Spilled","audience_score":40},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[{"name":"Juno Reactor","id":"770751447"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770827338.json","alternate":"http://www.rottentomatoes.com/m/juno-reactor-live-in-tokyo/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770827338/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770827338/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770827338/similar.json"}},{"id":"771004226","title":"Historic WWII Shell Shock Film: Military Psychology & War Combat Stress Reaction for Soldiers","year":2007,"mpaa_rating":"Unrated","runtime":33,"release_dates":{"dvd":"2007-02-01"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/771004226.json","alternate":"http://www.rottentomatoes.com/m/historic_wwii_shell_shock_film_military_psychology_and_war_combat_stress_reaction_for_soldiers/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/771004226/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/771004226/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/771004226/similar.json"}},{"id":"770978318","title":"Fifth Reaction","year":2003,"mpaa_rating":"Unrated","runtime":107,"release_dates":{"dvd":"2005-11-22"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/kTMk0zw4RXlpYGytEtnYgNQv-Uc=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/02/55/11025581_ori.jpg","profile":"http://resizing.flixster.com/kTMk0zw4RXlpYGytEtnYgNQv-Uc=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/02/55/11025581_ori.jpg","detailed":"http://resizing.flixster.com/kTMk0zw4RXlpYGytEtnYgNQv-Uc=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/02/55/11025581_ori.jpg","original":"http://resizing.flixster.com/kTMk0zw4RXlpYGytEtnYgNQv-Uc=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/02/55/11025581_ori.jpg"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770978318.json","alternate":"http://www.rottentomatoes.com/m/fifth_reaction/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770978318/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770978318/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770978318/similar.json"}},{"id":"771006274","title":"Chain Reaction","year":2008,"mpaa_rating":"Unrated","runtime":90,"release_dates":{"dvd":"2008-01-22"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/2sFwWwxvTzwM5bT9qGm78oZjpBA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/05/21/11052126_ori.jpg","profile":"http://resizing.flixster.com/2sFwWwxvTzwM5bT9qGm78oZjpBA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/05/21/11052126_ori.jpg","detailed":"http://resizing.flixster.com/2sFwWwxvTzwM5bT9qGm78oZjpBA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/05/21/11052126_ori.jpg","original":"http://resizing.flixster.com/2sFwWwxvTzwM5bT9qGm78oZjpBA=/54x77/dkpu1ddg7pbsk.cloudfront.net/movie/11/05/21/11052126_ori.jpg"},"abridged_cast":[{"name":"Rick Ross","id":"770761752","characters":["Pac Man"]},{"name":"Mr. Bones","id":"771060841","characters":["Chase"]},{"name":"Total Kaos","id":"771060844","characters":["Paul"]},{"name":"M Beezy","id":"771060843","characters":["Reno"]},{"name":"Sho nuff","id":"771060842","characters":["Tee"]}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/771006274.json","alternate":"http://www.rottentomatoes.com/m/chain_reaction-2008/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/771006274/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/771006274/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/771006274/similar.json"}},{"id":"770879444","title":"Deadly Reactor","year":1989,"mpaa_rating":"Unrated","runtime":88,"release_dates":{},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[{"name":"David Heavener","id":"162767691","characters":["Cody"]},{"name":"Stuart Whitman","id":"162656122","characters":["Duke"]},{"name":"Darwyn Swalve","id":"770883640","characters":["Hog"]},{"name":"Allyson Davis","id":"770880183"},{"name":"Barbara Kerek","id":"770935570"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770879444.json","alternate":"http://www.rottentomatoes.com/m/deadly_reactor/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770879444/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770879444/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770879444/similar.json"}},{"id":"770953999","title":"Juno Reactor - Live in Tokyo","year":2002,"mpaa_rating":"Unrated","runtime":"","release_dates":{"dvd":"2002-10-22"},"ratings":{"critics_score":-1,"audience_rating":"Upright","audience_score":100},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/Yttvb_8gXph4S7iJCiLQFbZ2s7Q=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/11/00/22/11002233_ori.jpg","profile":"http://resizing.flixster.com/Yttvb_8gXph4S7iJCiLQFbZ2s7Q=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/11/00/22/11002233_ori.jpg","detailed":"http://resizing.flixster.com/Yttvb_8gXph4S7iJCiLQFbZ2s7Q=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/11/00/22/11002233_ori.jpg","original":"http://resizing.flixster.com/Yttvb_8gXph4S7iJCiLQFbZ2s7Q=/54x74/dkpu1ddg7pbsk.cloudfront.net/movie/11/00/22/11002233_ori.jpg"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770953999.json","alternate":"http://www.rottentomatoes.com/m/juno_reactor_live_in_tokyo/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770953999/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770953999/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770953999/similar.json"}},{"id":"770959249","title":"Neil Young & Crazy Horse - Re-Ac-Tor","year":1981,"mpaa_rating":"Unrated","runtime":"","release_dates":{"dvd":"2003-09-23"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770959249.json","alternate":"http://www.rottentomatoes.com/m/neil_young_and_crazy_horse_reactor/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770959249/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770959249/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770959249/similar.json"}},{"id":"770988328","title":"Standard Deviants - Organic Chemistry Module 14: Electrophilic Reactions III","year":2004,"mpaa_rating":"Unrated","runtime":26,"release_dates":{"dvd":"2004-12-21"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/cQUqzav2aBRwjf6dSJTkUKGIEZ4=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034874_ori.jpg","profile":"http://resizing.flixster.com/cQUqzav2aBRwjf6dSJTkUKGIEZ4=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034874_ori.jpg","detailed":"http://resizing.flixster.com/cQUqzav2aBRwjf6dSJTkUKGIEZ4=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034874_ori.jpg","original":"http://resizing.flixster.com/cQUqzav2aBRwjf6dSJTkUKGIEZ4=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034874_ori.jpg"},"abridged_cast":[{"name":"Standard Deviants","id":"770893547"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988328.json","alternate":"http://www.rottentomatoes.com/m/standard_deviants_organic_chemistry_module_14_electrophilic_reactions_iii/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988328/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988328/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988328/similar.json"}},{"id":"770988330","title":"Standard Deviants - Organic Chemistry Module 13: Electrophilic Reactions II","year":2004,"mpaa_rating":"Unrated","runtime":26,"release_dates":{"dvd":"2004-12-21"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/6R33pXKxhjyiO-hjSHvYZ1r_EGk=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034876_ori.jpg","profile":"http://resizing.flixster.com/6R33pXKxhjyiO-hjSHvYZ1r_EGk=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034876_ori.jpg","detailed":"http://resizing.flixster.com/6R33pXKxhjyiO-hjSHvYZ1r_EGk=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034876_ori.jpg","original":"http://resizing.flixster.com/6R33pXKxhjyiO-hjSHvYZ1r_EGk=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034876_ori.jpg"},"abridged_cast":[{"name":"Standard Deviants","id":"770893547"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988330.json","alternate":"http://www.rottentomatoes.com/m/standard_deviants_organic_chemistry_module_13_electrophilic_reactions_ii/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988330/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988330/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988330/similar.json"}},{"id":"770988332","title":"Standard Deviants - Organic Chemistry Module 11: Electrophilic Reactions I","year":2004,"mpaa_rating":"Unrated","runtime":26,"release_dates":{"dvd":"2004-12-21"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/z770YngyfBvk2oid95j5ppFpaNE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034878_ori.jpg","profile":"http://resizing.flixster.com/z770YngyfBvk2oid95j5ppFpaNE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034878_ori.jpg","detailed":"http://resizing.flixster.com/z770YngyfBvk2oid95j5ppFpaNE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034878_ori.jpg","original":"http://resizing.flixster.com/z770YngyfBvk2oid95j5ppFpaNE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034878_ori.jpg"},"abridged_cast":[{"name":"Standard Deviants","id":"770893547"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988332.json","alternate":"http://www.rottentomatoes.com/m/standard_deviants_organic_chemistry_module_11_electrophilic_reactions_i/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988332/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988332/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988332/similar.json"}},{"id":"770988334","title":"Standard Deviants - Organic Chemistry Module 9: Reaction Energy Diagrams","year":2004,"mpaa_rating":"Unrated","runtime":26,"release_dates":{"dvd":"2004-12-21"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/FtChYDmsGfsjWUVm-ThAwPv10nE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034880_ori.jpg","profile":"http://resizing.flixster.com/FtChYDmsGfsjWUVm-ThAwPv10nE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034880_ori.jpg","detailed":"http://resizing.flixster.com/FtChYDmsGfsjWUVm-ThAwPv10nE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034880_ori.jpg","original":"http://resizing.flixster.com/FtChYDmsGfsjWUVm-ThAwPv10nE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034880_ori.jpg"},"abridged_cast":[{"name":"Standard Deviants","id":"770893547"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988334.json","alternate":"http://www.rottentomatoes.com/m/standard_deviants_organic_chemistry_module_9_reaction_energy_diagrams/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988334/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988334/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988334/similar.json"}},{"id":"770988338","title":"Standard Deviants - Organic Chemistry Module 7: Addition Reactions","year":2004,"mpaa_rating":"Unrated","runtime":26,"release_dates":{"dvd":"2004-12-21"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://resizing.flixster.com/noxh6ykIwPcnBfhtSZY3d3yADjE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034884_ori.jpg","profile":"http://resizing.flixster.com/noxh6ykIwPcnBfhtSZY3d3yADjE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034884_ori.jpg","detailed":"http://resizing.flixster.com/noxh6ykIwPcnBfhtSZY3d3yADjE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034884_ori.jpg","original":"http://resizing.flixster.com/noxh6ykIwPcnBfhtSZY3d3yADjE=/54x78/dkpu1ddg7pbsk.cloudfront.net/movie/11/03/48/11034884_ori.jpg"},"abridged_cast":[{"name":"Standard Deviants","id":"770893547"}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988338.json","alternate":"http://www.rottentomatoes.com/m/standard_deviants_organic_chemistry_module_7_addition_reactions/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988338/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988338/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/770988338/similar.json"}},{"id":"771013389","title":"Burn: Bosu Ultimate Reactive Neuromuscular Training","year":2008,"mpaa_rating":"Unrated","runtime":"","release_dates":{"dvd":"2008-07-22"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/771013389.json","alternate":"http://www.rottentomatoes.com/m/burn_bosu_ultimate_reactive_neuromuscular_training/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/771013389/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/771013389/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/771013389/similar.json"}},{"id":"771041962","title":"Bill Nye the Science Guy: Chemical Reactions","year":1994,"mpaa_rating":"Unrated","runtime":"","release_dates":{"dvd":"2009-07-07"},"ratings":{"critics_score":-1,"audience_score":0},"synopsis":"","posters":{"thumbnail":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","profile":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","detailed":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif","original":"http://d3biamo577v4eu.cloudfront.net/static/images/redesign/poster_default_thumb.gif"},"abridged_cast":[],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies/771041962.json","alternate":"http://www.rottentomatoes.com/m/bill_nye_the_science_guy_chemical_reactions/","cast":"http://api.rottentomatoes.com/api/public/v1.0/movies/771041962/cast.json","reviews":"http://api.rottentomatoes.com/api/public/v1.0/movies/771041962/reviews.json","similar":"http://api.rottentomatoes.com/api/public/v1.0/movies/771041962/similar.json"}}],"links":{"self":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q=react&page_limit=30&page=1"},"link_template":"http://api.rottentomatoes.com/api/public/v1.0/movies.json?q={search-term}&page_limit={results-per-page}&page={page-number}"} diff --git a/versions/v0.26.0/docs/NativeComponentsAndroid.md b/versions/v0.26.0/docs/NativeComponentsAndroid.md new file mode 100644 index 0000000..b9e0142 --- /dev/null +++ b/versions/v0.26.0/docs/NativeComponentsAndroid.md @@ -0,0 +1,177 @@ +--- +id: native-components-android +title: Native UI Components +layout: docs +category: Guides (Android) +permalink: docs/native-components-android.html +next: running-on-device-android +--- + +There are tons of native UI widgets out there ready to be used in the latest apps - some of them are part of the platform, others are available as third-party libraries, and still more might be in use in your very own portfolio. React Native has several of the most critical platform components already wrapped, like `ScrollView` and `TextInput`, but not all of them, and certainly not ones you might have written yourself for a previous app. Fortunately, it's quite easy to wrap up these existing components for seamless integration with your React Native application. + +Like the native module guide, this too is a more advanced guide that assumes you are somewhat familiar with Android SDK programming. This guide will show you how to build a native UI component, walking you through the implementation of a subset of the existing `ImageView `component available in the core React Native library. + +## ImageView example + +For this example we are going to walk through the implementation requirements to allow the use of ImageViews in JavaScript. + +Native views are created and manipulated by extending `ViewManager` or more commonly `SimpleViewManager` . A `SimpleViewManager` is convenient in this case because it applies common properties such as background color, opacity, and Flexbox layout. + +These subclasses are essentially singletons - only one instance of each is created by the bridge. They vend native views to the `NativeViewHierarchyManager`, which delegates back to them to set and update the properties of the views as necessary. The `ViewManagers` are also typically the delegates for the views, sending events back to JavaScript via the bridge. + +Vending a view is simple: + +1. Create the ViewManager subclass. +2. Implement the `createViewInstance` method +3. Expose view property setters using `@ReactProp` (or `@ReactPropGroup`) annotation +4. Register the manager in `createViewManagers` of the applications package. +5. Implement the JavaScript module + +## 1. Create the `ViewManager` subclass + +In this example we create view manager class `ReactImageManager` that extends `SimpleViewManager` of type `ReactImageView`. `ReactImageView` is the type of object managed by the manager, this will be the custom native view. Name returned by `getName` is used to reference the native view type from JavaScript. + +```java +... + +public class ReactImageManager extends SimpleViewManager { + + public static final String REACT_CLASS = "RCTImageView"; + + @Override + public String getName() { + return REACT_CLASS; + } +``` + +## 2. Implement method `createViewInstance` + +Views are created in the `createViewInstance` method, the view should initialize itself in its default state, any properties will be set via a follow up call to `updateView.` + +```java + @Override + public ReactImageView createViewInstance(ThemedReactContext context) { + return new ReactImageView(context, Fresco.newDraweeControllerBuilder(), mCallerContext); + } +``` + +## 3. Expose view property setters using `@ReactProp` (or `@ReactPropGroup`) annotation + +Properties that are to be reflected in JavaScript needs to be exposed as setter method annotated with `@ReactProp` (or `@ReactPropGroup`). Setter method should take view to be updated (of the current view type) as a first argument and property value as a second argument. Setter should be declared as a `void` method and should be `public`. Property type sent to JS is determined automatically based on the type of value argument of the setter. The following type of values are currently supported: `boolean`, `int`, `float`, `double`, `String`, `Boolean`, `Integer`, `ReadableArray`, `ReadableMap`. + +Annotation `@ReactProp` has one obligatory argument `name` of type `String`. Name assigned to the `@ReactProp` annotation linked to the setter method is used to reference the property on JS side. + +Except from `name`, `@ReactProp` annotation may take following optional arguments: `defaultBoolean`, `defaultInt`, `defaultFloat`. Those arguments should be of the corresponding primitive type (accordingly `boolean`, `int`, `float`) and the value provided will be passed to the setter method in case when the property that the setter is referencing has been removed from the component. Note that "default" values are only provided for primitive types, in case when setter is of some complex type, `null` will be provided as a default value in case when corresponding property gets removed. + +Setter declaration requirements for methods annotated with `@ReactPropGroup` are different than for `@ReactProp`, please refer to the `@ReactPropGroup` annotation class docs for more information about it. + +**IMPORTANT!** in ReactJS updating the property value will result in setter method call. Note that one of the ways we can update component is by removing properties that has been set before. In that case setter method will be called as well to notify view manager that property has changed. In that case "default" value will be provided (for primitive types "default" can value can be specified using `defaultBoolean`, `defaultFloat`, etc. arguments of `@ReactProp` annotation, for complex types setter will be called with value set to `null`). + +```java + @ReactProp(name = "src") + public void setSrc(ReactImageView view, @Nullable String src) { + view.setSource(src); + } + + @ReactProp(name = "borderRadius", defaultFloat = 0f) + public void setBorderRadius(ReactImageView view, float borderRadius) { + view.setBorderRadius(borderRadius); + } + + @ReactProp(name = ViewProps.RESIZE_MODE) + public void setResizeMode(ReactImageView view, @Nullable String resizeMode) { + view.setScaleType(ImageResizeMode.toScaleType(resizeMode)); + } +``` + +## 4. Register the `ViewManager` + +The final Java step is to register the ViewManager to the application, this happens in a similar way to [Native Modules](docs/native-modules-android.html), via the applications package member function `createViewManagers.` + +```java + @Override + public List createViewManagers( + ReactApplicationContext reactContext) { + return Arrays.asList( + new ReactImageManager() + ); + } +``` + +## 5. Implement the JavaScript module + +The very final step is to create the JavaScript module that defines the interface layer between Java and JavaScript for the users of your new view. Much of the effort is handled by internal React code in Java and JavaScript and all that is left for you is to describe the `propTypes`. + +```js +// ImageView.js + +import { PropTypes } from 'react'; +import { requireNativeComponent, View } from 'react-native'; + +var iface = { + name: 'ImageView', + propTypes: { + src: PropTypes.string, + borderRadius: PropTypes.number, + resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']), + ...View.propTypes // include the default view properties + }, +}; + +module.exports = requireNativeComponent('RCTImageView', iface); +``` + +`requireNativeComponent` commonly takes two parameters, the first is the name of the native view and the second is an object that describes the component interface. The component interface should declare a friendly `name` for use in debug messages and must declare the `propTypes` reflected by the Native View. The `propTypes` are used for checking the validity of a user's use of the native view. Note that if you need your JavaScript component to do more than just specify a name and propTypes, like do custom event handling, you can wrap the native component in a normal react component. In that case, you want to pass in the wrapper component instead of `iface` to `requireNativeComponent`. This is illustrated in the `MyCustomView` example below. + +# Events + +So now we know how to expose native view components that we can control easily from JS, but how do we deal with events from the user, like pinch-zooms or panning? When a native event occurs the native code should issue an event to the JavaScript representation of the View, and the two views are linked with the value returned from the `getId()` method. + +```java +class MyCustomView extends View { + ... + public void onReceiveNativeEvent() { + WritableMap event = Arguments.createMap(); + event.putString("message", "MyMessage"); + ReactContext reactContext = (ReactContext)getContext(); + reactContext.getJSModule(RCTEventEmitter.class).receiveEvent( + getId(), + "topChange", + event); + } +} +``` + +The event name `topChange` maps to the `onChange` callback prop in JavaScript (mappings are in `UIManagerModuleConstants.java`). This callback is invoked with the raw event, which we typically process in the wrapper component to make a simpler API: + +```js +// MyCustomView.js + +class MyCustomView extends React.Component { + constructor() { + this._onChange = this._onChange.bind(this); + } + _onChange(event: Event) { + if (!this.props.onChangeMessage) { + return; + } + this.props.onChangeMessage(event.nativeEvent.message); + } + render() { + return ; + } +} +MyCustomView.propTypes = { + /** + * Callback that is called continuously when the user is dragging the map. + */ + onChangeMessage: React.PropTypes.func, + ... +}; + +var RCTMyCustomView = requireNativeComponent(`RCTMyCustomView`, MyCustomView, { + nativeOnly: {onChange: true} +}); +``` + +Note the use of `nativeOnly` above. Sometimes you'll have some special properties that you need to expose for the native component, but don't actually want them as part of the API for the associated React component. For example, `Switch` has a custom `onChange` handler for the raw native event, and exposes an `onValueChange` handler property that is invoked with just the boolean value rather than the raw event (similar to `onChangeMessage` in the example above). Since you don't want these native only properties to be part of the API, you don't want to put them in `propTypes`, but if you don't you'll get an error. The solution is simply to call them out via the `nativeOnly` option. diff --git a/versions/v0.26.0/docs/NativeComponentsIOS.md b/versions/v0.26.0/docs/NativeComponentsIOS.md new file mode 100644 index 0000000..49ef64e --- /dev/null +++ b/versions/v0.26.0/docs/NativeComponentsIOS.md @@ -0,0 +1,379 @@ +--- +id: native-components-ios +title: Native UI Components +layout: docs +category: Guides (iOS) +permalink: docs/native-components-ios.html +next: linking-libraries-ios +--- + +There are tons of native UI widgets out there ready to be used in the latest apps - some of them are part of the platform, others are available as third-party libraries, and still more might be in use in your very own portfolio. React Native has several of the most critical platform components already wrapped, like `ScrollView` and `TextInput`, but not all of them, and certainly not ones you might have written yourself for a previous app. Fortunately, it's quite easy to wrap up these existing components for seamless integration with your React Native application. + +Like the native module guide, this too is a more advanced guide that assumes you are somewhat familiar with iOS programming. This guide will show you how to build a native UI component, walking you through the implementation of a subset of the existing `MapView` component available in the core React Native library. + +## iOS MapView example + +Let's say we want to add an interactive Map to our app - might as well use [`MKMapView`](https://developer.apple.com/library/prerelease/mac/documentation/MapKit/Reference/MKMapView_Class/index.html), we just need to make it usable from JavaScript. + +Native views are created and manipulated by subclasses of `RCTViewManager`. These subclasses are similar in function to view controllers, but are essentially singletons - only one instance of each is created by the bridge. They vend native views to the `RCTUIManager`, which delegates back to them to set and update the properties of the views as necessary. The `RCTViewManager`s are also typically the delegates for the views, sending events back to JavaScript via the bridge. + +Vending a view is simple: + +- Create the basic subclass. +- Add the `RCT_EXPORT_MODULE()` marker macro. +- Implement the `-(UIView *)view` method. + +```objective-c +// RCTMapManager.m +#import + +#import "RCTViewManager.h" + +@interface RCTMapManager : RCTViewManager +@end + +@implementation RCTMapManager + +RCT_EXPORT_MODULE() + +- (UIView *)view +{ + return [[MKMapView alloc] init]; +} + +@end +``` +**Note:** Do not attempt to set the `frame` or `backgroundColor` properties on the `UIView` instance that you vend through the `-view` method. React Native will overwrite the values set by your custom class in order to match your JavaScript component's layout props. If you need this granularity of control it might be better to wrap the `UIView` instance you want to style in another `UIView` and return the wrapper `UIView` instead. See [Issue 2948](https://github.com/facebook/react-native/issues/2948) for more context. + +Then you just need a little bit of JavaScript to make this a usable React component: + +```javascript +// MapView.js + +import { requireNativeComponent } from 'react-native'; + +// requireNativeComponent automatically resolves this to "RCTMapManager" +module.exports = requireNativeComponent('RCTMap', null); +``` + +This is now a fully-functioning native map view component in JavaScript, complete with pinch-zoom and other native gesture support. We can't really control it from JavaScript yet, though :( + +## Properties + +The first thing we can do to make this component more usable is to bridge over some native properties. Let's say we want to be able to disable pitch control and specify the visible region. Disabling pitch is a simple boolean, so we add this one line: + +```objective-c +// RCTMapManager.m +RCT_EXPORT_VIEW_PROPERTY(pitchEnabled, BOOL) +``` + +Note that we explicitly specify the type as `BOOL` - React Native uses `RCTConvert` under the hood to convert all sorts of different data types when talking over the bridge, and bad values will show convenient "RedBox" errors to let you know there is an issue ASAP. When things are straightforward like this, the whole implementation is taken care of for you by this macro. + +Now to actually disable pitch, we set the property in JS: + +```javascript +// MyApp.js + +``` + +This isn't very well documented though - in order to know what properties are available and what values they accept, the client of your new component needs to dig through the Objective-C code. To make this better, let's make a wrapper component and document the interface with React `PropTypes`: + +```javascript +// MapView.js +import React from 'react'; +import { requireNativeComponent } from 'react-native'; + +class MapView extends React.Component { + render() { + return ; + } +} + +MapView.propTypes = { + /** + * When this property is set to `true` and a valid camera is associated + * with the map, the camera’s pitch angle is used to tilt the plane + * of the map. When this property is set to `false`, the camera’s pitch + * angle is ignored and the map is always displayed as if the user + * is looking straight down onto it. + */ + pitchEnabled: React.PropTypes.bool, +}; + +var RCTMap = requireNativeComponent('RCTMap', MapView); + +module.exports = MapView; +``` + +Now we have a nicely documented wrapper component that is easy to work with. Note that we changed the second argument to `requireNativeComponent` from `null` to the new `MapView` wrapper component. This allows the infrastructure to verify that the propTypes match the native props to reduce the chances of mismatches between the ObjC and JS code. + +Next, let's add the more complex `region` prop. We start by adding the native code: + +```objective-c +// RCTMapManager.m +RCT_CUSTOM_VIEW_PROPERTY(region, MKCoordinateRegion, RCTMap) +{ + [view setRegion:json ? [RCTConvert MKCoordinateRegion:json] : defaultView.region animated:YES]; +} +``` + +Ok, this is more complicated than the simple `BOOL` case we had before. Now we have a `MKCoordinateRegion` type that needs a conversion function, and we have custom code so that the view will animate when we set the region from JS. Within the function body that we provide, `json` refers to the raw value that has been passed from JS. There is also a `view` variable which gives us access to the manager's view instance, and a `defaultView` that we use to reset the property back to the default value if JS sends us a null sentinel. + +You could write any conversion function you want for your view - here is the implementation for `MKCoordinateRegion` via two categories on `RCTConvert`: + +```objective-c +@implementation RCTConvert(CoreLocation) + +RCT_CONVERTER(CLLocationDegrees, CLLocationDegrees, doubleValue); +RCT_CONVERTER(CLLocationDistance, CLLocationDistance, doubleValue); + ++ (CLLocationCoordinate2D)CLLocationCoordinate2D:(id)json +{ + json = [self NSDictionary:json]; + return (CLLocationCoordinate2D){ + [self CLLocationDegrees:json[@"latitude"]], + [self CLLocationDegrees:json[@"longitude"]] + }; +} + +@end + +@implementation RCTConvert(MapKit) + ++ (MKCoordinateSpan)MKCoordinateSpan:(id)json +{ + json = [self NSDictionary:json]; + return (MKCoordinateSpan){ + [self CLLocationDegrees:json[@"latitudeDelta"]], + [self CLLocationDegrees:json[@"longitudeDelta"]] + }; +} + ++ (MKCoordinateRegion)MKCoordinateRegion:(id)json +{ + return (MKCoordinateRegion){ + [self CLLocationCoordinate2D:json], + [self MKCoordinateSpan:json] + }; +} +``` + +These conversion functions are designed to safely process any JSON that the JS might throw at them by displaying "RedBox" errors and returning standard initialization values when missing keys or other developer errors are encountered. + +To finish up support for the `region` prop, we need to document it in `propTypes` (or we'll get an error that the native prop is undocumented), then we can set it just like any other prop: + +```javascript +// MapView.js + +MapView.propTypes = { + /** + * When this property is set to `true` and a valid camera is associated + * with the map, the camera’s pitch angle is used to tilt the plane + * of the map. When this property is set to `false`, the camera’s pitch + * angle is ignored and the map is always displayed as if the user + * is looking straight down onto it. + */ + pitchEnabled: React.PropTypes.bool, + + /** + * The region to be displayed by the map. + * + * The region is defined by the center coordinates and the span of + * coordinates to display. + */ + region: React.PropTypes.shape({ + /** + * Coordinates for the center of the map. + */ + latitude: React.PropTypes.number.isRequired, + longitude: React.PropTypes.number.isRequired, + + /** + * Distance between the minimum and the maximum latitude/longitude + * to be displayed. + */ + latitudeDelta: React.PropTypes.number.isRequired, + longitudeDelta: React.PropTypes.number.isRequired, + }), +}; + +// MyApp.js + + render() { + var region = { + latitude: 37.48, + longitude: -122.16, + latitudeDelta: 0.1, + longitudeDelta: 0.1, + }; + return ; + } + +``` + +Here you can see that the shape of the region is explicit in the JS documentation - ideally we could codegen some of this stuff, but that's not happening yet. + +Sometimes you'll have some special properties that you need to expose for the native component, but don't actually want them as part of the API for the associated React component. For example, `Switch` has a custom `onChange` handler for the raw native event, and exposes an `onValueChange` handler property that is invoked with just the boolean value rather than the raw event. Since you don't want these native only properties to be part of the API, you don't want to put them in `propTypes`, but if you don't you'll get an error. The solution is simply to call them out via the `nativeOnly` option, e.g. + +```javascript +var RCTSwitch = requireNativeComponent('RCTSwitch', Switch, { + nativeOnly: { onChange: true } +}); +``` + +## Events + +So now we have a native map component that we can control easily from JS, but how do we deal with events from the user, like pinch-zooms or panning to change the visible region? The key is to declare an event handler property on `RCTMapManager`, make it a delegate for all the views it vends, and forward events to JS by calling the event handler block from the native view. This looks like so (simplified from the full implementation): + +```objective-c +// RCTMap.h + +#import + +#import "RCTComponent.h" + +@interface RCTMap: MKMapView + +@property (nonatomic, copy) RCTBubblingEventBlock onChange; + +@end +``` + +```objective-c +// RCTMap.m + +#import "RCTMap.h" + +@implementation RCTMap + +@end +``` + +```objective-c +// RCTMapManager.m + +#import "RCTMapManager.h" + +#import + +#import "RCTMap.h" +#import "UIView+React.h" + +@interface RCTMapManager() +@end + +@implementation RCTMapManager + +RCT_EXPORT_MODULE() + +RCT_EXPORT_VIEW_PROPERTY(onChange, RCTBubblingEventBlock) + +- (UIView *)view +{ + RCTMap *map = [RCTMap new]; + map.delegate = self; + return map; +} + +#pragma mark MKMapViewDelegate + +- (void)mapView:(RCTMap *)mapView regionDidChangeAnimated:(BOOL)animated +{ + if (!mapView.onChange) { + return; + } + + MKCoordinateRegion region = mapView.region; + mapView.onChange(@{ + @"region": @{ + @"latitude": @(region.center.latitude), + @"longitude": @(region.center.longitude), + @"latitudeDelta": @(region.span.latitudeDelta), + @"longitudeDelta": @(region.span.longitudeDelta), + } + }); +} +``` + +You can see we're adding an event handler property to the view by subclassing `MKMapView`. Then we're exposing the `onChange` event handler property and setting the manager as the delegate for every view that it vends. Finally, in the delegate method `-mapView:regionDidChangeAnimated:` the event handler block is called on the corresponding view with the region data. Calling the `onChange` event handler block results in calling the same callback prop in JavaScript. This callback is invoked with the raw event, which we typically process in the wrapper component to make a simpler API: + +```javascript +// MapView.js + +class MapView extends React.Component { + constructor() { + this._onChange = this._onChange.bind(this); + } + _onChange(event: Event) { + if (!this.props.onRegionChange) { + return; + } + this.props.onRegionChange(event.nativeEvent.region); + } + render() { + return ; + } +} +MapView.propTypes = { + /** + * Callback that is called continuously when the user is dragging the map. + */ + onRegionChange: React.PropTypes.func, + ... +}; +``` + +## Styles + +Since all our native react views are subclasses of `UIView`, most style attributes will work like you would expect out of the box. Some components will want a default style, however, for example `UIDatePicker` which is a fixed size. This default style is important for the layout algorithm to work as expected, but we also want to be able to override the default style when using the component. `DatePickerIOS` does this by wrapping the native component in an extra view, which has flexible styling, and using a fixed style (which is generated with constants passed in from native) on the inner native component: + +```javascript +// DatePickerIOS.ios.js + +import { UIManager } from 'react-native'; +var RCTDatePickerIOSConsts = UIManager.RCTDatePicker.Constants; +... + render: function() { + return ( + + + + ); + } +}); + +var styles = StyleSheet.create({ + rkDatePickerIOS: { + height: RCTDatePickerIOSConsts.ComponentHeight, + width: RCTDatePickerIOSConsts.ComponentWidth, + }, +}); +``` + +The `RCTDatePickerIOSConsts` constants are exported from native by grabbing the actual frame of the native component like so: + +```objective-c +// RCTDatePickerManager.m + +- (NSDictionary *)constantsToExport +{ + UIDatePicker *dp = [[UIDatePicker alloc] init]; + [dp layoutIfNeeded]; + + return @{ + @"ComponentHeight": @(CGRectGetHeight(dp.frame)), + @"ComponentWidth": @(CGRectGetWidth(dp.frame)), + @"DatePickerModes": @{ + @"time": @(UIDatePickerModeTime), + @"date": @(UIDatePickerModeDate), + @"datetime": @(UIDatePickerModeDateAndTime), + } + }; +} +``` + +This guide covered many of the aspects of bridging over custom native components, but there is even more you might need to consider, such as custom hooks for inserting and laying out subviews. If you want to go even deeper, check out the actual `RCTMapManager` and other components in the [source code](https://github.com/facebook/react-native/blob/master/React/Views). diff --git a/versions/v0.26.0/docs/NativeModulesAndroid.md b/versions/v0.26.0/docs/NativeModulesAndroid.md new file mode 100644 index 0000000..fcdd790 --- /dev/null +++ b/versions/v0.26.0/docs/NativeModulesAndroid.md @@ -0,0 +1,435 @@ +--- +id: native-modules-android +title: Native Modules +layout: docs +category: Guides (Android) +permalink: docs/native-modules-android.html +next: native-components-android +--- + +Sometimes an app needs access to a platform API that React Native doesn't have a corresponding module for yet. Maybe you want to reuse some existing Java code without having to reimplement it in JavaScript, or write some high performance, multi-threaded code such as for image processing, a database, or any number of advanced extensions. + +We designed React Native such that it is possible for you to write real native code and have access to the full power of the platform. This is a more advanced feature and we don't expect it to be part of the usual development process, however it is essential that it exists. If React Native doesn't support a native feature that you need, you should be able to build it yourself. + +## The Toast Module + +This guide will use the [Toast](http://developer.android.com/reference/android/widget/Toast.html) example. Let's say we would like to be able to create a toast message from JavaScript. + +We start by creating a native module. A native module is a Java class that usually extends the `ReactContextBaseJavaModule` class and implements the functionality required by the JavaScript. Our goal here is to be able to write `ToastAndroid.show('Awesome', ToastAndroid.SHORT);` from JavaScript to display a short toast on the screen. + +```java +package com.facebook.react.modules.toast; + +import android.widget.Toast; + +import com.facebook.react.bridge.NativeModule; +import com.facebook.react.bridge.ReactApplicationContext; +import com.facebook.react.bridge.ReactContext; +import com.facebook.react.bridge.ReactContextBaseJavaModule; +import com.facebook.react.bridge.ReactMethod; + +import java.util.Map; + +public class ToastModule extends ReactContextBaseJavaModule { + + private static final String DURATION_SHORT_KEY = "SHORT"; + private static final String DURATION_LONG_KEY = "LONG"; + + public ToastModule(ReactApplicationContext reactContext) { + super(reactContext); + } +} +``` + +`ReactContextBaseJavaModule` requires that a method called `getName` is implemented. The purpose of this method is to return the string name of the `NativeModule` which represents this class in JavaScript. So here we will call this `ToastAndroid` so that we can access it through `React.NativeModules.ToastAndroid` in JavaScript. + +```java + @Override + public String getName() { + return "ToastAndroid"; + } +``` + +An optional method called `getConstants` returns the constant values exposed to JavaScript. Its implementation is not required but is very useful to key pre-defined values that need to be communicated from JavaScript to Java in sync. + +```java + @Override + public Map getConstants() { + final Map constants = new HashMap<>(); + constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT); + constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG); + return constants; + } +``` + +To expose a method to JavaScript a Java method must be annotated using `@ReactMethod`. The return type of bridge methods is always `void`. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events (see below). + +```java + @ReactMethod + public void show(String message, int duration) { + Toast.makeText(getReactApplicationContext(), message, duration).show(); + } +``` + +### Argument Types + +The following argument types are supported for methods annotated with `@ReactMethod` and they directly map to their JavaScript equivalents + +``` +Boolean -> Bool +Integer -> Number +Double -> Number +Float -> Number +String -> String +Callback -> function +ReadableMap -> Object +ReadableArray -> Array +``` + +Read more about [ReadableMap](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableMap.java) and [ReadableArray](https://github.com/facebook/react-native/blob/master/ReactAndroid/src/main/java/com/facebook/react/bridge/ReadableArray.java) + +### Register the Module + +The last step within Java is to register the Module; this happens in the `createNativeModules` of your apps package. If a module is not registered it will not be available from JavaScript. + +```java +class AnExampleReactPackage implements ReactPackage { + + @Override + public List> createJSModules() { + return Collections.emptyList(); + } + + @Override + public List createViewManagers(ReactApplicationContext reactContext) { + return Collections.emptyList(); + } + + @Override + public List createNativeModules( + ReactApplicationContext reactContext) { + List modules = new ArrayList<>(); + + modules.add(new ToastModule(reactContext)); + + return modules; + } +``` + +The package needs to be provided in the `getPackages` method of the `MainActivity.java` file. This file exists under the android folder in your react-native application directory. The path to this file is: `android/app/src/main/java/com/your-app-name/MainActivity.java`. + +```java +protected List getPackages() { + return Arrays.asList( + new MainReactPackage(), + new AnExampleReactPackage()); // <-- Add this line with your package name. +} +``` + +To make it simpler to access your new functionality from JavaScript, it is common to wrap the native module in a JavaScript module. This is not necessary but saves the consumers of your library the need to pull it off of `NativeModules` each time. This JavaScript file also becomes a good location for you to add any JavaScript side functionality. + +```js +'use strict'; +/** + * This exposes the native ToastAndroid module as a JS module. This has a + * function 'show' which takes the following parameters: + * + * 1. String message: A string with the text to toast + * 2. int duration: The duration of the toast. May be ToastAndroid.SHORT or + * ToastAndroid.LONG + */ +import { NativeModules } from 'react-native'; +module.exports = NativeModules.ToastAndroid; +``` + +Now, from your other JavaScript file you can call the method like this: + +```js +import ToastAndroid from './ToastAndroid'; + +ToastAndroid.show('Awesome', ToastAndroid.SHORT); +``` + +## Beyond Toasts + +### Callbacks + +Native modules also support a special kind of argument - a callback. In most cases it is used to provide the function call result to JavaScript. + +```java +public class UIManagerModule extends ReactContextBaseJavaModule { + +... + + @ReactMethod + public void measureLayout( + int tag, + int ancestorTag, + Callback errorCallback, + Callback successCallback) { + try { + measureLayout(tag, ancestorTag, mMeasureBuffer); + float relativeX = PixelUtil.toDIPFromPixel(mMeasureBuffer[0]); + float relativeY = PixelUtil.toDIPFromPixel(mMeasureBuffer[1]); + float width = PixelUtil.toDIPFromPixel(mMeasureBuffer[2]); + float height = PixelUtil.toDIPFromPixel(mMeasureBuffer[3]); + successCallback.invoke(relativeX, relativeY, width, height); + } catch (IllegalViewOperationException e) { + errorCallback.invoke(e.getMessage()); + } + } + +... +``` + +This method would be accessed in JavaScript using: + +```js +UIManager.measureLayout( + 100, + 100, + (msg) => { + console.log(msg); + }, + (x, y, width, height) => { + console.log(x + ':' + y + ':' + width + ':' + height); + } +); +``` + +A native module is supposed to invoke its callback only once. It can, however, store the callback and invoke it later. + +It is very important to highlight that the callback is not invoked immediately after the native function completes - remember that bridge communication is asynchronous, and this too is tied to the run loop. + +### Promises + +Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's `async/await` syntax. When the last parameter of a bridged native method is a `Promise`, its corresponding JS method will return a JS Promise object. + +Refactoring the above code to use a promise instead of callbacks looks like this: + +```java +public class UIManagerModule extends ReactContextBaseJavaModule { + +... + + @ReactMethod + public void measureLayout( + int tag, + int ancestorTag, + Promise promise) { + try { + measureLayout(tag, ancestorTag, mMeasureBuffer); + + WritableMap map = Arguments.createMap(); + + map.putDouble("relativeX", PixelUtil.toDIPFromPixel(mMeasureBuffer[0])); + map.putDouble("relativeY", PixelUtil.toDIPFromPixel(mMeasureBuffer[1])); + map.putDouble("width", PixelUtil.toDIPFromPixel(mMeasureBuffer[2])); + map.putDouble("height", PixelUtil.toDIPFromPixel(mMeasureBuffer[3])); + + promise.resolve(map); + } catch (IllegalViewOperationException e) { + promise.reject(e); + } + } + +... +``` + +The JavaScript counterpart of this method returns a Promise. This means you can use the `await` keyword within an async function to call it and wait for its result: + +```js +async function measureLayout() { + try { + var { + relativeX, + relativeY, + width, + height, + } = await UIManager.measureLayout(100, 100); + + console.log(relativeX + ':' + relativeY + ':' + width + ':' + height); + } catch (e) { + console.error(e); + } +} + +measureLayout(); +``` + +### Threading + +Native modules should not have any assumptions about what thread they are being called on, as the current assignment is subject to change in the future. If a blocking call is required, the heavy work should be dispatched to an internally managed worker thread, and any callbacks distributed from there. + +### Sending Events to JavaScript + +Native modules can signal events to JavaScript without being invoked directly. The easiest way to do this is to use the `RCTDeviceEventEmitter` which can be obtained from the `ReactContext` as in the code snippet below. + +```java +... +private void sendEvent(ReactContext reactContext, + String eventName, + @Nullable WritableMap params) { + reactContext + .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) + .emit(eventName, params); +} +... +WritableMap params = Arguments.createMap(); +... +sendEvent(reactContext, "keyboardWillShow", params); +``` + +JavaScript modules can then register to receive events by `addListenerOn` using the `Subscribable` mixin + +```js +import { DeviceEventEmitter } from 'react-native'; +... + +var ScrollResponderMixin = { + mixins: [Subscribable.Mixin], + + + componentWillMount: function() { + ... + this.addListenerOn(DeviceEventEmitter, + 'keyboardWillShow', + this.scrollResponderKeyboardWillShow); + ... + }, + scrollResponderKeyboardWillShow:function(e: Event) { + this.keyboardWillOpenTo = e; + this.props.onKeyboardWillShow && this.props.onKeyboardWillShow(e); + }, +``` + +You can also directly use the `DeviceEventEmitter` module to listen for events. + +```js +... +componentWillMount: function() { + DeviceEventEmitter.addListener('keyboardWillShow', function(e: Event) { + // handle event. + }); +} +... +``` + +### Getting activity result from `startActivityForResult` + +You'll need to listen to `onActivityResult` if you want to get results from an activity you started with `startActivityForResult`. To do this, the module must implement `ActivityEventListener`. Then, you need to register a listener in the module's constructor, + +```java +reactContext.addActivityEventListener(this); +``` + +Now you can listen to `onActivityResult` by implementing the following method: + +```java +@Override +public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { + // Your logic here +} +``` + +We will implement a simple image picker to demonstrate this. The image picker will expose the method `pickImage` to JavaScript, which will return the path of the image when called. + +```java +public class ImagePickerModule extends ReactContextBaseJavaModule implements ActivityEventListener { + + private static final int IMAGE_PICKER_REQUEST = 467081; + private static final String E_ACTIVITY_DOES_NOT_EXIST = "E_ACTIVITY_DOES_NOT_EXIST"; + private static final String E_PICKER_CANCELLED = "E_PICKER_CANCELLED"; + private static final String E_FAILED_TO_SHOW_PICKER = "E_FAILED_TO_SHOW_PICKER"; + private static final String E_NO_IMAGE_DATA_FOUND = "E_NO_IMAGE_DATA_FOUND"; + + private Promise mPickerPromise; + + public ImagePickerModule(ReactApplicationContext reactContext) { + super(reactContext); + + // Add the listener for `onActivityResult` + reactContext.addActivityEventListener(this); + } + + @Override + public String getName() { + return "ImagePickerModule"; + } + + @ReactMethod + public void pickImage(final Promise promise) { + Activity currentActivity = getCurrentActivity(); + + if (currentActivity == null) { + promise.reject(E_ACTIVITY_DOES_NOT_EXIST, "Activity doesn't exist"); + return; + } + + // Store the promise to resolve/reject when picker returns data + mPickerPromise = promise; + + try { + final Intent galleryIntent = new Intent(Intent.ACTION_PICK); + + galleryIntent.setType("image/*"); + + final Intent chooserIntent = Intent.createChooser(galleryIntent, "Pick an image"); + + currentActivity.startActivityForResult(chooserIntent, IMAGE_PICKER_REQUEST); + } catch (Exception e) { + mPickerPromise.reject(E_FAILED_TO_SHOW_PICKER, e); + mPickerPromise = null; + } + } + + // You can get the result here + @Override + public void onActivityResult(final int requestCode, final int resultCode, final Intent intent) { + if (requestCode == IMAGE_PICKER_REQUEST) { + if (mPickerPromise != null) { + if (resultCode == Activity.RESULT_CANCELED) { + mPickerPromise.reject(E_PICKER_CANCELLED, "Image picker was cancelled"); + } else if (resultCode == Activity.RESULT_OK) { + Uri uri = intent.getData(); + + if (uri == null) { + mPickerPromise.reject(E_NO_IMAGE_DATA_FOUND, "No image data found"); + } else { + mPickerPromise.resolve(uri.toString()); + } + } + + mPickerPromise = null; + } + } + } +} +``` + +### Listening to LifeCycle events + +Listening to the activity's LifeCycle events such as `onResume`, `onPause` etc. is very similar to how we implemented `ActivityEventListener`. The module must implement `LifecycleEventListener`. Then, you need to register a listener in the module's constructor, + +```java +reactContext.addLifecycleEventListener(this); +``` + +Now you can listen to the activity's LifeCycle events by implementing the following methods: + +```java +@Override +public void onHostResume() { + // Actvity `onResume` +} + +@Override +public void onHostPause() { + // Actvity `onPause` +} + +@Override +public void onHostDestroy() { + // Actvity `onDestroy` +} +``` diff --git a/versions/v0.26.0/docs/NativeModulesIOS.md b/versions/v0.26.0/docs/NativeModulesIOS.md new file mode 100644 index 0000000..00c03ce --- /dev/null +++ b/versions/v0.26.0/docs/NativeModulesIOS.md @@ -0,0 +1,391 @@ +--- +id: native-modules-ios +title: Native Modules +layout: docs +category: Guides (iOS) +permalink: docs/native-modules-ios.html +next: native-components-ios +--- + +Sometimes an app needs access to platform API, and React Native doesn't have a corresponding module yet. Maybe you want to reuse some existing Objective-C, Swift or C++ code without having to reimplement it in JavaScript, or write some high performance, multi-threaded code such as for image processing, a database, or any number of advanced extensions. + +We designed React Native such that it is possible for you to write real native code and have access to the full power of the platform. This is a more advanced feature and we don't expect it to be part of the usual development process, however it is essential that it exists. If React Native doesn't support a native feature that you need, you should be able to build it yourself. + +This is a more advanced guide that shows how to build a native module. It assumes the reader knows Objective-C or Swift and core libraries (Foundation, UIKit). + +## iOS Calendar Module Example + +This guide will use the [iOS Calendar API](https://developer.apple.com/library/mac/documentation/DataManagement/Conceptual/EventKitProgGuide/Introduction/Introduction.html) example. Let's say we would like to be able to access the iOS calendar from JavaScript. + +A native module is just an Objective-C class that implements the `RCTBridgeModule` protocol. If you are wondering, RCT is an abbreviation of ReaCT. + +```objective-c +// CalendarManager.h +#import "RCTBridgeModule.h" + +@interface CalendarManager : NSObject +@end +``` + +In addition to implementing the `RCTBridgeModule` protocol, your class must also include the `RCT_EXPORT_MODULE()` macro. This takes an optional argument that specifies the name that the module will be accessible as in your JavaScript code (more on this later). If you do not specify a name, the JavaScript module name will match the Objective-C class name. + +```objective-c +// CalendarManager.m +@implementation CalendarManager + +RCT_EXPORT_MODULE(); + +@end +``` + +React Native will not expose any methods of `CalendarManager` to JavaScript unless explicitly told to. This is done using the `RCT_EXPORT_METHOD()` macro: + +```objective-c +RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location) +{ + RCTLogInfo(@"Pretending to create an event %@ at %@", name, location); +} +``` + +Now, from your JavaScript file you can call the method like this: + +```javascript +import { NativeModules } from 'react-native'; +var CalendarManager = NativeModules.CalendarManager; +CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey'); +``` + +> **NOTE**: JavaScript method names +> +> The name of the method exported to JavaScript is the native method's name up to the first colon. React Native also defines a macro called `RCT_REMAP_METHOD()` to specify the JavaScript method's name. This is useful when multiple native methods are the same up to the first colon and would have conflicting JavaScript names. + +The CalendarManager module is instantiated on the Objective-C side using a [CalendarManager new] call. The return type of bridge methods is always `void`. React Native bridge is asynchronous, so the only way to pass a result to JavaScript is by using callbacks or emitting events (see below). + +## Argument Types + +`RCT_EXPORT_METHOD` supports all standard JSON object types, such as: + +- string (`NSString`) +- number (`NSInteger`, `float`, `double`, `CGFloat`, `NSNumber`) +- boolean (`BOOL`, `NSNumber`) +- array (`NSArray`) of any types from this list +- map (`NSDictionary`) with string keys and values of any type from this list +- function (`RCTResponseSenderBlock`) + +But it also works with any type that is supported by the `RCTConvert` class (see [`RCTConvert`](https://github.com/facebook/react-native/blob/master/React/Base/RCTConvert.h) for details). The `RCTConvert` helper functions all accept a JSON value as input and map it to a native Objective-C type or class. + +In our `CalendarManager` example, we need to pass the event date to the native method. We can't send JavaScript Date objects over the bridge, so we need to convert the date to a string or number. We could write our native function like this: + +```objective-c +RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSNumber *)secondsSinceUnixEpoch) +{ + NSDate *date = [RCTConvert NSDate:secondsSinceUnixEpoch]; +} +``` + +or like this: + +```objective-c +RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSString *)ISO8601DateString) +{ + NSDate *date = [RCTConvert NSDate:ISO8601DateString]; +} +``` + +But by using the automatic type conversion feature, we can skip the manual conversion step completely, and just write: + +```objective-c +RCT_EXPORT_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(NSDate *)date) +{ + // Date is ready to use! +} +``` + +You would then call this from JavaScript by using either: + +```javascript +CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.getTime()); // passing date as number of seconds since Unix epoch +``` + +or + +```javascript +CalendarManager.addEvent('Birthday Party', '4 Privet Drive, Surrey', date.toISOString()); // passing date as ISO-8601 string +``` + +And both values would get converted correctly to the native `NSDate`. A bad value, like an `Array`, would generate a helpful "RedBox" error message. + +As `CalendarManager.addEvent` method gets more and more complex, the number of arguments will grow. Some of them might be optional. In this case it's worth considering changing the API a little bit to accept a dictionary of event attributes, like this: + +```objective-c +#import "RCTConvert.h" + +RCT_EXPORT_METHOD(addEvent:(NSString *)name details:(NSDictionary *)details) +{ + NSString *location = [RCTConvert NSString:details[@"location"]]; + NSDate *time = [RCTConvert NSDate:details[@"time"]]; + ... +} +``` + +and call it from JavaScript: + +```javascript +CalendarManager.addEvent('Birthday Party', { + location: '4 Privet Drive, Surrey', + time: date.getTime(), + description: '...' +}) +``` + +> **NOTE**: About array and map +> +> Objective-C doesn't provide any guarantees about the types of values in these structures. Your native module might expect an array of strings, but if JavaScript calls your method with an array containing numbers and strings, you'll get an `NSArray` containing a mix of `NSNumber` and `NSString`. For arrays, `RCTConvert` provides some typed collections you can use in your method declaration, such as `NSStringArray`, or `UIColorArray`. For maps, it is the developer's responsibility to check the value types individually by manually calling `RCTConvert` helper methods. + +## Callbacks + +> **WARNING** +> +> This section is more experimental than others because we don't have a solid set of best practices around callbacks yet. + +Native modules also supports a special kind of argument- a callback. In most cases it is used to provide the function call result to JavaScript. + +```objective-c +RCT_EXPORT_METHOD(findEvents:(RCTResponseSenderBlock)callback) +{ + NSArray *events = ... + callback(@[[NSNull null], events]); +} +``` + +`RCTResponseSenderBlock` accepts only one argument - an array of parameters to pass to the JavaScript callback. In this case we use node's convention to make the first parameter an error object (usually `null` when there is no error) and the rest are the results of the function. + +```javascript +CalendarManager.findEvents((error, events) => { + if (error) { + console.error(error); + } else { + this.setState({events: events}); + } +}) +``` + +A native module is supposed to invoke its callback only once. It can, however, store the callback and invoke it later. This pattern is often used to wrap iOS APIs that require delegates. See [`RCTAlertManager`](https://github.com/facebook/react-native/blob/master/React/Modules/RCTAlertManager.m) for an example. + +If you want to pass error-like objects to JavaScript, use `RCTMakeError` from [`RCTUtils.h`](https://github.com/facebook/react-native/blob/master/React/Base/RCTUtils.h). Right now this just passes an Error-shaped dictionary to JavaScript, but we would like to automatically generate real JavaScript `Error` objects in the future. + +## Promises + +Native modules can also fulfill a promise, which can simplify your code, especially when using ES2016's `async/await` syntax. When the last parameters of a bridged native method are an `RCTPromiseResolveBlock` and `RCTPromiseRejectBlock`, its corresponding JS method will return a JS Promise object. + +Refactoring the above code to use a promise instead of callbacks looks like this: + +```objective-c +RCT_REMAP_METHOD(findEvents, + resolver:(RCTPromiseResolveBlock)resolve + rejecter:(RCTPromiseRejectBlock)reject) +{ + NSArray *events = ... + if (events) { + resolve(events); + } else { + NSError *error = ... + reject(@"no_events", @"There were no events", error); + } +} +``` + +The JavaScript counterpart of this method returns a Promise. This means you can use the `await` keyword within an async function to call it and wait for its result: + +```js +async function updateEvents() { + try { + var events = await CalendarManager.findEvents(); + + this.setState({ events }); + } catch (e) { + console.error(e); + } +} + +updateEvents(); +``` + +## Threading + +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. The `- (dispatch_queue_t)methodQueue` method allows the native module to specify which queue its methods should be run on. For example, if it needs to use a main-thread-only iOS API, it should specify this via: + +```objective-c +- (dispatch_queue_t)methodQueue +{ + return dispatch_get_main_queue(); +} +``` + +Similarly, if an operation may take a long time to complete, the native module should not block and can specify it's own queue to run operations on. For example, the `RCTAsyncLocalStorage` module creates it's own queue so the React queue isn't blocked waiting on potentially slow disk access: + +```objective-c +- (dispatch_queue_t)methodQueue +{ + return dispatch_queue_create("com.facebook.React.AsyncLocalStorageQueue", DISPATCH_QUEUE_SERIAL); +} +``` + +The specified `methodQueue` will be shared by all of the methods in your module. If *just one* of your methods is long-running (or needs to be run on a different queue than the others for some reason), you can use `dispatch_async` inside the method to perform that particular method's code on another queue, without affecting the others: + +```objective-c +RCT_EXPORT_METHOD(doSomethingExpensive:(NSString *)param callback:(RCTResponseSenderBlock)callback) +{ + dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ + // Call long-running code on background thread + ... + // You can invoke callback from any thread/queue + callback(@[...]); + }); +} +``` + +> **NOTE**: Sharing dispatch queues between modules +> +> The `methodQueue` method will be called once when the module is initialized, and then retained by the bridge, so there is no need to retain the queue yourself, unless you wish to make use of it within your module. However, if you wish to share the same queue between multiple modules then you will need to ensure that you retain and return the same queue instance for each of them; merely returning a queue of the same name for each won't work. + +## Exporting Constants + +A native module can export constants that are immediately available to JavaScript at runtime. This is useful for communicating static data that would otherwise require a round-trip through the bridge. + +```objective-c +- (NSDictionary *)constantsToExport +{ + return @{ @"firstDayOfTheWeek": @"Monday" }; +} +``` + +JavaScript can use this value right away, synchronously: + +```javascript +console.log(CalendarManager.firstDayOfTheWeek); +``` + +Note that the constants are exported only at initialization time, so if you change `constantsToExport` values at runtime it won't affect the JavaScript environment. + +### Enum Constants + +Enums that are defined via `NS_ENUM` cannot be used as method arguments without first extending RCTConvert. + +In order to export the following `NS_ENUM` definition: + +```objc +typedef NS_ENUM(NSInteger, UIStatusBarAnimation) { + UIStatusBarAnimationNone, + UIStatusBarAnimationFade, + UIStatusBarAnimationSlide, +}; +``` + +You must create a class extension of RCTConvert like so: + +```objc +@implementation RCTConvert (StatusBarAnimation) + RCT_ENUM_CONVERTER(UIStatusBarAnimation, (@{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone), + @"statusBarAnimationFade" : @(UIStatusBarAnimationFade), + @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide)}), + UIStatusBarAnimationNone, integerValue) +@end +``` + +You can then define methods and export your enum constants like this: + +```objc +- (NSDictionary *)constantsToExport +{ + return @{ @"statusBarAnimationNone" : @(UIStatusBarAnimationNone), + @"statusBarAnimationFade" : @(UIStatusBarAnimationFade), + @"statusBarAnimationSlide" : @(UIStatusBarAnimationSlide) } +}; + +RCT_EXPORT_METHOD(updateStatusBarAnimation:(UIStatusBarAnimation)animation + completion:(RCTResponseSenderBlock)callback) +``` + +Your enum will then be automatically unwrapped using the selector provided (`integerValue` in the above example) before being passed to your exported method. + + +## Sending Events to JavaScript + +The native module can signal events to JavaScript without being invoked directly. The easiest way to do this is to use `eventDispatcher`: + +```objective-c +#import "RCTBridge.h" +#import "RCTEventDispatcher.h" + +@implementation CalendarManager + +@synthesize bridge = _bridge; + +- (void)calendarEventReminderReceived:(NSNotification *)notification +{ + NSString *eventName = notification.userInfo[@"name"]; + [self.bridge.eventDispatcher sendAppEventWithName:@"EventReminder" + body:@{@"name": eventName}]; +} + +@end +``` + +JavaScript code can subscribe to these events: + +```javascript +import { NativeAppEventEmitter } from 'react-native'; + +var subscription = NativeAppEventEmitter.addListener( + 'EventReminder', + (reminder) => console.log(reminder.name) +); +... +// Don't forget to unsubscribe, typically in componentWillUnmount +subscription.remove(); +``` +For more examples of sending events to JavaScript, see [`RCTLocationObserver`](https://github.com/facebook/react-native/blob/master/Libraries/Geolocation/RCTLocationObserver.m). + +## Exporting Swift + +Swift doesn't have support for macros so exposing it to React Native requires a bit more setup but works relatively the same. + +Let's say we have the same `CalendarManager` but as a Swift class: + +```swift +// CalendarManager.swift + +@objc(CalendarManager) +class CalendarManager: NSObject { + + @objc func addEvent(name: String, location: String, date: NSNumber) -> Void { + // Date is ready to use! + } + +} +``` + +> **NOTE**: It is important to use the @objc modifiers to ensure the class and functions are exported properly to the Objective-C runtime. + +Then create a private implementation file that will register the required information with the React Native bridge: + +```objc +// CalendarManagerBridge.m +#import "RCTBridgeModule.h" + +@interface RCT_EXTERN_MODULE(CalendarManager, NSObject) + +RCT_EXTERN_METHOD(addEvent:(NSString *)name location:(NSString *)location date:(nonnull NSNumber *)date) + +@end +``` + +For those of you new to Swift and Objective-C, whenever you [mix the two languages in an iOS project](https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/BuildingCocoaApps/MixandMatch.html), you will also need an additional bridging file, known as a bridging header, to expose the Objective-C files to Swift. Xcode will offer to create this header file for you if you add your Swift file to your app through the Xcode `File>New File` menu option. You will need to import `RCTBridgeModule.h` in this header file. + +```objc +// CalendarManager-Bridging-Header.h +#import "RCTBridgeModule.h" +``` + +You can also use `RCT_EXTERN_REMAP_MODULE` and `RCT_EXTERN_REMAP_METHOD` to alter the JavaScript name of the module or methods you are exporting. For more information see [`RCTBridgeModule`](https://github.com/facebook/react-native/blob/master/React/Base/RCTBridgeModule.h). diff --git a/versions/v0.26.0/docs/NavigatorComparison.md b/versions/v0.26.0/docs/NavigatorComparison.md new file mode 100644 index 0000000..69a8c46 --- /dev/null +++ b/versions/v0.26.0/docs/NavigatorComparison.md @@ -0,0 +1,49 @@ +--- +id: navigator-comparison +title: Navigator Comparison +layout: docs +category: Guides +permalink: docs/navigator-comparison.html +next: known-issues +--- + +The differences between [Navigator](docs/navigator.html) +and [NavigatorIOS](docs/navigatorios.html) are a common +source of confusion for newcomers. + +Both `Navigator` and `NavigatorIOS` are components that allow you to +manage the navigation in your app between various "scenes" (another word +for screens). They manage a route stack and allow you to pop, push, and +replace states. In this way, [they are similar to the html5 history +API](https://developer.mozilla.org/en-US/docs/Web/Guide/API/DOM/Manipulating_the_browser_history). +The primary distinction between the two is that `NavigatorIOS` leverages +the iOS +[UINavigationController](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/) +class, and `Navigator` re-implements that functionality entirely in +JavaScript as a React component. A corollary of this is that `Navigator` +will be compatible with Android and iOS, whereas `NavigatorIOS` will +only work on the one platform. Below is an itemized list of differences +between the two. + +## Navigator + +- Extensive API makes it completely customizable from JavaScript. +- Under active development from the React Native team. +- Written in JavaScript. +- Works on iOS and Android. +- Includes a simple navigation bar component similar to the default `NavigatorIOS` bar: `Navigator.NavigationBar`, and another with breadcrumbs called `Navigator.BreadcrumbNavigationBar`. See the UIExplorer demo to try them out and see how to use them. + - Currently animations are good and improving, but they are still less refined than Apple's, which you get from `NavigatorIOS`. +- You can provide your own navigation bar by passing it through the `navigationBar` prop. + +## NavigatorIOS + +- Small, limited API makes it much less customizable than `Navigator` in its current form. +- Development belongs to open-source community - not used by the React Native team on their apps. + - A result of this is that there is currently a backlog of unresolved bugs, nobody who uses this has stepped up to take ownership for it yet. + - You may find an alternative in the community project [react-native-navigation](https://github.com/wix/react-native-navigation) which replaces `NavigatorIOS`. +- Wraps UIKit, so it works exactly the same as it would on another native app. Lives in Objective-C and JavaScript. + - Consequently, you get the animations and behavior that Apple has developed. +- iOS only. +- Includes a navigation bar by default; this navigation bar is not a React Native view component and the style can only be slightly modified. + +For most non-trivial apps, you will want to use `Navigator` - it won't be long before you run into issues when trying to do anything complex with `NavigatorIOS`. diff --git a/versions/v0.26.0/docs/Network.md b/versions/v0.26.0/docs/Network.md new file mode 100644 index 0000000..d3bcf9c --- /dev/null +++ b/versions/v0.26.0/docs/Network.md @@ -0,0 +1,155 @@ +--- +id: network +title: Network +layout: docs +category: Polyfills +permalink: docs/network.html +next: timers +--- + +One of React Native's goals is to be a playground where we can experiment with different architectures and crazy ideas. Since browsers are not flexible enough, we had no choice but to reimplement the entire stack. In the places that we did not intend to change anything, we tried to be as faithful as possible to the browser APIs. The networking stack is a great example. + +## Fetch + +[fetch](https://fetch.spec.whatwg.org/) is a better networking API being worked on by the standards committee and is already available in Chrome. It is available in React Native by default. + +#### Usage + +```js +fetch('https://mywebsite.com/endpoint/') +``` + +Include a request object as the optional second argument to customize the HTTP request: + +```js +fetch('https://mywebsite.com/endpoint/', { + method: 'POST', + headers: { + 'Accept': 'application/json', + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + firstParam: 'yourValue', + secondParam: 'yourOtherValue', + }) +}) +``` + +#### Async + +`fetch` returns a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that can be processed in two ways: + +1. Using `then` and `catch` in synchronous code: + + ```js + fetch('https://mywebsite.com/endpoint.php') + .then((response) => response.text()) + .then((responseText) => { + console.log(responseText); + }) + .catch((error) => { + console.warn(error); + }); + ``` +2. Called within an asynchronous function using ES7 `async`/`await` syntax: + + ```js + class MyComponent extends React.Component { + ... + async getUsersFromApi() { + try { + let response = await fetch('https://mywebsite.com/endpoint/'); + let responseJson = await response.json(); + return responseJson.users; + } catch(error) { + // Handle error + console.error(error); + } + } + ... + } + ``` + +- Note: Errors thrown by rejected Promises need to be caught, or they will be swallowed silently + +## WebSocket + +WebSocket is a protocol providing 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.onmessage = (e) => { + // a message was received + console.log(e.data); +}; + +ws.onerror = (e) => { + // an error occurred + console.log(e.message); +}; + +ws.onclose = (e) => { + // connection closed + console.log(e.code, e.reason); +}; +``` + +## XMLHttpRequest + +XMLHttpRequest API is implemented on-top of [iOS networking apis](https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/URLLoadingSystem/URLLoadingSystem.html). The notable difference from web is the security model: you can read from arbitrary websites on the internet since there is no concept of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing). + +```js +var request = new XMLHttpRequest(); +request.onreadystatechange = (e) => { + if (request.readyState !== 4) { + return; + } + + if (request.status === 200) { + console.log('success', request.responseText); + } else { + console.warn('error'); + } +}; + +request.open('GET', 'https://mywebsite.com/endpoint.php'); +request.send(); +``` + +You can also use - + +```js +var request = new XMLHttpRequest(); + +function onLoad() { + console.log(request.status); + console.log(request.responseText); +}; + +function onTimeout() { + console.log('Timeout'); + console.log(request.responseText); +}; + +function onError() { + console.log('General network error'); + console.log(request.responseText); +}; + +request.onload = onLoad; +request.ontimeout = onTimeout; +request.onerror = onError; +request.open('GET', 'https://mywebsite.com/endpoint.php'); +request.send(); +``` + + +Please follow the [MDN Documentation](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) for a complete description of the API. + +As a developer, you're probably not going to use XMLHttpRequest directly as its API is very tedious to work with. But the fact that it is implemented and compatible with the browser API gives you the ability to use third-party libraries such as [frisbee](https://github.com/niftylettuce/frisbee) or [axios](https://github.com/mzabriskie/axios) directly from npm. diff --git a/versions/v0.26.0/docs/Newsletter.md b/versions/v0.26.0/docs/Newsletter.md new file mode 100644 index 0000000..800bf54 --- /dev/null +++ b/versions/v0.26.0/docs/Newsletter.md @@ -0,0 +1,8 @@ +--- +id: newsletter +title: Newsletter +layout: docs +category: Community Resources +permalink: http://reactnative.cc/ +next: style +--- diff --git a/versions/v0.26.0/docs/Performance.md b/versions/v0.26.0/docs/Performance.md new file mode 100644 index 0000000..89c02fd --- /dev/null +++ b/versions/v0.26.0/docs/Performance.md @@ -0,0 +1,308 @@ +--- +id: performance +title: Performance +layout: docs +category: Guides +permalink: docs/performance.html +next: upgrading +--- + +A compelling reason for using React Native instead of WebView-based +tools is to achieve 60 FPS and a native look & feel to your apps. Where +possible, we would like for React Native to do the right thing and help +you to focus on your app instead of performance optimization, but there +are areas where we're not quite there yet, and others where React Native +(similar to writing native code directly) cannot possibly determine the +best way to optimize for you and so manual intervention will be +necessary. + +This guide is intended to teach you some basics to help you +to troubleshoot performance issues, as well as discuss common sources of +problems and their suggested solutions. + +### What you need to know about frames + +Your grandparents' generation called movies ["moving +pictures"](https://www.youtube.com/watch?v=F1i40rnpOsA) for a reason: +realistic motion in video is an illusion created by quickly changing +static images at a consistent speed. We refer to each of these images as +frames. The number of frames that is displayed each second has a direct +impact on how smooth and ultimately life-like a video (or user +interface) seems to be. iOS devices display 60 frames per second, which +gives you and the UI system about 16.67ms to do all of the work needed to +generate the static image (frame) that the user will see on the screen +for that interval. If you are unable to do the work necessary to +generate that frame within the allotted 16.67ms, then you will "drop a +frame" and the UI will appear unresponsive. + +Now to confuse the matter a little bit, open up the developer menu in +your app and toggle `Show FPS Monitor`. You will notice that there are +two different frame rates. + +#### JavaScript frame rate + +For most React Native applications, your business logic will run on the +JavaScript thread. This is where your React application lives, API calls +are made, touch events are processed, etc... Updates to native-backed +views are batched and sent over to the native side at the end of each iteration of the event loop, before the frame deadline (if +all goes well). If the JavaScript thread is unresponsive for a frame, it +will be considered a dropped frame. For example, if you were to call +`this.setState` on the root component of a complex application and it +resulted in re-rendering computationally expensive component subtrees, +it's conceivable that this might take 200ms and result in 12 frames +being dropped. Any animations controlled by JavaScript would appear to freeze during that time. If anything takes longer than 100ms, the user will feel it. + +This often happens during Navigator transitions: when you push a new +route, the JavaScript thread needs to render all of the components +necessary for the scene in order to send over the proper commands to the +native side to create the backing views. It's common for the work being +done here to take a few frames and cause jank because the transition is +controlled by the JavaScript thread. Sometimes components will do +additional work on `componentDidMount`, which might result in a second +stutter in the transition. + +Another example is responding to touches: if you are doing work across +multiple frames on the JavaScript thread, you might notice a delay in +responding to TouchableOpacity, for example. This is because the JavaScript thread is busy and cannot process the raw touch events sent over from the main thread. As a result, TouchableOpacity cannot react to the touch events and command the native view to adjust its opacity. + +#### Main thread (aka UI thread) frame rate + +Many people have noticed that performance of `NavigatorIOS` is better +out of the box than `Navigator`. The reason for this is that the +animations for the transitions are done entirely on the main thread, and +so they are not interrupted by frame drops on the JavaScript thread. +([Read about why you should probably use Navigator +anyways.](docs/navigator-comparison.html)) + +Similarly, you can happily scroll up and down through a ScrollView when +the JavaScript thread is locked up because the ScrollView lives on the +main thread (the scroll events are dispatched to the JS thread though, +but their receipt is not necessary for the scroll to occur). + +### Common sources of performance problems + +#### Development mode (dev=true) + +JavaScript thread performance suffers greatly when running in dev mode. +This is unavoidable: a lot more work needs to be done at runtime to +provide you with good warnings and error messages, such as validating +propTypes and various other assertions. + +#### Slow navigator transitions + +As mentioned above, `Navigator` animations are controlled by the +JavaScript thread. Imagine the "push from right" scene transition: each +frame, the new scene is moved from the right to left, starting offscreen +(let's say at an x-offset of 320) and ultimately settling when the scene sits +at an x-offset of 0. Each frame during this transition, the +JavaScript thread needs to send a new x-offset to the main thread. +If the JavaScript thread is locked up, it cannot do this and so no +update occurs on that frame and the animation stutters. + +Part of the long-term solution to this is to allow for JavaScript-based +animations to be offloaded to the main thread. If we were to do the same +thing as in the above example with this approach, we might calculate a +list of all x-offsets for the new scene when we are starting the +transition and send them to the main thread to execute in an +optimized way. Now that the JavaScript thread is freed of this +responsibility, it's not a big deal if it drops a few frames while +rendering the scene -- you probably won't even notice because you will be +too distracted by the pretty transition. + +Unfortunately this solution is not yet implemented, and so in the +meantime we should use the InteractionManager to selectively render the +minimal amount of content necessary for the new scene as long as the +animation is in progress. `InteractionManager.runAfterInteractions` takes +a callback as its only argument, and that callback is fired when the +navigator transition is complete (each animation from the `Animated` API +also notifies the InteractionManager, but that's beyond the scope of +this discussion). + +Your scene component might look something like this: + +```js +class ExpensiveScene extends React.Component { + constructor(props, context) { + super(props, context); + this.state = {renderPlaceholderOnly: true}; + } + + componentDidMount() { + InteractionManager.runAfterInteractions(() => { + this.setState({renderPlaceholderOnly: false}); + }); + } + + render() { + if (this.state.renderPlaceholderOnly) { + return this._renderPlaceholderView(); + } + + return ( + + Your full view goes here + + ); + } + + + _renderPlaceholderView() { + return ( + + Loading... + + ); + } +}; +``` + +You don't need to be limited to rendering some loading indicator, you +could alternatively render part of your content -- for example, when you +load the Facebook app you see a placeholder news feed item with grey +rectangles where text will be. If you are rendering a Map in your new +scene, you might want to display a grey placeholder view or a spinner +until the transition is complete as this can actually cause frames to be +dropped on the main thread. + +#### ListView initial rendering is too slow or scroll performance is bad for large lists + +This is an issue that comes up frequently because iOS ships with +UITableView which gives you very good performance by re-using underlying +UIViews. Work is in progress to do something similar with React Native, +but until then we have some tools at our disposal to help us tweak the +performance to suit our needs. It may not be possible to get all the way +there, but a little bit of creativity and experimentation with these +options can go a long way. + +##### initialListSize + +This prop specifies how many rows we want to render on our first render +pass. If we are concerned with getting *something* on screen as quickly +as possible, we could set the `initialListSize` to 1, and we'll quickly +see other rows fill in on subsequent frames. The number of rows per +frame is determined by the `pageSize`. + +##### pageSize + +After the initial render where `initialListSize` is used, ListView looks +at the `pageSize` to determine how many rows to render per frame. The +default here is 1 -- but if your views are very small and inexpensive to +render, you might want to bump this up. Tweak it and find what works for +your use case. + +##### scrollRenderAheadDistance + +"How early to start rendering rows before they come on screen, in pixels." + +If we had a list with 2000 items and rendered them all immediately that +would be a poor use of both memory and computational resources. It would +also probably cause some pretty awful jank. So the scrollRenderAhead +distance allows us to specify for far beyond the current viewport we +should continue to render rows. + +##### removeClippedSubviews + +"When true, offscreen child views (whose `overflow` value is `hidden`) +are removed from their native backing superview when offscreen. This +can improve scrolling performance on long lists. The default value is +`true`."(The default value is `false` before version 0.14-rc). + +This is an extremely important optimization to apply on large ListViews. +On Android the `overflow` value is always `hidden` so you don't need to +worry about setting it, but on iOS you need to be sure to set `overflow: +hidden` on row containers. + +#### My component renders too slowly and I don't need it all immediately + +It's common at first to overlook ListView, but using it properly is +often key to achieving solid performance. As discussed above, it +provides you with a set of tools that lets you split rendering of your +view across various frames and tweak that behavior to fit your specific +needs. Remember that ListView can be horizontal too. + +#### JS FPS plunges when re-rendering a view that hardly changes + +If you are using a ListView, you must provide a `rowHasChanged` function +that can reduce a lot of work by quickly determining whether or not a +row needs to be re-rendered. If you are using immutable data structures, +this would be as simple as a reference equality check. + +Similarly, you can implement `shouldComponentUpdate` and indicate the +exact conditions under which you would like the component to re-render. +If you write pure components (where the return value of the render +function is entirely dependent on props and state), you can leverage +PureRenderMixin to do this for you. Once again, immutable data +structures are useful to keep this fast -- if you have to do a deep +comparison of a large list of objects, it may be that re-rendering your +entire component would be quicker, and it would certainly require less +code. + +#### Dropping JS thread FPS because of doing a lot of work on the JavaScript thread at the same time + +"Slow Navigator transitions" is the most common manifestation of this, +but there are other times this can happen. Using InteractionManager can +be a good approach, but if the user experience cost is too high to delay +work during an animation, then you might want to consider +LayoutAnimation. + +The Animated api currently calculates each keyframe on-demand on the +JavaScript thread, while LayoutAnimation leverages Core Animation and is +unaffected by JS thread and main thread frame drops. + +One case where I have used this is for animating in a modal (sliding +down from top and fading in a translucent overlay) while +initializing and perhaps receiving responses for several network +requests, rendering the contents of the modal, and updating the view +where the modal was opened from. See the Animations guide for more +information about how to use LayoutAnimation. + +Caveats: +- LayoutAnimation only works for fire-and-forget animations ("static" + animations) -- if it must be be interruptible, you will need to use +Animated. + +#### Moving a view on the screen (scrolling, translating, rotating) drops UI thread FPS + +This is especially true when you have text with a transparent background +positioned on top of an image, or any other situation where alpha +compositing would be required to re-draw the view on each frame. You +will find that enabling `shouldRasterizeIOS` or `renderToHardwareTextureAndroid` +can help with this significantly. + +Be careful not to overuse this or your memory usage could go through the +roof. Profile your performance and memory usage when using these props. If you don't plan to move a view anymore, turn this property off. + +#### Animating the size of an image drops UI thread FPS + +On iOS, each time you adjust the width or height of an Image component +it is re-cropped and scaled from the original image. This can be very expensive, +especially for large images. Instead, use the `transform: [{scale}]` +style property to animate the size. An example of when you might do this is +when you tap an image and zoom it in to full screen. + +#### My TouchableX view isn't very responsive + +Sometimes, if we do an action in the same frame that we are adjusting +the opacity or highlight of a component that is responding to a touch, +we won't see that effect until after the `onPress` function has returned. +If `onPress` does a `setState` that results in a lot of work and a few +frames dropped, this may occur. A solution to this is to wrap any action +inside of your `onPress` handler in `requestAnimationFrame`: + +```js +handleOnPress() { + // Always use TimerMixin with requestAnimationFrame, setTimeout and + // setInterval + this.requestAnimationFrame(() => { + this.doExpensiveAction(); + }); +} +``` + +### Profiling + +Use the built-in Profiler to get detailed information about work done in +the JavaScript thread and main thread side-by-side. + +For iOS, Instruments are an invaluable tool, and on Android you should +learn to use systrace. diff --git a/versions/v0.26.0/docs/PixelRatio.md b/versions/v0.26.0/docs/PixelRatio.md new file mode 100644 index 0000000..4fc8729 --- /dev/null +++ b/versions/v0.26.0/docs/PixelRatio.md @@ -0,0 +1,9 @@ +## Pixel Grid Snapping + +In iOS, you can specify positions and dimensions for elements with arbitrary precision, for example 29.674825. But, ultimately the physical display only have a fixed number of pixels, for example 640×960 for iphone 4 or 750×1334 for iphone 6. iOS tries to be as faithful as possible to the user value by spreading one original pixel into multiple ones to trick the eye. The downside of this technique is that it makes the resulting element look blurry. + +In practice, we found out that developers do not want this feature and they have to work around it by doing manual rounding in order to avoid having blurry elements. In React Native, we are rounding all the pixels automatically. + +We have to be careful when to do this rounding. You never want to work with rounded and unrounded values at the same time as you're going to accumulate rounding errors. Having even one rounding error is deadly because a one pixel border may vanish or be twice as big. + +In React Native, everything in JS and within the layout engine work with arbitrary precision numbers. It's only when we set the position and dimensions of the native element on the main thread that we round. Also, rounding is done relative to the root rather than the parent, again to avoid accumulating rounding errors. diff --git a/versions/v0.26.0/docs/PlatformSpecificInformation.md b/versions/v0.26.0/docs/PlatformSpecificInformation.md new file mode 100644 index 0000000..1f43f61 --- /dev/null +++ b/versions/v0.26.0/docs/PlatformSpecificInformation.md @@ -0,0 +1,102 @@ +--- +id: platform-specific-code +title: Platform Specific Code +layout: docs +category: Guides +permalink: docs/platform-specific-code.html +next: native-modules-ios +--- + +When building a cross-platform app, the need to write different code for different platforms may arise. This can always be achieved by organizing the various components in different folders: + +```sh +/common/components/ +/android/components/ +/ios/components/ +``` + +Another option may be naming the components differently depending on the platform they are going to be used in: + +```sh +BigButtonIOS.js +BigButtonAndroid.js +``` + +But React Native provides two alternatives to easily organize your code separating it by platform: + +## Platform specific extensions +React Native will detect when a file has a `.ios.` or `.android.` extension and load the right file for each platform when requiring them from other components. + +For example, you can have these files in your project: + +```sh +BigButton.ios.js +BigButton.android.js +``` + +With this setup, you can just require the files from a different component without paying attention to the platform in which the app will run. + +```javascript +import BigButton from './components/BigButton'; +``` + +React Native will import the correct component for the running platform. + +## Platform module +A module is provided by React Native to detect what is the platform in which the app is running. This piece of functionality can be useful when only small parts of a component are platform specific. + +```javascript +var { Platform } = React; + +var styles = StyleSheet.create({ + height: (Platform.OS === 'ios') ? 200 : 100, +}); +``` + +`Platform.OS` will be `ios` when running in iOS and `android` when running in an Android device or simulator. + +There is also a `Platform.select` method available, that given an object containing Platform.OS as keys, +returns the value for the platform you are currently running on. + +```javascript +var { Platform } = React; + +var styles = StyleSheet.create({ + container: { + flex: 1, + ...Platform.select({ + ios: { + backgroundColor: 'red', + }, + android: { + backgroundColor: 'blue', + }, + }), + }, +}); +``` + +This will result in a container having `flex: 1` on both platforms and backgroundColor - red on iOS and blue +on Android. + +Since it accepts `any` value, you can also use it to return platform specific component, like below: + +```javascript +var Component = Platform.select({ + ios: () => require('ComponentIOS'), + android: () => require('ComponentAndroid'), +})(); + +; +``` + +###Detecting Android version +On Android, the Platform module can be also used to detect which is the version of the Android Platform in which the app is running + +```javascript +var {Platform} = React; + +if(Platform.Version === 21){ + console.log('Running on Lollipop!'); +} +``` diff --git a/versions/v0.26.0/docs/PullRequestGuidelines.md b/versions/v0.26.0/docs/PullRequestGuidelines.md new file mode 100644 index 0000000..ee9a169 --- /dev/null +++ b/versions/v0.26.0/docs/PullRequestGuidelines.md @@ -0,0 +1,18 @@ +## Tips on reviewing pull requests + +Does the PR miss info required in the [Pull request template](https://github.com/facebook/react-native/blob/master/PULL_REQUEST_TEMPLATE.md)? Example: [#6395](https://github.com/facebook/react-native/pull/6395). Add labels 'Needs revision' and 'Needs response from author'. Add a response like: + +> Hey @author, thanks for sending the pull request. +> Can you please add all the info specified in the [template](https://github.com/facebook/react-native/blob/master/PULL_REQUEST_TEMPLATE.md)? This is necessary for people to be able to understand and review your pull request. + +Does the code style match the [Style guide](https://github.com/facebook/react-native/blob/master/CONTRIBUTING.md#style-guide), especially consistency (formatting, naming) with the rest of the codebase? If not, link to the style guide and add the label 'Needs revision'. + +Does the pull request add a completely new feature we don't want to add to the core and maintain? Ask the author to release it a separate npm module and close the PR. Example: [#2648](https://github.com/facebook/react-native/pull/2648). + +Does the pull request do several unrelated things at the same time? Ask the author to split it. + +Is the PR old and need rebasing? Ask the author "Can you rebase please?" and add the label "Needs response from author". + +Is a PR waiting for a response from author (usually has label "Needs response from author") and there's no reply in last 30 days? Close it with the [bookmarklet](https://github.com/facebook/react-native/blob/master/bots/pr-inactivity-bookmarklet.js). Examples: [#3066](https://github.com/facebook/react-native/pull/3066), [#1099](https://github.com/facebook/react-native/pull/1099). + +Is the PR old and waiting for review? Review it or cc someone who might be able to review. diff --git a/versions/v0.26.0/docs/RunningOnDeviceAndroid.md b/versions/v0.26.0/docs/RunningOnDeviceAndroid.md new file mode 100644 index 0000000..b2c881f --- /dev/null +++ b/versions/v0.26.0/docs/RunningOnDeviceAndroid.md @@ -0,0 +1,105 @@ +--- +id: running-on-device-android +title: Running On Device +layout: docs +category: Guides (Android) +permalink: docs/running-on-device-android.html +next: embedded-app-android +--- + +## Prerequisite: USB Debugging + +You'll need this in order to install your app on your device. First, make sure you have [USB debugging enabled on your device](https://www.google.com/search?q=android+Enable+USB+debugging). + +Check that your device has been **successfully connected** by running `adb devices`: + + $ adb devices + List of devices attached + emulator-5554 offline # Google emulator + 14ed2fcc device # Physical device + +Seeing **device** in the right column means the device is connected. Android - go figure :) You must have **only one device connected**. + +Now you can use `react-native run-android` to install and launch your app on the device. + +## Setting up an Android Device + +Let's now set up an Android device to run our React Native projects. + +First thing is to plug in your device and check the manufacturer code by using `lsusb`, which should output something like this: + +```bash +$ lsusb +Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub +Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 001 Device 003: ID 22b8:2e76 Motorola PCS +Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub +Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub +Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +``` +These lines represent the USB devices currently connected to your machine. + +You want the line that represents your phone. If you're in doubt, try unplugging your phone and running the command again: + +```bash +$ lsusb +Bus 002 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub +Bus 002 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 001 Device 002: ID 8087:0024 Intel Corp. Integrated Rate Matching Hub +Bus 001 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +Bus 004 Device 001: ID 1d6b:0003 Linux Foundation 3.0 root hub +Bus 003 Device 001: ID 1d6b:0002 Linux Foundation 2.0 root hub +``` +You'll see that after removing the phone, the line which has the phone model ("Motorola PCS" in this case) disappeared from the list. This is the line that we care about. + +`Bus 001 Device 003: ID 22b8:2e76 Motorola PCS` + +From the above line, you want to grab the first four digits from the device ID: + +`22b8:2e76` + +In this case, it's `22b8`. That's the identifier for Motorola. + +You'll need to input this into your udev rules in order to get up and running: + +```sh +echo SUBSYSTEM=="usb", ATTR{idVendor}=="22b8", MODE="0666", GROUP="plugdev" | sudo tee /etc/udev/rules.d/51-android-usb.rules +``` + +Make sure that you replace `22b8` with the identifier you get in the above command. + +Now check that your device is properly connecting to ADB, the Android Debug Bridge, by using `adb devices`. + +```bash +List of devices attached +TA9300GLMK device +``` + +## Accessing development server from device + +You can also iterate quickly on device using the development server. Follow one of the steps described below to make your development server running on your laptop accessible for your device. + +> Hint +> +> Most modern android devices don't have a hardware menu button, which we use to trigger the developer menu. In that case you can shake the device to open the dev menu (to reload, debug, etc.). Alternatively, you can run the command `adb shell input keyevent 82` to open the dev menu (82 being the [Menu](http://developer.android.com/reference/android/view/KeyEvent.html#KEYCODE_MENU) key code). + +### Using adb reverse + +> Note that this option is available on devices running android 5.0+ (API 21). + +Have your device connected via USB with debugging enabled (see paragraph above on how to enable USB debugging on your device). + +1. Run `adb reverse tcp:8081 tcp:8081` +2. You can use `Reload JS` and other development options with no extra configuration + +### Configure your app to connect to the local dev server via Wi-Fi + +1. Make sure your laptop and your phone are on the **same Wi-Fi network**. +2. Open your React Native app on your device. You can do this the same way you'd open any other app. +3. You'll see a red screen with an error. This is OK. The following steps will fix that. +4. Open the **Developer menu** by shaking the device or running `adb shell input keyevent 82` from the command line. +5. Go to `Dev Settings`. +6. Go to `Debug server host for device`. +7. Type in your machine's IP address and the port of the local dev server (e.g. 10.0.1.1:8081). **On Mac**, you can find the IP address in System Preferences / Network. **On Windows**, open the command prompt and type `ipconfig` to find your machine's IP address ([more info](http://windows.microsoft.com/en-us/windows/using-command-line-tools-networking-information)). +8. Go back to the **Developer menu** and select `Reload JS`. diff --git a/versions/v0.26.0/docs/RunningOnDeviceIOS.md b/versions/v0.26.0/docs/RunningOnDeviceIOS.md new file mode 100644 index 0000000..619b048 --- /dev/null +++ b/versions/v0.26.0/docs/RunningOnDeviceIOS.md @@ -0,0 +1,40 @@ +--- +id: running-on-device-ios +title: Running On Device +layout: docs +category: Guides (iOS) +permalink: docs/running-on-device-ios.html +next: embedded-app-ios +--- + +Note that running on device requires [Apple Developer account](https://developer.apple.com/register) and provisioning your iPhone. This guide covers only React Native specific topic. + +## Accessing development server from device + +You can iterate quickly on device using development server. To do that, your laptop and your phone have to be on the same wifi network. + +1. Open `AwesomeApp/ios/AwesomeApp/AppDelegate.m` +2. Change the IP in the URL from `localhost` to your laptop's IP. On Mac, you can find the IP address in System Preferences / Network. +3. In Xcode select your phone as build target and press "Build and run" + +> Hint +> +> Shake the device to open development menu (reload, debug, etc.) + +## Using offline bundle + +When you run your app on device, we pack all the JavaScript code and the images used into the app's resources. This way you can test it without development server running and submit the app to the AppStore. + +1. Open `AwesomeApp/ios/AwesomeApp/AppDelegate.m` +2. Uncomment `jsCodeLocation = [[NSBundle mainBundle] ...` +3. The JS bundle will be built for dev or prod depending on your app's scheme (Debug = development build with warnings, Release = minified prod build with perf optimizations). To change the scheme navigate to `Product > Scheme > Edit Scheme...` in xcode and change `Build Configuration` between `Debug` and `Release`. + +## Disabling in-app developer menu + +When building your app for production, your app's scheme should be set to `Release` as detailed in [the debugging documentation](docs/debugging.html#debugging-react-native-apps) in order to disable the in-app developer menu. + +## Troubleshooting + +If `curl` command fails make sure the packager is running. Also try adding `--ipv4` flag to the end of it. + +Note that since [v0.14](https://github.com/facebook/react-native/releases/tag/0.14.0) JS and images are automatically packaged into the iOS app using `Bundle React Native code and images` Xcode build phase. diff --git a/versions/v0.26.0/docs/SignedAPKAndroid.md b/versions/v0.26.0/docs/SignedAPKAndroid.md new file mode 100644 index 0000000..555e4cc --- /dev/null +++ b/versions/v0.26.0/docs/SignedAPKAndroid.md @@ -0,0 +1,107 @@ +--- +id: signed-apk-android +title: Generating Signed APK +layout: docs +category: Guides (Android) +permalink: docs/signed-apk-android.html +next: android-ui-performance +--- + +Android requires that all apps be digitally signed with a certificate before they can be installed, so to distribute your Android application via [Google Play store](https://play.google.com/store), you'll need to generate a signed release APK. The [Signing Your Applications](https://developer.android.com/tools/publishing/app-signing.html) page on Android Developers documentation describes the topic in detail. This guide covers the process in brief, as well as lists the steps required to packaging the JavaScript bundle. + +### Generating a signing key + +You can generate a private signing key using `keytool`. + + $ keytool -genkey -v -keystore my-release-key.keystore -alias my-key-alias -keyalg RSA -keysize 2048 -validity 10000 + +This command prompts you for passwords for the keystore and key, and to provide the Distinguished Name fields for your key. It then generates the keystore as a file called `my-release-key.keystore`. + +The keystore contains a single key, valid for 10000 days. The alias is a name that you will use later when signing your app, so remember to take note of the alias. + +_Note: Remember to keep your keystore file private and never commit it to version control._ + +### Setting up gradle variables + +1. Place the `my-release-key.keystore` file under the `android/app` directory in your project folder. +2. Edit the file `~/.gradle/gradle.properties` and add the following (replace `*****` with the correct keystore password, alias and key password), + +``` +MYAPP_RELEASE_STORE_FILE=my-release-key.keystore +MYAPP_RELEASE_KEY_ALIAS=my-key-alias +MYAPP_RELEASE_STORE_PASSWORD=***** +MYAPP_RELEASE_KEY_PASSWORD=***** +``` + +These are going to be global gradle variables, which we can later use in our gradle config to sign our app. + +_Note about saving the keystore: Once you publish the app on the Play Store, you will need to republish your app under a different package name (losing all downloads and ratings) if you want to change the signing key at any point. So backup your keystore and don't forget the passwords._ + +_Note about security: If you are not keen on storing your passwords in plaintext and you are running OSX, you can also [store your credentials in the Keychain Access app](https://pilloxa.gitlab.io/posts/safer-passwords-in-gradle/). Then you can skip the two last rows in `~/.gradle/gradle.properties`._ + + +### Adding signing config to your app's gradle config + +Edit the file `android/app/build.gradle` in your project folder and add the signing config, + +```gradle +... +android { + ... + defaultConfig { ... } + signingConfigs { + release { + storeFile file(MYAPP_RELEASE_STORE_FILE) + storePassword MYAPP_RELEASE_STORE_PASSWORD + keyAlias MYAPP_RELEASE_KEY_ALIAS + keyPassword MYAPP_RELEASE_KEY_PASSWORD + } + } + buildTypes { + release { + ... + signingConfig signingConfigs.release + } + } +} +... +``` + +### Generating the release APK + +Simply run the following in a terminal: + +```sh +$ cd android && ./gradlew assembleRelease +``` + +Gradle's `assembleRelease` will bundle all the JavaScript needed to run your app into the APK. If you need to change the way the JavaScript bundle and/or drawable resources are bundled (e.g. if you changed the default file/folder names or the general structure of the project), have a look at `android/app/build.gradle` to see how you can update it to reflect these changes. + +The generated APK can be found under `android/app/build/outputs/apk/app-release.apk`, and is ready to be distributed. + +### Testing the release build of your app + +Before uploading the release build to the Play Store, make sure you test it thoroughly. Install it on the device using: + +```sh +$ cd android && ./gradlew installRelease +``` + +Note that `installRelease` is only available if you've set up signing as described above. + +You can kill any running packager instances, all your and framework JavaScript code is bundled in the APK's assets. + +### Enabling Proguard to reduce the size of the APK (optional) + +Proguard is a tool that can slightly reduce the size of the APK. It does this by stripping parts of the React Native Java bytecode (and its dependencies) that your app is not using. + +_**IMPORTANT**: Make sure to thoroughly test your app if you've enabled Proguard. Proguard often requires configuration specific to each native library you're using. See `app/proguard-rules.pro`._ + +To enable Proguard, edit `android/app/build.gradle`: + +```gradle +/** + * Run Proguard to shrink the Java bytecode in release builds. + */ +def enableProguardInReleaseBuilds = true +``` diff --git a/versions/v0.26.0/docs/Style.md b/versions/v0.26.0/docs/Style.md new file mode 100644 index 0000000..fb6cb7a --- /dev/null +++ b/versions/v0.26.0/docs/Style.md @@ -0,0 +1,102 @@ +--- +id: style +title: Style +layout: docs +category: Guides +permalink: docs/style.html +next: images +--- + +React Native doesn't implement CSS but instead relies on JavaScript to let you style your application. This has been a controversial decision and you can read through those slides for the rationale behind it. + + + +## Declare Styles + +The way to declare styles in React Native is the following: + +```javascript +var styles = StyleSheet.create({ + base: { + width: 38, + height: 38, + }, + background: { + backgroundColor: '#222222', + }, + active: { + borderWidth: 2, + borderColor: '#00ff00', + }, +}); +``` + +`StyleSheet.create` construct is optional but provides some key advantages. It ensures that the values are **immutable** and **opaque** by transforming them into plain numbers that reference an internal table. By putting it at the end of the file, you also ensure that they are only created once for the application and not on every render. + +All the attribute names and values are a subset of what works on the web. For layout, React Native implements [Flexbox](docs/flexbox.html). + +## Using Styles + +All the core components accept a style attribute. + +```javascript + + +``` + +They also accept an array of styles. + +```javascript + +``` + +The behavior is the same as `Object.assign`: in case of conflicting values, the one from the right-most element will have precedence and falsy values like `false`, `undefined` and `null` will be ignored. A common pattern is to conditionally add a style based on some condition. + +```javascript + +``` + +Finally, if you really have to, you can also create style objects in render, but they are highly discouraged. Put them last in the array definition. + +```javascript + +``` + +## Pass Styles Around + +In order to let a call site customize the style of your component children, you can pass styles around. Use `View.propTypes.style` and `Text.propTypes.style` in order to make sure only styles are being passed. + +```javascript +var List = React.createClass({ + propTypes: { + style: View.propTypes.style, + elementStyle: View.propTypes.style, + }, + render: function() { + return ( + + {elements.map((element) => + + )} + + ); + } +}); + +// ... in another file ... + +``` +## Supported Properties + +You can checkout latest support of CSS Properties in following Links. + +- [View Properties](docs/view.html#style) +- [Image Properties](docs/image.html#style) +- [Text Properties](docs/text.html#style) +- [Flex Properties](docs/flexbox.html#content) +- [Transform Properties](docs/transforms.html#content) diff --git a/versions/v0.26.0/docs/Testing.md b/versions/v0.26.0/docs/Testing.md new file mode 100644 index 0000000..4c881b2 --- /dev/null +++ b/versions/v0.26.0/docs/Testing.md @@ -0,0 +1,67 @@ +--- +id: testing +title: Testing +layout: docs +category: Guides +permalink: docs/testing.html +next: javascript-environment +--- + +## Running Tests and Contributing + +The React Native repo has several tests you can run to verify you haven't caused a regression with your PR. These tests are run with the [Travis](http://docs.travis-ci.com/) continuous integration system, and will automatically post the results to your PR. + + + +We don't have perfect test coverage of course, especially for complex end-to-end interactions with the user, so many changes will still require significant manual verification, but we would love it if you want to help us increase our test coverage and add more tests and test cases! + +## Jest Tests + +[Jest](http://facebook.github.io/jest/) tests are JS-only tests run on the command line with node. The tests themselves live in the `__tests__` directories of the files they test, and there is a large emphasis on aggressively mocking out functionality that is not under test for failure isolation and maximum speed. You can run the existing React Native jest tests with + +``` +npm test +``` + +from the react-native root, and we encourage you to add your own tests for any components you want to contribute to. See [`getImageSource-test.js`](https://github.com/facebook/react-native/blob/master/Examples/Movies/__tests__/getImageSource-test.js) for a basic example. + +Note: In order to run your own tests, you will have to first follow the Getting Started instructions on the Jest page and then include the `jest` objects below in `package.json` so that the scripts are pre-processed before execution. + +``` +... +"scripts": { + ... + "test": "jest" +}, +... +"jest": { + "scriptPreprocessor": "node_modules/react-native/jestSupport/preprocessor.js", + "setupEnvScriptFile": "node_modules/react-native/jestSupport/env.js", + "testPathIgnorePatterns": [ + "/node_modules/", + "packager/react-packager/src/Activity/" + ], + "testFileExtensions": [ + "js" + ], + "unmockedModulePathPatterns": [ + "promise", + "source-map" + ] +}, +... +``` + +Note: you may have to install/upgrade/link Node.js and other parts of your environment in order for the tests to run correctly. Check out the latest setup in [.travis.yml](https://github.com/facebook/react-native/blob/master/.travis.yml#L11-24) + +## Integration Tests (iOS only) + +React Native provides facilities to make it easier to test integrated components that require both native and JS components to communicate across the bridge. The two main components are `RCTTestRunner` and `RCTTestModule`. `RCTTestRunner` sets up the ReactNative environment and provides facilities to run the tests as `XCTestCase`s in Xcode (`runTest:module` is the simplest method). `RCTTestModule` is exported to JS as `NativeModules.TestModule`. The tests themselves are written in JS, and must call `TestModule.markTestCompleted()` when they are done, otherwise the test will timeout and fail. Test failures are primarily indicated by throwing a JS exception. It is also possible to test error conditions with `runTest:module:initialProps:expectErrorRegex:` or `runTest:module:initialProps:expectErrorBlock:` which will expect an error to be thrown and verify the error matches the provided criteria. See [`IntegrationTestHarnessTest.js`](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestHarnessTest.js), [`UIExplorerIntegrationTests.m`](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerIntegrationTests.m), and [IntegrationTestsApp.js](https://github.com/facebook/react-native/blob/master/IntegrationTests/IntegrationTestsApp.js) for example usage and integration points. + +You can run integration tests locally with cmd+U in the IntegrationTest and UIExplorer apps in Xcode. + +## Snapshot Tests (iOS only) + +A common type of integration test is the snapshot test. These tests render a component, and verify snapshots of the screen against reference images using `TestModule.verifySnapshot()`, using the [`FBSnapshotTestCase`](https://github.com/facebook/ios-snapshot-test-case) library behind the scenes. Reference images are recorded by setting `recordMode = YES` on the `RCTTestRunner`, then running the tests. Snapshots will differ slightly between 32 and 64 bit, and various OS versions, so it's recommended that you enforce tests are run with the correct configuration. It's also highly recommended that all network data be mocked out, along with other potentially troublesome dependencies. See [`SimpleSnapshotTest`](https://github.com/facebook/react-native/blob/master/IntegrationTests/SimpleSnapshotTest.js) for a basic example. + +If you make a change that affects a snapshot test in a PR, such as adding a new example case to one of the examples that is snapshotted, you'll need to re-record the snapshot reference image. To do this, simply change to `_runner.recordMode = YES;` in [UIExplorer/UIExplorerSnapshotTests.m](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/UIExplorerIntegrationTests/UIExplorerSnapshotTests.m#L42), re-run the failing tests, then flip record back to `NO` and submit/update your PR and wait to see if the Travis build passes. diff --git a/versions/v0.26.0/docs/Text.md b/versions/v0.26.0/docs/Text.md new file mode 100644 index 0000000..800137b --- /dev/null +++ b/versions/v0.26.0/docs/Text.md @@ -0,0 +1,103 @@ + + +## Nested Text + +Both iOS and Android allow you to display formatted text by annotating ranges of a string with specific formatting like bold or colored text (`NSAttributedString` on iOS, `SpannableString` on Android). In practice, this is very tedious. For React Native, we decided to use web paradigm for this where you can nest text to achieve the same effect. + +```javascript + + I am bold + + and red + + +``` + +Behind the scenes, React Native converts this to a flat `NSAttributedString` or `SpannableString` that contains the following information: + +```javascript +"I am bold and red" +0-9: bold +9-17: bold, red +``` + +## Containers + +The `` element is special relative to layout: everything inside is no longer using the flexbox layout but using text layout. This means that elements inside of a `` are no longer rectangles, but wrap when they see the end of the line. + +```javascript + + First part and + second part + +// Text container: all the text flows as if it was one +// |First part | +// |and second | +// |part | + + + First part and + second part + +// View container: each text is its own block +// |First part | +// |and | +// |second part| +``` + +## Limited Style Inheritance + +On the web, the usual way to set a font family and size for the entire document is to write: + +```css +/* CSS, *not* React Native */ +html { + font-family: 'lucida grande', tahoma, verdana, arial, sans-serif; + font-size: 11px; + color: #141823; +} +``` + +When the browser is trying to render a text node, it's going to go all the way up to the root element of the tree and find an element with a `font-size` attribute. An unexpected property of this system is that **any** node can have `font-size` attribute, including a `
`. This was designed for convenience, even though not really semantically correct. + +In React Native, we are more strict about it: **you must wrap all the text nodes inside of a `` component**; you cannot have a text node directly under a ``. + +```javascript +// BAD: will raise exception, can't have a text node as child of a + + Some text + + +// GOOD + + + Some text + + +``` + +You also lose the ability to set up a default font for an entire subtree. The recommended way to use consistent fonts and sizes across your application is to create a component `MyAppText` that includes them and use this component across your app. You can also use this component to make more specific components like `MyAppHeaderText` for other kinds of text. + +```javascript + + Text styled with the default font for the entire application + Text styled as a header + +``` + +React Native still has the concept of style inheritance, but limited to text subtrees. In this case, the second part will be both bold and red. + +```javascript + + I am bold + + and red + + +``` + +We believe that this more constrained way to style text will yield better apps: + +- (Developer) React components are designed with strong isolation in mind: You should be able to drop a component anywhere in your application, trusting that as long as the props are the same, it will look and behave the same way. Text properties that could inherit from outside of the props would break this isolation. + +- (Implementor) The implementation of React Native is also simplified. We do not need to have a `fontFamily` field on every single element, and we do not need to potentially traverse the tree up to the root every time we display a text node. The style inheritance is only encoded inside of the native Text component and doesn't leak to other components or the system itself. diff --git a/versions/v0.26.0/docs/Timers.md b/versions/v0.26.0/docs/Timers.md new file mode 100644 index 0000000..2829468 --- /dev/null +++ b/versions/v0.26.0/docs/Timers.md @@ -0,0 +1,79 @@ +--- +id: timers +title: Timers +layout: docs +category: Polyfills +permalink: docs/timers.html +next: colors +--- + +Timers are an important part of an application and React Native implements the [browser timers](https://developer.mozilla.org/en-US/Add-ons/Code_snippets/Timers). + +## Timers + +- setTimeout, clearTimeout +- setInterval, clearInterval +- setImmediate, clearImmediate +- requestAnimationFrame, cancelAnimationFrame + +`requestAnimationFrame(fn)` is not the same as `setTimeout(fn, 0)` - the former will fire after all the frame has flushed, whereas the latter will fire as quickly as possible (over 1000x per second on a iPhone 5S). + +`setImmediate` is executed at the end of the current JavaScript execution block, right before sending the batched response back to native. Note that if you call `setImmediate` within a `setImmediate` callback, it will be executed right away, it won't yield back to native in between. + +The `Promise` implementation uses `setImmediate` as its asynchronicity primitive. + + +## InteractionManager + +One reason why well-built native apps feel so smooth is by avoiding expensive operations during interactions and animations. In React Native, we currently have a limitation that there is only a single JS execution thread, but you can use `InteractionManager` to make sure long-running work is scheduled to start after any interactions/animations have completed. + +Applications can schedule tasks to run after interactions with the following: + +```javascript +InteractionManager.runAfterInteractions(() => { + // ...long-running synchronous task... +}); +``` + +Compare this to other scheduling alternatives: + +- requestAnimationFrame(): for code that animates a view over time. +- setImmediate/setTimeout/setInterval(): run code later, note this may delay animations. +- runAfterInteractions(): run code later, without delaying active animations. + +The touch handling system considers one or more active touches to be an 'interaction' and will delay `runAfterInteractions()` callbacks until all touches have ended or been cancelled. + +InteractionManager also allows applications to register animations by creating an interaction 'handle' on animation start, and clearing it upon completion: + +```javascript +var handle = InteractionManager.createInteractionHandle(); +// run animation... (`runAfterInteractions` tasks are queued) +// later, on animation completion: +InteractionManager.clearInteractionHandle(handle); +// queued tasks run if all handles were cleared +``` + + +## TimerMixin + +We found out that the primary cause of fatals in apps created with React Native was due to timers firing after a component was unmounted. To solve this recurring issue, we introduced `TimerMixin`. If you include `TimerMixin`, then you can replace your calls to `setTimeout(fn, 500)` with `this.setTimeout(fn, 500)` (just prepend `this.`) and everything will be properly cleaned up for you when the component unmounts. + +This library does not ship with React Native - in order to use it on your project, you will need to install it with `npm i react-timer-mixin --save` from your project directory. + +```javascript +import TimerMixin from 'react-timer-mixin'; + +var Component = React.createClass({ + mixins: [TimerMixin], + componentDidMount: function() { + this.setTimeout( + () => { console.log('I do not leak!'); }, + 500 + ); + } +}); +``` + +This will eliminate a lot of hard work tracking down bugs, such as crashes caused by timeouts firing after a component has been unmounted. + +Keep in mind that if you use ES6 classes for your React components [there is no built-in API for mixins](https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#mixins). To use `TimerMixin` with ES6 classes, we recommend [react-mixin](https://github.com/brigand/react-mixin). diff --git a/versions/v0.26.0/docs/Troubleshooting.md b/versions/v0.26.0/docs/Troubleshooting.md new file mode 100644 index 0000000..875dcd8 --- /dev/null +++ b/versions/v0.26.0/docs/Troubleshooting.md @@ -0,0 +1,109 @@ +--- +id: troubleshooting +title: Troubleshooting +layout: docs +category: Quick Start +permalink: docs/troubleshooting.html +--- + +## Cmd-R does not reload the simulator +Enable iOS simulator's "Connect hardware keyboard" from menu Hardware > Keyboard menu. + +![Keyboard Menu](https://cloud.githubusercontent.com/assets/1388454/6863127/03837824-d409-11e4-9251-e05bd31d978f.png) + + +If you are using a non-QWERTY/AZERTY keyboard layout you can use the `Hardware > Shake Gesture` to bring up the dev menu and click "Refresh". Alternatively, you can hit `Cmd-P` on Dvorak/Colemak layouts to reload the simulator. + +## Port already in use red-screen +![red-screen](https://cloud.githubusercontent.com/assets/602176/6857442/63fd4f0a-d3cc-11e4-871f-875b0c784611.png) + + +Something is probably already running on port 8081. You can either kill it or try to change which port the packager is listening to. + +##### Kill process on port 8081 +`$ sudo lsof -n -i4TCP:8081 | grep LISTEN` + +then + +`$ kill -9 ` + + + +##### Change the port in Xcode +Edit `AppDelegate.m` to use a different port. +``` + // OPTION 1 + // Load from development server. Start the server from the repository root: + // + // $ npm start + // + // To run on device, change `localhost` to the IP address of your computer, and make sure your computer and + // iOS device are on the same Wi-Fi network. + jsCodeLocation = [NSURL URLWithString:@"http://localhost:9381/index.ios.bundle"]; + ``` + + +## Watchman took too long to load +Permission settings prevent Watchman from loading. A recent update solves this, get a HEAD install of Watchman if you are experiencing this error. + +``` +brew uninstall watchman +brew install --HEAD watchman +``` + +## NPM locking error + +If in the `react-native init ` phase you saw npm fail with "npm WARN locking Error: EACCES" then try the following: +``` +sudo chown -R $USER ~/.npm +sudo chown -R $USER /usr/local/lib/node_modules +``` + +## Debugging in Chrome hangs and/or does not work well +It is possible that one of your Chrome extensions is interacting in unexpected ways with the debugger. If you are having this issue, try disabling all of your extensions and re-enabling them one-by-one until you find the problematic extension. + +## Xcode Build Failures + +To see the exact error that is causing your build to fail, go into the Issues Navigator in the left sidebar. + +##### React libraries missing +If you are using CocoaPods, verify that you have added React along with the subspecs to the `Podfile`. For example, if you were using the ``, `` and `fetch()` APIs, you would need to add these in your `Podfile`: +``` +pod 'React', :path => '../node_modules/react-native', :subspecs => [ + 'RCTText', + 'RCTImage', + 'RCTNetwork', + 'RCTWebSocket', +] +``` +Next, make sure you have run `pod install` and that a `Pods/` directory has been created in your project with React installed. CocoaPods will instruct you to use the generated `.xcworkspace` file henceforth to be able to use these installed dependencies. + +If you are adding React manually, make sure you have included all the relevant dependencies, like `RCTText.xcodeproj`, `RCTImage.xcodeproj` depending on the ones you are using. Next, the binaries built by these dependencies have to be linked to your app binary. Use the `Linked Frameworks and Binaries` section in the Xcode project settings. More detailed steps are here: [Linking Libraries](docs/linking-libraries-ios.html#content). + +##### Argument list too long: recursive header expansion failed + +In the project's build settings, `User Search Header Paths` and `Header Search Paths` are two configs that specify where Xcode should look for `#import` header files specified in the code. For Pods, CocoaPods uses a default array of specific folders to look in. Verify that this particular config is not overwritten, and that none of the folders configured are too large. If one of the folders is a large folder, Xcode will attempt to recursively search the entire directory and throw above error at some point. + +To revert the `User Search Header Paths` and `Header Search Paths` build settings to their defaults set by CocoaPods - select the entry in the Build Settings panel, and hit delete. It will remove the custom override and return to the CocoaPod defaults. + +## Unable to connect to development server + +##### iOS +Ensure that you are on the same WiFi network as your computer. If you're using a cell data plan, your phone can't access your computer's local IP address. + +##### Android +You need to run `adb reverse tcp:8081 tcp:8081` to forward requests from the device to your computer. This works only on Android 5.0 and newer. + +## Module that uses `WebSocket` (such as Firebase) throws an exception + +React Native implements a polyfill for WebSockets. These polyfills are initialized as part of the react-native module that you include in your application through `import React from 'react-native'`. If you load another module that requires WebSockets, be sure to load/require it after react-native. + +So: +``` +import React from 'react-native'; +import Firebase from 'firebase'; +``` + +Requiring firebase *before* react-native will result in a 'No transports available' redbox. + +Discovered thanks to issue [#3645](https://github.com/facebook/react-native/issues/3645). If you're curious, the polyfills are set up in [InitializeJavaScriptAppEngine.js](https://github.com/facebook/react-native/blob/master/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js). diff --git a/versions/v0.26.0/docs/Tutorial.md b/versions/v0.26.0/docs/Tutorial.md new file mode 100644 index 0000000..d0cb750 --- /dev/null +++ b/versions/v0.26.0/docs/Tutorial.md @@ -0,0 +1,511 @@ +--- +id: tutorial +title: Tutorial +layout: docs +category: Quick Start +permalink: docs/tutorial.html +next: videos +--- + +## Preface + +This tutorial aims to get you up to speed with writing iOS and Android apps using React Native. If you're wondering what React Native is and why Facebook built it, this [blog post](https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/) explains that. + +We assume you have experience writing applications with React. If not, you can learn about it on the [React website](http://facebook.github.io/react/). + +### Building a real-world app + +This tutorial explains how to build a simple app to get you started. If you're looking for a more advanced tutorial on building a real-world app, check out [makeitopen.com](http://makeitopen.com/). + +## Setup + +React Native requires the basic setup explained at [React Native Getting Started](docs/getting-started.html#content). + +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-native` as 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/iOS/AwesomeProject.xcodeproj` and a gradle project in `AwesomeProject/android/app`. + + +## Overview + +In 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. + +### Starting the app on iOS + +Open this new project (`AwesomeProject/ios/AwesomeProject.xcodeproj`) in Xcode and simply build and run it with `⌘+R`. Doing so will also start a Node server which enables live code reloading. With this you can see your changes by pressing `⌘+R` in the simulator rather than recompiling in Xcode. + +### Starting the app on Android + +In your terminal navigate into the `AwesomeProject` and run: + + react-native run-android + +This will install the generated app on your emulator or device, as well as start the Node server which enables live code reloading. To see your changes you have to open the rage-shake-menu (either shake the device or press the menu button on devices, press F2 or Page Up for emulator, ⌘+M for Genymotion), and then press `Reload JS`. + +### Hello World + +`react-native init` will generate an app with the name of your project, in this case AwesomeProject. This is a simple hello world app. For iOS, you can edit `index.ios.js` to make changes to the app and then press ⌘+R in the simulator to see the changes. For Android, you can edit `index.android.js` to make changes to the app and press `Reload JS` from the rage shake menu 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 imports, but feel free to add the following constant wherever you like. In `index.ios.js` or `index.android.js` : + +```javascript +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 imports below. + +```javascript +import React, { + Component, +} from 'react'; +import { + AppRegistry, + Image, + StyleSheet, + Text, + View, +} from 'react-native'; +``` + +Now change the render function so that we're rendering the data mentioned above rather than hello world. + +```javascript + render() { + var movie = MOCKED_MOVIES_DATA[0]; + return ( + + {movie.title} + {movie.year} + + + ); + } +``` + +Press `⌘+R` / `Reload JS` and you should see "Title" above "2015". Notice that the Image doesn't render anything. This is because we haven't specified the width and height of the image we want to render. This is done via styles. While we're changing the styles let's also clean up the styles we're no longer using. + +```javascript +var styles = StyleSheet.create({ + container: { + flex: 1, + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, + thumbnail: { + width: 53, + height: 81, + }, +}); +``` + +And lastly we need to apply this style to the Image component: + +```javascript + +``` + +Press `⌘+R` / `Reload JS` and the image should now render. + +
+ + +
+ + +### Add some styling + +Great, we've rendered our data. Now let's make it look better. I'd like to put the text to the right of the image and make the title larger and centered within that area: + +``` ++---------------------------------+ +|+-------++----------------------+| +|| || Title || +|| Image || || +|| || Year || +|+-------++----------------------+| ++---------------------------------+ +``` + +We'll need to add another container in order to vertically lay out components within horizontally laid out components. + +```javascript + return ( + + + + {movie.title} + {movie.year} + + + ); +``` + +Not too much has changed, we added a container around the Texts and then moved them after the Image (because they're to the right of the Image). Let's see what the style changes look like: + +```javascript + container: { + flex: 1, + flexDirection: 'row', + justifyContent: 'center', + alignItems: 'center', + backgroundColor: '#F5FCFF', + }, +``` + +We use FlexBox for layout - see [this great guide](https://css-tricks.com/snippets/css/a-guide-to-flexbox/) 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: + +```javascript + 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: + +```javascript + title: { + fontSize: 20, + marginBottom: 8, + textAlign: 'center', + }, + year: { + textAlign: 'center', + }, +``` + +Go ahead and press `⌘+R` / `Reload JS` and you'll see the updated view. + +
+ + +
+ +### Fetching real data + +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 imports) to create the REQUEST_URL used to request data with. + +```javascript +/** + * For quota reasons we replaced the Rotten Tomatoes' API with a sample data of + * their very own API that lives in React Native's Github repo. + */ +var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json'; +``` + +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. + +```javascript + constructor(props) { + super(props); + this.state = { + movies: null, + }; + } +``` + +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. + +```javascript + componentDidMount() { + this.fetchData(); + } +``` + +Now add `fetchData` function used above to our main component. This method will be responsible 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. + +```javascript + fetchData() { + fetch(REQUEST_URL) + .then((response) => response.json()) + .then((responseData) => { + this.setState({ + movies: responseData.movies, + }); + }) + .done(); + } +``` + +Now modify the render function to render a loading view if we don't have any movies data, and to render the first movie otherwise. + +```javascript + render() { + if (!this.state.movies) { + return this.renderLoadingView(); + } + + var movie = this.state.movies[0]; + return this.renderMovie(movie); + } + + renderLoadingView() { + return ( + + + Loading movies... + + + ); + } + + renderMovie(movie) { + return ( + + + + {movie.title} + {movie.year} + + + ); + } +``` + +Now press `⌘+R` / `Reload JS` and you should see "Loading movies..." until the response comes back, then it will render the first movie it fetched from Rotten Tomatoes. + +
+ + +
+ +## 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 things first: add the `ListView` import to the top of the file. + +```javascript +import React, { + Component, +} from 'react'; +import { + AppRegistry, + Image, + ListView, + StyleSheet, + Text, + View, +} from 'react-native'; +``` + +Now modify the render function so that once we have our data it renders a ListView of movies instead of a single movie. + +```javascript + render() { + if (!this.state.loaded) { + return this.renderLoadingView(); + } + + return ( + + ); + } +``` + +The `dataSource` is an interface 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 `constructor`. Also, now that we're storing the data in `dataSource`, we should no 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. + +```javascript + constructor(props) { + super(props); + this.state = { + dataSource: new ListView.DataSource({ + rowHasChanged: (row1, row2) => row1 !== row2, + }), + loaded: false, + }; + } +``` + +And here is the modified `fetchData` method that updates the state accordingly: + +```javascript + fetchData() { + fetch(REQUEST_URL) + .then((response) => response.json()) + .then((responseData) => { + this.setState({ + dataSource: this.state.dataSource.cloneWithRows(responseData.movies), + loaded: true, + }); + }) + .done(); + } +``` + +Finally, we add styles for the `ListView` component to the `styles` JS object: +```javascript + listView: { + paddingTop: 20, + backgroundColor: '#F5FCFF', + }, +``` + +And here's the final result: + +
+ + +
+ +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](https://github.com/facebook/react-native/tree/master/Examples/Movies) to see it all working. + + +### Final source code + +```javascript +/** + * Sample React Native App + * https://github.com/facebook/react-native + */ + +import React, { + Component, +} from 'react'; +import { + AppRegistry, + Image, + ListView, + StyleSheet, + Text, + View, +} from 'react-native'; + +var REQUEST_URL = 'https://raw.githubusercontent.com/facebook/react-native/master/docs/MoviesExample.json'; + +class AwesomeProject extends Component { + constructor(props) { + super(props); + this.state = { + dataSource: new ListView.DataSource({ + rowHasChanged: (row1, row2) => row1 !== row2, + }), + loaded: false, + }; + } + + componentDidMount() { + this.fetchData(); + } + + fetchData() { + fetch(REQUEST_URL) + .then((response) => response.json()) + .then((responseData) => { + this.setState({ + dataSource: this.state.dataSource.cloneWithRows(responseData.movies), + loaded: true, + }); + }) + .done(); + } + + render() { + if (!this.state.loaded) { + return this.renderLoadingView(); + } + + return ( + + ); + } + + renderLoadingView() { + return ( + + + Loading movies... + + + ); + } + + renderMovie(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, + }, + listView: { + paddingTop: 20, + backgroundColor: '#F5FCFF', + }, +}); + +AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject); +``` diff --git a/versions/v0.26.0/docs/Upgrading.md b/versions/v0.26.0/docs/Upgrading.md new file mode 100644 index 0000000..4034b4f --- /dev/null +++ b/versions/v0.26.0/docs/Upgrading.md @@ -0,0 +1,70 @@ +--- +id: upgrading +title: Upgrading +layout: docs +category: Guides +permalink: docs/upgrading.html +next: platform-specific-code +--- + +Upgrading to new versions of React Native will give you access to more APIs, views, developer tools +and other goodies. Because React Native projects are essentially made up of an Android project, an +iOS project and a JavaScript project, all combined under an npm package, upgrading can be rather +tricky. But we try to make it easy for you. Here's what you need to do to upgrade from an older +version of React Native: + +## 1. Upgrade the `react-native` dependency + +Note the latest version of the `react-native` npm package from here (or use `npm info react-native` to check): + +* https://www.npmjs.com/package/react-native + +Now install that version of `react-native` in your project with `npm install --save`. For example, to upgrade to the version `0.18`, in a terminal run: + +```sh +$ npm install --save react-native@0.18 +``` + +## 2. Upgrade your project templates + +The new npm package will likely contain updates to the files that are normally generated when you +run `react-native init`, like the iOS and the Android sub-projects. To get these latest changes, +run this in a terminal: + +```sh +$ react-native upgrade +``` + +This will check your files against the latest template and perform the following: + +* If there is a new file in the template, it is simply created. +* If a file in the template is identical to your file, it is skipped. +* If a file is different in your project than the template, you will be prompted; you have options + to view a diff between your file and the template file, keep your file or overwrite it with the + template version. If you are unsure, press `h` to get a list of possible commands. + + +# Manual Upgrades + +Xcode project format is pretty complex and sometimes it's tricky to upgrade and merge new changes. + +### From 0.13 to 0.14 + +The major change in this version happened to the CLI ([see changelog](https://github.com/facebook/react-native/releases/tag/v0.14.0-rc)) and static images ([see docs](docs/images.html)). To use the new asset system in existing Xcode project, do the following: + +Add new "Run Script" step to your project's build phases: + +![](https://cloud.githubusercontent.com/assets/192222/11050044/871bf926-86f7-11e5-8908-736106457bcb.png) + +Set the script to +```sh +../node_modules/react-native/packager/react-native-xcode.sh +``` + +![](https://cloud.githubusercontent.com/assets/192222/11050052/8f098252-86f7-11e5-994a-364aabbaa7d1.png) + +Move main.jsbundle to Trash (it will be generated automatically by Xcode using the script above) + +![](https://cloud.githubusercontent.com/assets/192222/11050104/f3d025e2-86f7-11e5-9101-a4622236338d.png) + +If you installed Node via nvm, you might experience "react-native: command not found". See [issues/3974](https://github.com/facebook/react-native/issues/3974) for workaround and [pull/4015](https://github.com/facebook/react-native/pull/4015) for the fix. diff --git a/versions/v0.26.0/docs/Videos.md b/versions/v0.26.0/docs/Videos.md new file mode 100644 index 0000000..68537e1 --- /dev/null +++ b/versions/v0.26.0/docs/Videos.md @@ -0,0 +1,67 @@ +--- +id: videos +title: Videos +layout: docs +category: Community Resources +permalink: docs/videos.html +next: newsletter +--- + +### React.js Conf 2016 + + + + + + + + + + + + + + + + + + + + + + + + + + +### React.js Conf 2015 + + + + + + + + + + + + + + + +### [The Changelog #149](https://thechangelog.com/149/) +With Christopher "vjeux" Chedeau and Spencer Ahrens + + + +### [JSJabber #146](http://devchat.tv/js-jabber/146-jsj-react-with-christopher-chedeau-and-jordan-walke) +With Christopher "vjeux" Chedeau and Jordan Walke + + diff --git a/versions/v0.26.0/img/AddToBuildPhases.png b/versions/v0.26.0/img/AddToBuildPhases.png new file mode 100644 index 0000000..7b83937 Binary files /dev/null and b/versions/v0.26.0/img/AddToBuildPhases.png differ diff --git a/versions/v0.26.0/img/AddToLibraries.png b/versions/v0.26.0/img/AddToLibraries.png new file mode 100644 index 0000000..652cdfd Binary files /dev/null and b/versions/v0.26.0/img/AddToLibraries.png differ diff --git a/versions/v0.26.0/img/AddToSearchPaths.png b/versions/v0.26.0/img/AddToSearchPaths.png new file mode 100644 index 0000000..ccbe819 Binary files /dev/null and b/versions/v0.26.0/img/AddToSearchPaths.png differ diff --git a/versions/v0.26.0/img/AndroidSDK1.png b/versions/v0.26.0/img/AndroidSDK1.png new file mode 100644 index 0000000..9b9add7 Binary files /dev/null and b/versions/v0.26.0/img/AndroidSDK1.png differ diff --git a/versions/v0.26.0/img/AndroidSDK2.png b/versions/v0.26.0/img/AndroidSDK2.png new file mode 100644 index 0000000..a554e07 Binary files /dev/null and b/versions/v0.26.0/img/AndroidSDK2.png differ diff --git a/versions/v0.26.0/img/AnimationExperimentalOpacity.gif b/versions/v0.26.0/img/AnimationExperimentalOpacity.gif new file mode 100644 index 0000000..cdc7902 Binary files /dev/null and b/versions/v0.26.0/img/AnimationExperimentalOpacity.gif differ diff --git a/versions/v0.26.0/img/AnimationExperimentalScaleXY.gif b/versions/v0.26.0/img/AnimationExperimentalScaleXY.gif new file mode 100644 index 0000000..850cfd1 Binary files /dev/null and b/versions/v0.26.0/img/AnimationExperimentalScaleXY.gif differ diff --git a/versions/v0.26.0/img/CreateAVD.png b/versions/v0.26.0/img/CreateAVD.png new file mode 100644 index 0000000..5a3d494 Binary files /dev/null and b/versions/v0.26.0/img/CreateAVD.png differ diff --git a/versions/v0.26.0/img/EmbeddedAppAndroid.png b/versions/v0.26.0/img/EmbeddedAppAndroid.png new file mode 100644 index 0000000..126ba2d Binary files /dev/null and b/versions/v0.26.0/img/EmbeddedAppAndroid.png differ diff --git a/versions/v0.26.0/img/EmbeddedAppContainerViewExample.png b/versions/v0.26.0/img/EmbeddedAppContainerViewExample.png new file mode 100644 index 0000000..6130dfb Binary files /dev/null and b/versions/v0.26.0/img/EmbeddedAppContainerViewExample.png differ diff --git a/versions/v0.26.0/img/EmbeddedAppExample.png b/versions/v0.26.0/img/EmbeddedAppExample.png new file mode 100644 index 0000000..fefd306 Binary files /dev/null and b/versions/v0.26.0/img/EmbeddedAppExample.png differ diff --git a/versions/v0.26.0/img/LayoutAnimationExample.gif b/versions/v0.26.0/img/LayoutAnimationExample.gif new file mode 100644 index 0000000..68fcfce Binary files /dev/null and b/versions/v0.26.0/img/LayoutAnimationExample.gif differ diff --git a/versions/v0.26.0/img/Rebound.gif b/versions/v0.26.0/img/Rebound.gif new file mode 100644 index 0000000..0371663 Binary files /dev/null and b/versions/v0.26.0/img/Rebound.gif differ diff --git a/versions/v0.26.0/img/ReboundExample.png b/versions/v0.26.0/img/ReboundExample.png new file mode 100644 index 0000000..db33e5f Binary files /dev/null and b/versions/v0.26.0/img/ReboundExample.png differ diff --git a/versions/v0.26.0/img/ReboundImage.gif b/versions/v0.26.0/img/ReboundImage.gif new file mode 100644 index 0000000..9c1da74 Binary files /dev/null and b/versions/v0.26.0/img/ReboundImage.gif differ diff --git a/versions/v0.26.0/img/StaticImageAssets.png b/versions/v0.26.0/img/StaticImageAssets.png new file mode 100644 index 0000000..e79acdc Binary files /dev/null and b/versions/v0.26.0/img/StaticImageAssets.png differ diff --git a/versions/v0.26.0/img/SystraceBadCreateUI.png b/versions/v0.26.0/img/SystraceBadCreateUI.png new file mode 100644 index 0000000..813b101 Binary files /dev/null and b/versions/v0.26.0/img/SystraceBadCreateUI.png differ diff --git a/versions/v0.26.0/img/SystraceBadJS.png b/versions/v0.26.0/img/SystraceBadJS.png new file mode 100644 index 0000000..c67c840 Binary files /dev/null and b/versions/v0.26.0/img/SystraceBadJS.png differ diff --git a/versions/v0.26.0/img/SystraceBadJS2.png b/versions/v0.26.0/img/SystraceBadJS2.png new file mode 100644 index 0000000..de972c6 Binary files /dev/null and b/versions/v0.26.0/img/SystraceBadJS2.png differ diff --git a/versions/v0.26.0/img/SystraceBadUI.png b/versions/v0.26.0/img/SystraceBadUI.png new file mode 100644 index 0000000..ebd9faf Binary files /dev/null and b/versions/v0.26.0/img/SystraceBadUI.png differ diff --git a/versions/v0.26.0/img/SystraceExample.png b/versions/v0.26.0/img/SystraceExample.png new file mode 100644 index 0000000..521ee16 Binary files /dev/null and b/versions/v0.26.0/img/SystraceExample.png differ diff --git a/versions/v0.26.0/img/SystraceHighlightVSync.png b/versions/v0.26.0/img/SystraceHighlightVSync.png new file mode 100644 index 0000000..dc7595a Binary files /dev/null and b/versions/v0.26.0/img/SystraceHighlightVSync.png differ diff --git a/versions/v0.26.0/img/SystraceJSThreadExample.png b/versions/v0.26.0/img/SystraceJSThreadExample.png new file mode 100644 index 0000000..736af7d Binary files /dev/null and b/versions/v0.26.0/img/SystraceJSThreadExample.png differ diff --git a/versions/v0.26.0/img/SystraceNativeModulesThreadExample.png b/versions/v0.26.0/img/SystraceNativeModulesThreadExample.png new file mode 100644 index 0000000..7e919f2 Binary files /dev/null and b/versions/v0.26.0/img/SystraceNativeModulesThreadExample.png differ diff --git a/versions/v0.26.0/img/SystraceRenderThreadExample.png b/versions/v0.26.0/img/SystraceRenderThreadExample.png new file mode 100644 index 0000000..2fa05bd Binary files /dev/null and b/versions/v0.26.0/img/SystraceRenderThreadExample.png differ diff --git a/versions/v0.26.0/img/SystraceUIThreadExample.png b/versions/v0.26.0/img/SystraceUIThreadExample.png new file mode 100644 index 0000000..4883e85 Binary files /dev/null and b/versions/v0.26.0/img/SystraceUIThreadExample.png differ diff --git a/versions/v0.26.0/img/SystraceWellBehaved.png b/versions/v0.26.0/img/SystraceWellBehaved.png new file mode 100644 index 0000000..9540873 Binary files /dev/null and b/versions/v0.26.0/img/SystraceWellBehaved.png differ diff --git a/versions/v0.26.0/img/TutorialFinal.png b/versions/v0.26.0/img/TutorialFinal.png new file mode 100644 index 0000000..2f05b13 Binary files /dev/null and b/versions/v0.26.0/img/TutorialFinal.png differ diff --git a/versions/v0.26.0/img/TutorialFinal2.png b/versions/v0.26.0/img/TutorialFinal2.png new file mode 100644 index 0000000..75ec47c Binary files /dev/null and b/versions/v0.26.0/img/TutorialFinal2.png differ diff --git a/versions/v0.26.0/img/TutorialMock.png b/versions/v0.26.0/img/TutorialMock.png new file mode 100644 index 0000000..6a267d0 Binary files /dev/null and b/versions/v0.26.0/img/TutorialMock.png differ diff --git a/versions/v0.26.0/img/TutorialMock2.png b/versions/v0.26.0/img/TutorialMock2.png new file mode 100644 index 0000000..94c7f65 Binary files /dev/null and b/versions/v0.26.0/img/TutorialMock2.png differ diff --git a/versions/v0.26.0/img/TutorialSingleFetched.png b/versions/v0.26.0/img/TutorialSingleFetched.png new file mode 100644 index 0000000..914cb88 Binary files /dev/null and b/versions/v0.26.0/img/TutorialSingleFetched.png differ diff --git a/versions/v0.26.0/img/TutorialSingleFetched2.png b/versions/v0.26.0/img/TutorialSingleFetched2.png new file mode 100644 index 0000000..c7dfd69 Binary files /dev/null and b/versions/v0.26.0/img/TutorialSingleFetched2.png differ diff --git a/versions/v0.26.0/img/TutorialStyledMock.png b/versions/v0.26.0/img/TutorialStyledMock.png new file mode 100644 index 0000000..48fb1c5 Binary files /dev/null and b/versions/v0.26.0/img/TutorialStyledMock.png differ diff --git a/versions/v0.26.0/img/TutorialStyledMock2.png b/versions/v0.26.0/img/TutorialStyledMock2.png new file mode 100644 index 0000000..16e99c2 Binary files /dev/null and b/versions/v0.26.0/img/TutorialStyledMock2.png differ diff --git a/versions/v0.26.0/img/TweenState.gif b/versions/v0.26.0/img/TweenState.gif new file mode 100644 index 0000000..84f34d2 Binary files /dev/null and b/versions/v0.26.0/img/TweenState.gif differ diff --git a/versions/v0.26.0/img/Warning.png b/versions/v0.26.0/img/Warning.png new file mode 100644 index 0000000..ceeb6ed Binary files /dev/null and b/versions/v0.26.0/img/Warning.png differ diff --git a/versions/v0.26.0/img/alertIOS.png b/versions/v0.26.0/img/alertIOS.png new file mode 100644 index 0000000..b35a2a4 Binary files /dev/null and b/versions/v0.26.0/img/alertIOS.png differ diff --git a/versions/v0.26.0/img/chrome_breakpoint.png b/versions/v0.26.0/img/chrome_breakpoint.png new file mode 100644 index 0000000..d37c953 Binary files /dev/null and b/versions/v0.26.0/img/chrome_breakpoint.png differ diff --git a/versions/v0.26.0/img/favicon.png b/versions/v0.26.0/img/favicon.png new file mode 100644 index 0000000..22c120d Binary files /dev/null and b/versions/v0.26.0/img/favicon.png differ diff --git a/versions/v0.26.0/img/header_logo.png b/versions/v0.26.0/img/header_logo.png new file mode 100644 index 0000000..8858ffa Binary files /dev/null and b/versions/v0.26.0/img/header_logo.png differ diff --git a/versions/v0.26.0/img/opengraph.png b/versions/v0.26.0/img/opengraph.png new file mode 100644 index 0000000..0e9e1d3 Binary files /dev/null and b/versions/v0.26.0/img/opengraph.png differ diff --git a/versions/v0.26.0/img/react-native-android-sdk-environment-variable-windows.png b/versions/v0.26.0/img/react-native-android-sdk-environment-variable-windows.png new file mode 100644 index 0000000..6b3d981 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-sdk-environment-variable-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-additional-installs-linux.png b/versions/v0.26.0/img/react-native-android-studio-additional-installs-linux.png new file mode 100644 index 0000000..3a0eda5 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-additional-installs-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-additional-installs.png b/versions/v0.26.0/img/react-native-android-studio-additional-installs.png new file mode 100644 index 0000000..de32a09 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-additional-installs.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools-linux.png b/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools-linux.png new file mode 100644 index 0000000..10391c7 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools-windows.png b/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools-windows.png new file mode 100644 index 0000000..600ef3a Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools.png b/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools.png new file mode 100644 index 0000000..a1d80be Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-android-sdk-build-tools.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms-linux.png b/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms-linux.png new file mode 100644 index 0000000..8c43a49 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms-windows.png b/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms-windows.png new file mode 100644 index 0000000..a5cf175 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms.png b/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms.png new file mode 100644 index 0000000..34407b1 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-android-sdk-platforms.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-avd-linux.png b/versions/v0.26.0/img/react-native-android-studio-avd-linux.png new file mode 100644 index 0000000..de5f254 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-avd-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-avd-windows.png b/versions/v0.26.0/img/react-native-android-studio-avd-windows.png new file mode 100644 index 0000000..ddc8f47 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-avd-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-avd.png b/versions/v0.26.0/img/react-native-android-studio-avd.png new file mode 100644 index 0000000..74c053b Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-avd.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-configure-sdk-linux.png b/versions/v0.26.0/img/react-native-android-studio-configure-sdk-linux.png new file mode 100644 index 0000000..8bb9d5f Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-configure-sdk-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-configure-sdk-windows.png b/versions/v0.26.0/img/react-native-android-studio-configure-sdk-windows.png new file mode 100644 index 0000000..1adf5cb Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-configure-sdk-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-configure-sdk.png b/versions/v0.26.0/img/react-native-android-studio-configure-sdk.png new file mode 100644 index 0000000..acfe1f3 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-configure-sdk.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-custom-install-linux.png b/versions/v0.26.0/img/react-native-android-studio-custom-install-linux.png new file mode 100644 index 0000000..4410948 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-custom-install-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-custom-install-windows.png b/versions/v0.26.0/img/react-native-android-studio-custom-install-windows.png new file mode 100644 index 0000000..7ed385a Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-custom-install-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-custom-install.png b/versions/v0.26.0/img/react-native-android-studio-custom-install.png new file mode 100644 index 0000000..01ab7b2 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-custom-install.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-kvm-linux.png b/versions/v0.26.0/img/react-native-android-studio-kvm-linux.png new file mode 100644 index 0000000..dab0810 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-kvm-linux.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-no-virtual-device-windows.png b/versions/v0.26.0/img/react-native-android-studio-no-virtual-device-windows.png new file mode 100644 index 0000000..933a583 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-no-virtual-device-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-studio-verify-installs-windows.png b/versions/v0.26.0/img/react-native-android-studio-verify-installs-windows.png new file mode 100644 index 0000000..8f0cf1b Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-studio-verify-installs-windows.png differ diff --git a/versions/v0.26.0/img/react-native-android-tools-environment-variable-windows.png b/versions/v0.26.0/img/react-native-android-tools-environment-variable-windows.png new file mode 100644 index 0000000..5ddeb61 Binary files /dev/null and b/versions/v0.26.0/img/react-native-android-tools-environment-variable-windows.png differ diff --git a/versions/v0.26.0/img/react-native-congratulations.png b/versions/v0.26.0/img/react-native-congratulations.png new file mode 100644 index 0000000..92f520e Binary files /dev/null and b/versions/v0.26.0/img/react-native-congratulations.png differ diff --git a/versions/v0.26.0/img/react-native-sorry-not-supported.png b/versions/v0.26.0/img/react-native-sorry-not-supported.png new file mode 100644 index 0000000..8848f4c Binary files /dev/null and b/versions/v0.26.0/img/react-native-sorry-not-supported.png differ diff --git a/versions/v0.26.0/img/search.png b/versions/v0.26.0/img/search.png new file mode 100644 index 0000000..222fb66 Binary files /dev/null and b/versions/v0.26.0/img/search.png differ diff --git a/versions/v0.26.0/img/survey.png b/versions/v0.26.0/img/survey.png new file mode 100644 index 0000000..8baf2fa Binary files /dev/null and b/versions/v0.26.0/img/survey.png differ diff --git a/versions/v0.26.0/img/uiexplorer_main_android.png b/versions/v0.26.0/img/uiexplorer_main_android.png new file mode 100644 index 0000000..d510e7a Binary files /dev/null and b/versions/v0.26.0/img/uiexplorer_main_android.png differ diff --git a/versions/v0.26.0/img/uiexplorer_main_ios.png b/versions/v0.26.0/img/uiexplorer_main_ios.png new file mode 100644 index 0000000..2274ef2 Binary files /dev/null and b/versions/v0.26.0/img/uiexplorer_main_ios.png differ diff --git a/versions/v0.26.0/title.txt b/versions/v0.26.0/title.txt new file mode 100644 index 0000000..d577223 --- /dev/null +++ b/versions/v0.26.0/title.txt @@ -0,0 +1 @@ +% React Native 0.26.0 Manual diff --git a/versions/v0.26.0/toc.json b/versions/v0.26.0/toc.json new file mode 100644 index 0000000..2e826e7 --- /dev/null +++ b/versions/v0.26.0/toc.json @@ -0,0 +1,118 @@ +[ + { + "title": "Getting Started", + "file": "GettingStarted" + }, + { + "title": "Tutorial", + "file": "Tutorial" + }, + { + "title": "Style", + "file": "Style" + }, + { + "title": "Images", + "file": "Images" + }, + { + "title": "Gesture Responder System", + "file": "GestureResponderSystem" + }, + { + "title": "Animations", + "file": "Animations" + }, + { + "title": "Accessibility", + "file": "Accessibility" + }, + { + "title": "Direct Manipulation", + "file": "DirectManipulation" + }, + { + "title": "Debugging", + "file": "Debugging" + }, + { + "title": "Testing", + "file": "Testing" + }, + { + "title": "JavaScript Environment", + "file": "JavaScriptEnvironment" + }, + { + "title": "Navigator Comparison", + "file": "NavigatorComparison" + }, + { + "title": "Known Issues", + "file": "KnownIssues" + }, + { + "title": "Performance", + "file": "Performance" + }, + { + "title": "Upgrading", + "file": "Upgrading" + }, + { + "title": "Platform Specific Code", + "file": "PlatformSpecificInformation" + }, + { + "title": "Native Modules IOS", + "file": "NativeModulesIOS" + }, + { + "title": "Native UI Components IOS", + "file": "NativeComponentsIOS" + }, + { + "title": "Linking Libraries", + "file": "LinkingLibraries" + }, + { + "title": "Running On IOS", + "file": "RunningOnDeviceIOS" + }, + { + "title": "Integrating with Existing IOS Apps", + "file": "EmbeddedAppIOS" + }, + { + "title": "Communication between IOS and React Native", + "file": "CommunicationIOS" + }, + { + "title": "Native Modules Android", + "file": "NativeModulesAndroid" + }, + { + "title": "Native UI Components Android", + "file": "NativeComponentsAndroid" + }, + { + "title": "Running On Android", + "file": "RunningOnDeviceAndroid" + }, + { + "title": "Integrating with Existing Android Apps", + "file": "EmbeddedAppAndroid" + }, + { + "title": "Generating Signed APK", + "file": "SignedAPKAndroid" + }, + { + "title": "Profiling Android UI Performance", + "file": "AndroidUIPerformance" + }, + { + "title": "Building React Native From Source", + "file": "AndroidBuildingFromSource" + } +]