Compare commits

...
29 Commits
Author SHA1 Message Date
Mike Grabowski 70fe990778 [0.29.1] Bump version numbers 2016-07-13 14:56:59 +02:00
Andy StreetandMike Grabowski 27251015d9 Don't hard crash if you get a null stack trace in Android
Summary: If stacktrace-parser can't parse a stack trace, it'll return null. This can cause us to accidentally enter a crash loop where whenever you start your app, you load the last JS bundle you had, get a crash, and then hard crash trying to print the stack trace.

Reviewed By: frantic

Differential Revision: D3528141

fbshipit-source-id: 1146f43bc40492bfa79b6a1c0f81092383896164
2016-07-13 14:07:16 +02:00
Nicolas CharpentierandMike Grabowski dc57f95706 Remove instructions about IP address on iOS
Summary:
The documentation was not updated after this change : Implemented automatic IP detection for iOS (8c29a52)

Fixes #8651.
Closes https://github.com/facebook/react-native/pull/8660

Differential Revision: D3539749

fbshipit-source-id: fe3b37c446a8c37941adbb08c4301284950a176a
2016-07-13 14:07:04 +02:00
Spencer AhrensandMike Grabowski 4dabb575b1 Fix bug in cancelling last task in TaskQueue
Summary:
We don't want to remove the last queue from the stack, it should just have no tasks in it.

Fixes issue reported here: https://www.facebook.com/groups/reactnativeoss/permalink/1569170356712926/

Reviewed By: yungsters

Differential Revision: D3539287

fbshipit-source-id: ea95673491fee0ea82f0f1b79b8f60e00cd3d035
2016-07-13 14:06:57 +02:00
Andy StreetandMike Grabowski b361490613 Fix 'Unexpected EOF' in old bridge
Summary: This is caused by receiving \u2028/2029 in callbacks/function calls. The correct solution is to not evaluate these strings as scripts but instead parse them as json and pass them through the JSC API.

Reviewed By: lexs

Differential Revision: D3543098

fbshipit-source-id: 4d8acce1d510bb17361d32103d4738fc0208b0a8
2016-07-13 14:06:35 +02:00
GantandMike Grabowski 214a41d62a changes link file on Android to MainApplication.java for 0.29 update
Summary:
rnpm aka `react-native link` is broken with Android 0.29 - #8603

This gets it back to working again by checking for new MyApplication.java file, and curtailing the path when needed.
Closes https://github.com/facebook/react-native/pull/8612

Differential Revision: D3533960

fbshipit-source-id: 95d799eaebb26ba1d876c88107ccd2af72427f55
2016-07-13 14:06:27 +02:00
Ritesh KadmawalaandMike Grabowski 4d70b85f2f Fixed the issue due to which js assets are not bundled in the apk when separate build for different CPU architectures is enabled
Summary:
This PR tries to fix a minor bug in `react.gradle` due to which task that bundles JS into the assets folder of the APK is not run when separate build per CPU architecture is enabled and we are using different product flavors.
Closes https://github.com/facebook/react-native/pull/8675

Differential Revision: D3541348

fbshipit-source-id: 4c84f21a06a45046f84bdd8ae5c5d834ec080476
2016-07-13 14:06:21 +02:00
Joel MarceyandKonstantin Raev eb55b99e53 Cherry-pick: Fix Navigation Links (#8703)
* Introduce navigators in the tutorial

Summary:
Adds a new section to the tutorial. Covers the basics of scenes and navigators.

The navigator comparison doc has been moved to docs/navigation.html in this PR.

![navigators](https://cloud.githubusercontent.com/assets/165856/16505919/37459e3a-3ed4-11e6-87e9-5fa7e6f792d3.png)
Closes https://github.com/facebook/react-native/pull/8515

Differential Revision: D3507325

Pulled By: caabernathy

fbshipit-source-id: e9ee5b2572868189af198cdf461b2728dfa84f9e

* Fix links from networking to navigation in The Basics.

Summary:
Fixes #8611.

Once this lands, we may want to cherry-pick it into 0.29 to fix the broken links.
Closes https://github.com/facebook/react-native/pull/8698

Differential Revision: D3544388

Pulled By: JoelMarcey

fbshipit-source-id: d5132b112e3079d1fd9ab6d84ff1a4328bee871f
2016-07-12 10:28:32 +01:00
Mike Grabowski 455496785a [0.29.0] Bump version numbers 2016-07-06 00:59:33 +02:00
Joel MarceyandGitHub 85bdc46b67 Merge pull request #8566 from JoelMarcey/post-lockdown-survey-to-0.29
0.29 cherry-pick: Add post documentation lockdown survey link
2016-07-05 12:57:45 -04:00
Konstantin Raev ab1bc0a769 [0.29.0-rc.3] Bump version numbers 2016-07-05 16:59:33 +01:00
Konstantin Raev 2f8cb25a1c [0.29.0-rc3] Bump version numbers 2016-07-05 16:59:06 +01:00
Alexey LangandKonstantin Raev 58e988b655 Change API for iOS
Reviewed By: michalgr

Differential Revision: D3514778

fbshipit-source-id: 29dc12ad0a701fd08262be3aa81ae990d4fc63a9
2016-07-05 16:58:38 +01:00
Joel Marcey 9f14dd0e53 Add post documentation lockdown survey link
Summary:
We did a survey prior to the doc lockdown to get an idea of what we should focus on. Now we have a yes/no style survey to ensure that we met the user needs when it came to our start of improving the docs.

This diff adds the survey link to the bottom of each page. And we will cherry-pick it into 0.29 as well, which will be the first official release with the new doc content

> **NOTE**: The content via the links in this survey will not be valid until 0.29 is actually released. So I have not enabled the questions for the survey until then.

**Test Plan:**

http://localhost:8079/react-native/docs/getting-started.html

<img width="753" alt="screenshot 2016-07-01 17 35 17" src="https://cloud.githubusercontent.com/assets/3757713/16535354/987dd3a8-3fb4-11e6-81b7-1a1fcffd3bb2.png">
Closes https://github.com/facebook/react-native/pull/8530

Differential Revision: D3515242

Pulled By: JoelMarcey

fbshipit-source-id: c2d241d472853dfb3f9e7d3ae9560b318aacb866
2016-07-04 15:55:43 -04:00
James Ide 288867c510 [0.29.0-rc.2] Bump version numbers 2016-07-01 17:40:38 -07:00
Ben AlpertandJames Ide 354dc2cd57 Update to React 15.2.0 final
Summary: This should have literally no changes from the RC that affect RN -- just a version bump.

Reviewed By: vjeux

Differential Revision: D3511116

fbshipit-source-id: 5bb3a330c0d2e78a2f3dfbb0e948c99607d2e66e
2016-07-01 17:13:05 -07:00
Joel ArvidssonandJames Ide 9f9408a4b3 Add RCTAnimation to Podspec
Summary:
**Motivation**

This PR adds a subspec for the `NativeAnimation` iOS library which so one can use it with CocoaPods.

**Test plan (required)**

Tested with the code in `NativeAnimationsExample.js` and this:
```
pod 'React', :subspecs => ['Core', 'RCTAnimation'], :path => 'node_modules/react-native'
```
Closes https://github.com/facebook/react-native/pull/8487

Differential Revision: D3502970

fbshipit-source-id: 0958acdbe088da8b50a1e5e3661f27b64db329c1
2016-07-01 17:13:05 -07:00
Nathan AzariaandJames Ide 9f9c6a8b38 Fixed setDefaults not being called in React Native apps, fixed typo
Reviewed By: javache

Differential Revision: D3469296

fbshipit-source-id: 032472fede4bfbd051b0f725f35368b22edcc130
2016-07-01 17:13:05 -07:00
Redmar KerkhoffandJames Ide 8839b6d09d Fixes ActivityIndicatorIOS doesn't hide initially
Summary:
I used the reproducible steps as described in origin bug ticket #7987 as test plan.
This has the same contents as PR #8130 but then against master per janicduplessis request.
Closes https://github.com/facebook/react-native/pull/8134

Differential Revision: D3491126

fbshipit-source-id: a22669dc998f82b36fbe31d882d0a29f0912e2ee
2016-07-01 17:13:05 -07:00
Hedger WangandJames Ide 0a2ef025fa Fix transtion props layout in NavigationTransitioner.
Summary: When layout is measure, transtion props should be updated.

Reviewed By: ericvicenti

Differential Revision: D3479967

fbshipit-source-id: 14bcd96b9691b7ee68689393b4fef51dbd04b69f
2016-07-01 17:13:05 -07:00
Eric VicentiandJames Ide c412d2506f Fix stale scene cleanup
Summary: Previously we would not re-compute `this._transitionProps` after cleaning up stale scenes, so the render caused by setState still had the stale scenes in the props

Reviewed By: hedgerwang

Differential Revision: D3471011

fbshipit-source-id: fd08ef7a21355a229e877c85f06d6584eb44f38e
2016-07-01 17:13:04 -07:00
Hedger WangandJames Ide 9819681625 Pass the current and previous transition props to render, onTransitionStart and onTransitionEnd.
Summary: This shall make it convenient to handle transition changes.

Reviewed By: ericvicenti

Differential Revision: D3442291

fbshipit-source-id: aee0ffe18ada40ef133484b4a4999f282c66c181
2016-07-01 17:13:04 -07:00
Martin Konicek 8e376f3ce6 [0.29.0-rc.1] Bump version numbers 2016-07-01 23:59:44 +01:00
Vitaly GorodetskyandMartin Konicek cf97c9a096 adds log-ios and log-android cli commands
Summary:
solves first part of #8186
Closes https://github.com/facebook/react-native/pull/8352

Differential Revision: D3475905

Pulled By: mkonicek

fbshipit-source-id: 99f6aa15b92ba3192fa0b812d369bd7020469573
2016-07-01 23:58:35 +01:00
Joel MarceyandGitHub 14bb6fa87c Merge pull request #8514 from JoelMarcey/image-pr-to-0.29
Cherry-pick in 0.29: Specify width and height for Image(remote source)
2016-06-30 15:37:26 -07:00
sunnylqmandJoel Marcey 561cfc626f Specify width and height for Image(remote source)
Summary: Closes https://github.com/facebook/react-native/pull/8486

Differential Revision: D3496850

Pulled By: javache

fbshipit-source-id: f2456b914c420089558484fb87e3d92ed2c923af
2016-06-30 14:50:15 -07:00
Joel MarceyandKonstantin Raev 17b127263d Additional docdown commits to 0.29 (#8492)
* Initial stab at NavigationExperimental tutorial

Summary:
Add a NavigationExperimental section to the Navigation guide.

![navexp](https://cloud.githubusercontent.com/assets/165856/16355280/120e7d38-3a67-11e6-9567-51c19c249fdf.png)
Closes https://github.com/facebook/react-native/pull/8431

Differential Revision: D3493158

Pulled By: JoelMarcey

fbshipit-source-id: 5e9646c3abf97f5cce6f5ba5b3d10853aa84ee8e

* Change method name color for API/Component methods

Summary: Closes https://github.com/facebook/react-native/pull/8481

Differential Revision: D3497267

Pulled By: JoelMarcey

fbshipit-source-id: 82ffb17a9ec3110481ad64d5065fc9fee6a31808
2016-06-29 08:18:52 -07:00
Joel MarceyandKonstantin Raev 7ac931ee9b Publish DocDown Commits Into Next Release (0.29) (#8480)
* Separate Out Core Components Into Individual Parts

Summary:
Will create new issue to add more information to the `Components` section of the Tutorial
since that was gutted by this change.

Fixes #8156
Closes https://github.com/facebook/react-native/pull/8256

Differential Revision: D3459601

Pulled By: JoelMarcey

fbshipit-source-id: 4038afc463bffcf8efda36d29bc7c443bbc8f4bd

* Cleanup troubleshooting and debugging docs.

Summary:
This is a followup to #8010. Troubleshooting has been updated to list only those issues that may affect a user that is setting up their environment. Any issues related to day to day use have been moved or merged into a more relevant doc.
Closes https://github.com/facebook/react-native/pull/8254

Reviewed By: caabernathy

Differential Revision: D3459018

Pulled By: JoelMarcey

fbshipit-source-id: dd76097af34bd33dda376fab39fb0f71061ef3e4

* Remove survey link

Summary:
We have enough responses now and we are in the lockdown for improving the documentation.

We can add another "did we improve?" survey after lockdown sometime.
Closes https://github.com/facebook/react-native/pull/8260

Differential Revision: D3463284

Pulled By: JoelMarcey

fbshipit-source-id: f2d585a8aa6308de0cce0bea3974b1e7f14d5a6f

* Add docs to show how to select specific simulator.

Summary:
Add a message to let people know they can use the `--simulator` flag to run their apps on different simulators instead of the default "iPhone 6"
Closes https://github.com/facebook/react-native/pull/8078

Differential Revision: D3464912

Pulled By: JoelMarcey

fbshipit-source-id: b59d5061d2b3501618602932fcc285bac99b7573

* Add ScrollView to Basics docs

Summary:
Add basic information about the generic `ScrollView` -- talk a bit about how it renders elements and a quick compare against something like a `ListView`. Provide a simple example.

Fixes #8261
Closes https://github.com/facebook/react-native/pull/8266

Differential Revision: D3465105

Pulled By: JoelMarcey

fbshipit-source-id: 3a2e1eac6e877669763fc6b8bb0fc78ebe870ab1

* Improve autogen for reference docs including jsdoc support

Summary:
As part of improving the API and Component reference docs #8154 this pull request adds the following:

- jsdoc support for API docs. See the AlertIOS changes as an example.
- type definitions support and added to both API and Component docs. This is supported via react-docgen and jsdoc.
- better formatting of method properties (now shown in a table).

FYI, API and Component docs were previously generated in two different ways. Components were using react-docgen and that basically remains as-is. APIs were using custom parsing code and that's been switched to use a jsdoc parser + react-docgen as an option for typedefs (it could also use the jsdoc parser).

Two docs have been updated to showcase how we'd like the new docs to look:

- AlertIOS (API): showing method parameters, examples, typedefs, more details overall.
- Statusbar (Component): showing method parameters, typedefs, more details overall.

**Note**: To convert new API docs to use the new format, add `jsdoc` to the initial file comment. C
Closes https://github.com/facebook/react-native/pull/8196

Differential Revision: D3465037

Pulled By: lacker

fbshipit-source-id: 78415d44bc5be02db802f5b1f7a0b249689abdf7

* overhaul showcase

Summary:
The motivation is that the showcase is becoming far too large to be useful. I filtered the apps for, basically, "apps that have some sort of interesting news coverage or technical blog post about them". The UI is a bit updated to also mention something about the information link. I also added the FB app itself.
Closes https://github.com/facebook/react-native/pull/8263

Differential Revision: D3463856

Pulled By: JoelMarcey

fbshipit-source-id: cdd309ba85edca417868f14dee7c772f73af654b

* New React Native Landing Page

Summary:
The motivation is that we haven't changed the copy on the initial React Native landing page since launching, and we have a much clearer view of the React Native value prop now.

Themes:
1. React Native is like React but for mobile apps
2. A React Native app is a "real native app"
3. Development is fast
4. You can drop down to normal native development if you need
Closes https://github.com/facebook/react-native/pull/8291

Differential Revision: D3466855

Pulled By: JoelMarcey

fbshipit-source-id: d1a5035640bcd795704d5f830b79e7c3d2e3ab02

* Move Videos and Newsletter to Support

Summary:
Simplify the sidebar. We have Twitter feed in support. These have
a community feel as well.
Closes https://github.com/facebook/react-native/pull/8287

Differential Revision: D3467042

Pulled By: lacker

fbshipit-source-id: 60749d0cb31f284dae7c5402bfcde7b4d01aa32f

* Include info about console.log

Summary:
I spent so much time trying to optimize my JS without noticing this.
Closes https://github.com/facebook/react-native/pull/8285

Differential Revision: D3468707

fbshipit-source-id: bd5ff38ca2501891318b4be3c75bdaa10a4c64da

* Add a new Handling Touches guide

Summary:
The new Handling Touches guide provides an overall view of how touches can be handled. It is meant to be a higher level discussion of basic touch handling, e.g. "how do I implement a button?". The existing Gesture Responder System guide has been moved to the end of the docs and is still available for reference when building custom gesture handlers.

Reference: #8160

![handlingtouchesguide](https://cloud.githubusercontent.com/assets/165856/16256634/50a20c92-3808-11e6-8a5b-b49f2cda9fca.png)
Closes https://github.com/facebook/react-native/pull/8299

Differential Revision: D3469681

Pulled By: JoelMarcey

fbshipit-source-id: 3bc18e759b26c2d5c141b626acb433c5e973cef0

* Remove Polyfills section from sidebar

Summary:
Some of these will be in basics, guides and apis instead. One less layer
of confusion.

> Note: APIs are not totally alphabetical any longer -- but neither were
Polyfills. We can fix that in `extractDocs.js` maybe. But not worth doing
in this pull request, imho.
Closes https://github.com/facebook/react-native/pull/8293

Differential Revision: D3469684

Pulled By: JoelMarcey

fbshipit-source-id: 4f7830ca10b8e4406df9cec8bf13ff150e355250

* Docs: Basic Components Update

Summary:
This is an improvement to basic components docs.

* I updated the basic components example code to better render components on iOS (added paddingTop).
* I also modified the code to allow reader to easily copy, paste, and then run the code in their project if they followed the 'Getting Started' quick start guide.
* I also added additional copy to clarify suggested usage/guidelines.
Closes https://github.com/facebook/react-native/pull/8292

Differential Revision: D3469943

Pulled By: JoelMarcey

fbshipit-source-id: 21ff6ee13b59741c43d80aab68a38aace0fbfca6

* Add react-native-web-player to core components docs

Summary:
This PR adds the interactive [React Native Web Player](http://dabbott.github.io/react-native-web-player/) to the docs. The web player is an embeddable iframe which runs React Native code using components from [react-native-web](https://github.com/necolas/react-native-web). For now, it's primarily for educational purposes, since only the basic components are implemented.

Some details:
- The iframe is loaded from MaxCDN using rawgit, locked down to a git tag.
- Asset paths (i.e. images) are resolved relative to `//facebook.github.io/react-native/`
- When viewed on mobile, it falls back to the syntax-highlighted code blocks.

The WebPlayer can be inserted into markdown by using the fences:

```
```ReactNativeWebPlayer

import ...

AppRegistry.registerComponent ...

`` `
```

![screen shot 2016-06-22 at 12 46 50 pm](https://cloud.githubusercontent.com/assets/1198882/16281068/7056804e-3877-11e6-82f7-ece245690548.png)

I didn't actually add the WebPlayer to any docs pages in this PR. That we c
Closes https://github.com/facebook/react-native/pull/8328

Differential Revision: D3471527

Pulled By: lacker

fbshipit-source-id: 704da41cd77e08c7e2bc820557a74d36e88e8eb7

* More Resources doc, updating Support doc and quickstart too

Summary:
TLDR even more docs changes

So I created a More Resources doc that aggregates the high-quality-but-off-site stuff. Let's try to put more outlinks there. Also I removed the stuff on Support that was not support, and some misc changes to clean stuff up.
Closes https://github.com/facebook/react-native/pull/8329

Differential Revision: D3471669

Pulled By: JoelMarcey

fbshipit-source-id: 54edd543ced1b3a8f3d0baca5475ac96bae6e487

* Add React Native Web Player to most component basics

Summary:
> ListView is not supported by React Native Web as of yet, so it will not have it.
Closes https://github.com/facebook/react-native/pull/8331

Differential Revision: D3472019

Pulled By: lacker

fbshipit-source-id: e5fb430b6c8f4d437943c159beb00b9d9252c92d

* Update Navigator component doc

Summary:
Related to #8203 to update the Navigator component reference doc.

**Test plan (required)**

Started up the website and checked:
http://localhost:8079/react-native/docs/navigator.html

![component_navigator_2](https://cloud.githubusercontent.com/assets/691109/16280426/3f2cdc32-3874-11e6-810b-ca34d7bd4972.png)

**Note**

The code is not Flow-ified so depended on jsdoc formatting to get the method parameter types. There's a current issue with handling optional types via react-docgen which parses components. There's an open PR to look into this: https://github.com/reactjs/react-docgen/pull/89. When that's resolved the `replaceAtIndex` method parameter type that's documented for `cb` needs to be updated to make it optional.
Closes https://github.com/facebook/react-native/pull/8318

Differential Revision: D3471185

Pulled By: JoelMarcey

fbshipit-source-id: 99f85ee2ab00dc200cf2812cce5b3ccec743d6a0

* fix Firefox bug

Summary:
The motivation is that the getting started page was not working in some cases in Firefox.

This line of code appears to be at best a no-op, at worst fails in Firefox, since "event" is undefined.
Closes https://github.com/facebook/react-native/pull/8335

Differential Revision: D3473333

Pulled By: JoelMarcey

fbshipit-source-id: 40581e83126675aa072c6ee25609cfb787015ce7

* Fix guides docs to es2015 classes and remove flowtype from Animation example

Summary:
1. Animation guide page is the only place where Flowtype is used, it would be better to remove it to prevent some confusion.

2. ES2015 classes in guidelines docs pages and fixed some typos

**Test plan (required)**

Should i write any tests for this?
Closes https://github.com/facebook/react-native/pull/8339

Differential Revision: D3474192

Pulled By: bestander

fbshipit-source-id: 5531d1e399eaed0952732ac2e0bd1effc72d00a8

* Update Views API documentation

Summary:
Ensure all `props` have documentation. Add more details to current `props`.
Provide more information to the API in general.

> Would like to try to integrate the React Native Web Player for the initial
> example, but not right now.
Closes https://github.com/facebook/react-native/pull/8341

Differential Revision: D3475105

Pulled By: caabernathy

fbshipit-source-id: 00ad30b2359831740715517278bec1d0231e089d

* Fixes #8252: Document how to connect to a non-default packager port o…

Summary:
Added some documentation to the `RunningOnDeviceAndroid.md` with screenshots to set custom port
Closes https://github.com/facebook/react-native/pull/8355

Differential Revision: D3475846

Pulled By: mkonicek

fbshipit-source-id: 73675b19e2bb93c859bda239f228da0883f0e305

* Add docs pages for basics: Dimensions and Layout

Summary:
These pages should sufficiently give a beginner enough information to make most layouts in React Native. They should go after the basics-style page, whenever that is ready.

Having a single page for Layout was too much, so I split it into two: Dimensions and Layout.

![dimensions react native a framework for building native apps using react](https://cloud.githubusercontent.com/assets/1198882/16311045/c6918b64-3923-11e6-8cc9-daeda9eb40e6.png)

![layout react native a framework for building native apps using react](https://cloud.githubusercontent.com/assets/1198882/16310233/9a66405a-3920-11e6-9ef6-1594f7228e83.png)

lacker
Closes https://github.com/facebook/react-native/pull/8364

Differential Revision: D3477147

Pulled By: lacker

fbshipit-source-id: 1ef31ac0a64e43166a7581b38fa8263282672eeb

* ES6-ify ListView Basics

Summary:
Fixes #8184
Closes https://github.com/facebook/react-native/pull/8370

Differential Revision: D3477196

Pulled By: caabernathy

fbshipit-source-id: 929f84b3f8edaf03f918bb04fb9dbb48b4884b18

* Fix nits in update View API documentation

Summary:
Ref comments in #8341

Ref #8203
Closes https://github.com/facebook/react-native/pull/8361

Differential Revision: D3477174

Pulled By: caabernathy

fbshipit-source-id: 495011c2d370d06d355e966d6ba2c52880146183

* ES6-ify ScrollView basics

Summary: Closes https://github.com/facebook/react-native/pull/8368

Differential Revision: D3477381

Pulled By: caabernathy

fbshipit-source-id: 0c43a9b8309db8f268a2776ebff2b4e52df559df

* ES6-ify View Basics

Summary: Closes https://github.com/facebook/react-native/pull/8366

Differential Revision: D3477409

Pulled By: caabernathy

fbshipit-source-id: 5906e8dffc7884a6ed527fada5f907702a72c08f

* ES6-ify Image Basics

Summary: Closes https://github.com/facebook/react-native/pull/8365

Differential Revision: D3477411

Pulled By: caabernathy

fbshipit-source-id: 26214fcf13c9e1352e198f34fcd6f5e88f1fe2da

* ES6-ify TextInput Basics

Summary: Closes https://github.com/facebook/react-native/pull/8367

Differential Revision: D3477404

Pulled By: caabernathy

fbshipit-source-id: 16c279853b5c7a2d24033ef0d987da52dd148b24

* ES6-ify Text Basics

Summary: Closes https://github.com/facebook/react-native/pull/8363

Differential Revision: D3477431

Pulled By: caabernathy

fbshipit-source-id: 86ee5efb84e50609fbfae82102b1dc61fea69f05

* Update NavigatorIOS component doc

Summary:
Reference: #8203

Changes made:

- Added more to the intro section and updated the intro examples to ES6
- Added more details to prop explanations
- Added parameter descriptions for methods

**Test plan (required)**

Ran the website locally and checked: http://localhost:8079/react-native/docs/navigatorios.html

![component_navigatorios_2](https://cloud.githubusercontent.com/assets/691109/16315939/1501ba2a-3939-11e6-8ec0-54b43e03b323.png)
Closes https://github.com/facebook/react-native/pull/8334

Differential Revision: D3476066

Pulled By: JoelMarcey

fbshipit-source-id: 9fcefe3f9d59008d8c72683c57cb004d1f185f62

* Update webview doc

Summary:
Reference: #8203

Changes made:

Added a webview example to the intro section
Added more details to prop explanations
Test plan (required)

Ran the website locally and checked: http://localhost:8079/react-native/docs/webview.html

![component_webview_2](https://cloud.githubusercontent.com/assets/691109/16316552/f6847c56-393b-11e6-8fdd-a0b61e7f787b.png)
Closes https://github.com/facebook/react-native/pull/8372

Differential Revision: D3477685

Pulled By: JoelMarcey

fbshipit-source-id: a624f5c6c12a8367aea2a6e7c2e520da7a074bbd

* Move everything out of Known Issues and into more appropriate locations.

Summary:
Two of the known issues have been moved to the issue tracker:

* #8315
* #8316

Others have been moved into more appropriate locations, such as the `TextInput` issue to the API doc itself, and the React debugging issue to the Debugging doc.

The Android-specific compatibility concerns have been dropped entirely as it does not seem like people would find these in the docs.
Closes https://github.com/facebook/react-native/pull/8321

Differential Revision: D3477999

Pulled By: JoelMarcey

fbshipit-source-id: dfffc9910ebf5514eb14c6aa8a9a3e70761db874

* Make a new "Style" doc that's in The Basics and uses the RNWP

Summary:
The example uses StyleSheet.create and also arrays-of-styles. I think this covers everything the old one did, but in simple-enough-for-the-basics form, so I removed the old one. I also reordered so that "Style -> Dimensions -> Layout" is the flow for learning "Styley" things.
Closes https://github.com/facebook/react-native/pull/8379

Differential Revision: D3478384

Pulled By: caabernathy

fbshipit-source-id: 158f0f0367c8eb8b2b24feda0d8d7a533fd7af4d

* Add `extends Component` to Dimensions and Layout Basics Examples

Summary:
It works without out the `extends`, but I do not really understand why,
unless there is some magic implicit `extends` if you don't put it and
you call `registerComponent`. But, I figure we should be explicit unless
there is a good reason not to be.
Closes https://github.com/facebook/react-native/pull/8377

Differential Revision: D3478950

Pulled By: JoelMarcey

fbshipit-source-id: 05ea4367c3c8c34aea6c092639ee51d8761bca3f

* Bring out prop descriptions, for Flexbox

Summary:
For Flexbox API docs would like to tease out the prop descriptions. This PR makes that feasible by exposing the description for style.

**Test plan (required)**

1. Temporarily modified the flexbox source doc: Libraries/StyleSheet/LayoutPropTypes.js to add a description.
2. Checked it out on local webpage: http://localhost:8079/react-native/docs/flexbox.html

![style_prop_descriptions](https://cloud.githubusercontent.com/assets/691109/16321579/866b186e-3952-11e6-823a-2d38132bd553.png)
Closes https://github.com/facebook/react-native/pull/8382

Differential Revision: D3478796

Pulled By: lacker

fbshipit-source-id: 49f3b7876ff1ccec9ee837921a78ee0dfb915453

* Update web player in docs for custom registerComponent names

Summary:
In the web player in the docs, allows `AppRegistry.registerComponent('name', App)` to use *anything* for `'name'`. It is ignored by the web player - last registration wins.
Closes https://github.com/facebook/react-native/pull/8383

Differential Revision: D3478922

Pulled By: JoelMarcey

fbshipit-source-id: 3d1d96e0ad41216d29134ba384896e86d0cd2b32

* Networking Guide

Summary:
Simplified Networking Guide, based on the old Network polyfill doc.

This guide strongly recommends using fetch, while still informing the user about React Native's support for other libraries.

In order to provide an actual working networking example, a `movies.json` file is added at the root of the site, allowing the user to fetch a small blob of JSON:

```
fetch('http://facebook.github.io/react-native/movies.json')
```

![networking](https://cloud.githubusercontent.com/assets/165856/16321804/d2bd7c6a-3953-11e6-9fc5-30baaa38d7a4.png)
Closes https://github.com/facebook/react-native/pull/8381

Differential Revision: D3479018

Pulled By: lacker

fbshipit-source-id: 1f2078bf2414a13f7f77d5af55b08948909093a3

* Move Component Embedded Simulator next to its example

Summary:
Right now the embedded simulator is always at the top right corner.
This can be confusing as to what code is associated with the simulation.

So, move the simulator next to its actual code.

This has the added benefit of allowing us to use the React Native
Web Player for the simpler examples in the components.
Closes https://github.com/facebook/react-native/pull/8384

Differential Revision: D3479056

Pulled By: bestander

fbshipit-source-id: f400d8387ec771b94d5e798c1e955b25f9a0f1bf

* fix bugs on landing page code, make the url an easter egg

Summary:
This is just improving a bit of lameness on the homepage - Devin pointed out the <>'s don't work within a Text tag, so I removed them, and someone else pointed out that nonexistent fake urls are suboptimal, so I improved that too.
Closes https://github.com/facebook/react-native/pull/8387

Differential Revision: D3479087

Pulled By: JoelMarcey

fbshipit-source-id: 45a2d21a9073b58b869e8b344550c28f849e0185

* Api documentation update for modal.js

Summary:
Related to #8203 to update the Modal API reference doc.

**Test plan (required)**

Started up the website and checked:
http://localhost:8079/react-native/docs/modal.html

![modal update](https://cloud.githubusercontent.com/assets/23874/16316792/ecde19cc-393c-11e6-8136-16243a199d9b.png)

**Note, copied from a previous PR**

The code is not Flow-ified so depended on jsdoc formatting to get the method parameter types. There's a current issue with handling optional types via react-docgen which parses components. There's an open PR to look into this: https://github.com/reactjs/react-docgen/pull/89. When that's resolved the `replaceAtIndex` method parameter type that's documented for `cb` needs to be updated to make it optional.
Closes https://github.com/facebook/react-native/pull/8375

Differential Revision: D3479536

Pulled By: caabernathy

fbshipit-source-id: de2db3aa221e4adce0c0c5f3d94a1fad528a60da

* Update MapView doc

Summary:
Reference: #8203

Changes made:

- Added a MapView example to the intro section
- Added more details to prop explanations
- Added more info to an exported type, even if it's not used anywhere I can see
- Removed mention of ios platform in props. Left an android one in there as I didn't want to touch code.

**Test plan (required)**

Ran the website locally and checked: http://localhost:8079/react-native/docs/mapview.html

![component_mapview_2](https://cloud.githubusercontent.com/assets/691109/16329753/43419508-3999-11e6-9310-11c53ca8c04b.png)
Closes https://github.com/facebook/react-native/pull/8389

Differential Revision: D3481609

Pulled By: JoelMarcey

fbshipit-source-id: 71e35ce49193dc09d40546ff16bc48559135d63f

* Accessing console logs

Summary:
Instructions for accessing the output of a `console.log`.

![debugging](https://cloud.githubusercontent.com/assets/165856/16318119/7aff884e-3942-11e6-9a78-853aaba68308.png)
Closes https://github.com/facebook/react-native/pull/8323

Differential Revision: D3480718

Pulled By: JoelMarcey

fbshipit-source-id: 4185d2e730277b8ad986d3c8904420e7ae1ceb21

* Add Navigation Overview

Summary:
Initial stab at writing a high level guide on navigation. Its main focus is on Navigator due to it being cross-platform and fairly simple to use.

This guide should be expanded to cover tabbed applications in a future pull request.

The Navigation (Experimental) section will be similarly expanded upon as the API stabilizes.

![navigation](https://cloud.githubusercontent.com/assets/165856/16324560/52b508dc-396a-11e6-94b7-b2d1175f69e0.png)
Closes https://github.com/facebook/react-native/pull/8390

Differential Revision: D3480304

Pulled By: caabernathy

fbshipit-source-id: 280da9185fca295bc107a2df20106c783b461be7

* Update AsyncStorage doc

Summary:
Relates to #8203 for AsyncStorage API update.

- Added a small example to the intro section.
- Added jsdoc format tags to show up class description, parameter descriptions.
- Word-smithed many of the method descriptions.

I also made a bug fix to the autogen. It wasn't handling the scenario where a method may have no parameters.

**Test plan (required)**

Wrote a small sample app to test the snippet added to the intro section.

Ran website locally: http://localhost:8079/react-native/docs/asyncstorage.html

![api_asyncstorage](https://cloud.githubusercontent.com/assets/691109/16329457/84f9d69c-3997-11e6-9e68-3a475df90377.png)

Ran changed files through the linter.
Closes https://github.com/facebook/react-native/pull/8396

Differential Revision: D3481783

Pulled By: JoelMarcey

fbshipit-source-id: ebc4b9695482ada8a3455e621534d2a7fb11edf4

* Fix errors related to typehint when generating docs

Summary:
After pulling in AsyncStorage doc changes, getting typehint errors when running docs. This fixes that issue.

**Test plan (required)**

Opened http://localhost:8079/react-native/index.html

Clicked around. No errors. Also successfully ran:

```
node server/generate.js
```
Closes https://github.com/facebook/react-native/pull/8412

Differential Revision: D3482007

Pulled By: JoelMarcey

fbshipit-source-id: 7b0da2b2b38fd1f1bdec1b7c810ee70c536dd2bb

* Update Image API

Summary:
- Provide runnable examples
- Add more details to properties and jsdoc-ify the methods

Ref #8203
Closes https://github.com/facebook/react-native/pull/8413

Differential Revision: D3482168

Pulled By: caabernathy

fbshipit-source-id: 04fce5133317af282cced5850a53858e3f5b72f2

* Replace NavigatorComparison with the new Navigation guide.

Summary:
Several external sites link back to docs/navigator-comparison.html when talking about React Native's navigation. The Navigation guide added in #8390 is meant to replace this content, but it was added at docs/navigation.html.

This pull request removes the comparison guide and replaces it with the Navigation guide's content. There is no content update in this PR. For review purposes, note that the next link from the previous document (JS Environment) has been updated to point to navigator-comparison, and the content of the Navigation guide remain unchanged from #8390.
Closes https://github.com/facebook/react-native/pull/8417

Differential Revision: D3482273

Pulled By: caabernathy

fbshipit-source-id: 9e04e11a5829d48541f8612fb65c01fe319e768b

* Overhaul the Flexbox documentation

Summary: Closes https://github.com/facebook/react-native/pull/8395

Differential Revision: D3482652

Pulled By: lacker

fbshipit-source-id: 0bf8955341221b74f69ba24dcf5ab332c910a52c

* Update TextInput API

Summary:
- Make the examples runnable (both copy/paste and with the web player)
- Add a bit more information in props where needed.
Closes https://github.com/facebook/react-native/pull/8392

Differential Revision: D3482747

Pulled By: caabernathy

fbshipit-source-id: 8f2d812efc1efb3f14db45b5c054ce0d5c14f5f5

* Make "The Basics" flow like a linear tutorial

Summary: Closes https://github.com/facebook/react-native/pull/8429

Differential Revision: D3487369

Pulled By: lacker

fbshipit-source-id: 59b32f2a2a67370192c91dc43da3d4b76a43b810

* map -> object

Summary: Closes https://github.com/facebook/react-native/pull/8450

Differential Revision: D3488018

fbshipit-source-id: a30269c89e87b546f77da7a32b1c4c65d978459d

* Make the method signatures stand out more

Summary:
And more delineated from other parts of the method
information.

Hopefully this makes it easier to parse through.
Closes https://github.com/facebook/react-native/pull/8421

Differential Revision: D3488251

Pulled By: JoelMarcey

fbshipit-source-id: 44f2ed00b16849396cac94fd46567eaab48c50f3

* Use npmcdn in docs instead of rawgit for web player

Summary:
Switch web player cdn to npmcdn per discussion with lacker. This will make the url agnostic to who owns the git repo.
Closes https://github.com/facebook/react-native/pull/8426

Differential Revision: D3488755

Pulled By: lacker

fbshipit-source-id: b54dd4428a48c8a5a15b0b38ee0564d119916f9b

* Update instructions for pointing Gradle to Android SDK

Summary:
Closes #8439
Closes https://github.com/facebook/react-native/pull/8446

Differential Revision: D3489034

fbshipit-source-id: 7cb50a43e64e216512294eaec06690dc9f3d6895

* Update RunningOnDeviceAndroid.md

Summary:
Add note associating error message to "adb reverse" command. When I first ran a React Native app on my Android phone, I received a cryptic "bridge configuration isn't available" error. After some research, I discovered that the "adb reverse" command mentioned further down on the page resolved the problem.
Closes https://github.com/facebook/react-native/pull/7725

Differential Revision: D3491577

Pulled By: JoelMarcey

fbshipit-source-id: 34c580acd6bf3e7788b674bd0b41bc5a1023b010

* improve text input docs

Summary:
Not a big deal, I was just going through the tutorial trying to figure out which doc was the most boring, and improve it a bit. IMO now the example is slightly funnier, and it mentions onSubmitEditing which in practice is probably a more useful callback.
Closes https://github.com/facebook/react-native/pull/8447

Differential Revision: D3491938

Pulled By: JoelMarcey

fbshipit-source-id: 3bd0f5762dc4db4a85c9d5badb6c005f4b8c52f4

* Update Text Component

Summary:
This updates the documentation for the `Text` component itself and the embedded `Text.md` that goes with it.

- React Native Web Player
- Document all props
  - NOTE: I actually added a new prop to `Text` called `accessible` since it was set by default and thus shown in the Props list
    in the original documentation (but with an empty description).
- Stylistic fixes
Closes https://github.com/facebook/react-native/pull/8445

Differential Revision: D3493112

Pulled By: JoelMarcey

fbshipit-source-id: b428d4eb09065db5c6cb1ae5524ad22084fd2a82

* Fix TextInput API update nits

Summary:
Ref: https://github.com/facebook/react-native/pull/8392/files/7e7c2b5d57afe451dc5b6ede6b419819e3ac7fbd#r68444537

Ref: https://github.com/facebook/react-native/pull/8392/files/7e7c2b5d57afe451dc5b6ede6b419819e3ac7fbd#r68444442
Closes https://github.com/facebook/react-native/pull/8476

Differential Revision: D3494641

Pulled By: JoelMarcey

fbshipit-source-id: 9a75ff66ccb895deb2f5027bdffe5d5bfe898e41
2016-06-29 03:25:02 -07:00
Mike Grabowski cb6e3297e8 [0.29.0-rc.0] Bump version numbers 2016-06-22 06:28:19 +02:00
100 changed files with 4846 additions and 3518 deletions
+59 -30
View File
@@ -27,21 +27,58 @@ const requireNativeComponent = require('requireNativeComponent');
type Event = Object;
/**
* State an annotation on the map.
*/
export type AnnotationDragState = $Enum<{
/**
* Annotation is not being touched.
*/
idle: string;
/**
* Annotation dragging has began.
*/
starting: string;
/**
* Annotation is being dragged.
*/
dragging: string;
/**
* Annotation dragging is being canceled.
*/
canceling: string;
/**
* Annotation dragging has ended.
*/
ending: string;
}>;
/**
* A component for displaying embeddable maps and annotations using the native
* iOS MKMapView class. The Android version is not currently available in the
* open source React Native project, but you can use Leland Richardson's
* cross-platform and more feature-complete
* **This component is only supported on iOS.**
*
* `MapView` is used to display embeddable maps and annotations using
* `MKMapView`.
*
* For a cross-platform solution, check out
* [react-native-maps](https://github.com/lelandrichardson/react-native-maps)
* instead.
* by Leland Richardson.
*
* ```
* import React, { Component } from 'react';
* import { MapView } from 'react-native';
*
* class MapMyRide extends Component {
* render() {
* return (
* <MapView
* style={{height: 200, margin: 40}}
* showsUserLocation={true}
* />
* );
* }
* }
* ```
*
*/
const MapView = React.createClass({
@@ -51,8 +88,7 @@ const MapView = React.createClass({
propTypes: {
...View.propTypes,
/**
* Used to style and layout the `MapView`. See `StyleSheet.js` and
* `ViewStylePropTypes.js` for more info.
* Used to style and layout the `MapView`.
*/
style: View.propTypes.style,
@@ -60,7 +96,7 @@ const MapView = React.createClass({
* If `true` the app will ask for the user's location and display it on
* the map. Default value is `false`.
*
* **NOTE**: on iOS, you need to add the `NSLocationWhenInUseUsageDescription`
* **NOTE**: You'll need to add the `NSLocationWhenInUseUsageDescription`
* key in Info.plist to enable geolocation, otherwise it will fail silently.
*/
showsUserLocation: React.PropTypes.bool,
@@ -69,21 +105,18 @@ const MapView = React.createClass({
* If `true` the map will follow the user's location whenever it changes.
* Note that this has no effect unless `showsUserLocation` is enabled.
* Default value is `true`.
* @platform ios
*/
followUserLocation: React.PropTypes.bool,
/**
* If `false` points of interest won't be displayed on the map.
* Default value is `true`.
* @platform ios
*/
showsPointsOfInterest: React.PropTypes.bool,
/**
* If `false` compass won't be displayed on the map.
* If `false`, compass won't be displayed on the map.
* Default value is `true`.
* @platform ios
*/
showsCompass: React.PropTypes.bool,
@@ -96,7 +129,9 @@ const MapView = React.createClass({
/**
* When this property is set to `true` and a valid camera is associated with
* the map, the cameras heading angle is used to rotate the plane of the
* map around its center point. When this property is set to `false`, the
* map around its center point.
*
* When this property is set to `false`, the
* cameras heading angle is ignored and the map is always oriented so
* that true north is situated at the top of the map view
*/
@@ -105,7 +140,9 @@ const MapView = React.createClass({
/**
* When this property is set to `true` and a valid camera is associated
* with the map, the cameras pitch angle is used to tilt the plane
* of the map. When this property is set to `false`, the cameras pitch
* of the map.
*
* When this property is set to `false`, the cameras pitch
* angle is ignored and the map is always displayed as if the user
* is looking straight down onto it.
*/
@@ -120,11 +157,9 @@ const MapView = React.createClass({
/**
* The map type to be displayed.
*
* - standard: standard road map (default)
* - satellite: satellite view
* - hybrid: satellite view with roads and points of interest overlaid
*
* @platform ios
* - `standard`: Standard road map (default).
* - `satellite`: Satellite view.
* - `hybrid`: Satellite view with roads and points of interest overlaid.
*/
mapType: React.PropTypes.oneOf([
'standard',
@@ -154,8 +189,7 @@ const MapView = React.createClass({
}),
/**
* Map annotations with title/subtitle.
* @platform ios
* Map annotations with title and subtitle.
*/
annotations: React.PropTypes.arrayOf(React.PropTypes.shape({
/**
@@ -192,7 +226,7 @@ const MapView = React.createClass({
onBlur: React.PropTypes.func,
/**
* Annotation title/subtile.
* Annotation title and subtile.
*/
title: React.PropTypes.string,
subtitle: React.PropTypes.string,
@@ -253,7 +287,6 @@ const MapView = React.createClass({
/**
* Map overlays
* @platform ios
*/
overlays: React.PropTypes.arrayOf(React.PropTypes.shape({
/**
@@ -278,21 +311,17 @@ const MapView = React.createClass({
})),
/**
* Maximum size of area that can be displayed.
* @platform ios
* Maximum size of the area that can be displayed.
*/
maxDelta: React.PropTypes.number,
/**
* Minimum size of area that can be displayed.
* @platform ios
* Minimum size of the area that can be displayed.
*/
minDelta: React.PropTypes.number,
/**
* Insets for the map's legal label, originally at bottom left of the map.
* See `EdgeInsetsPropType.js` for more information.
* @platform ios
*/
legalLabelInsets: EdgeInsetsPropType,
@@ -307,7 +336,7 @@ const MapView = React.createClass({
onRegionChangeComplete: React.PropTypes.func,
/**
* Deprecated. Use annotation onFocus and onBlur instead.
* Deprecated. Use annotation `onFocus` and `onBlur` instead.
*/
onAnnotationPress: React.PropTypes.func,
@@ -93,76 +93,189 @@ type Event = Object;
*/
/**
* NavigatorIOS wraps UIKit navigation and allows you to add back-swipe
* functionality across your app.
* `NavigatorIOS` is a wrapper around
* [`UINavigationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/),
* enabling you to implement a navigation stack. It works exactly the same as it
* would on a native app using `UINavigationController`, providing the same
* animations and behavior from UIKIt.
*
* > **NOTE**: This Component is not maintained by Facebook
* >
* > This component is under community responsibility.
* > If a pure JavaScript solution fits your needs you may try the `Navigator`
* > component instead.
* As the name implies, it is only available on iOS. Take a look at
* [`Navigator`](/docs/navigator.html) for a similar solution for your
* cross-platform needs, or check out
* [react-native-navigation](https://github.com/wix/react-native-navigation), a
* component that aims to provide native navigation on both iOS and Android.
*
* #### Routes
* A route is an object used to describe each page in the navigator. The first
* route is provided to NavigatorIOS as `initialRoute`:
* To set up the navigator, provide the `initialRoute` prop with a route
* object. A route object is used to describe each scene that your app
* navigates to. `initialRoute` represents the first route in your navigator.
*
* ```
* render: function() {
* return (
* <NavigatorIOS
* initialRoute={{
* component: MyView,
* title: 'My View Title',
* passProps: { myProp: 'foo' },
* }}
* />
* );
* },
* import React, { Component } from 'react';
* import { NavigatorIOS, Text } from 'react-native';
*
* export default class NavigatorIOSApp extends Component {
* render() {
* return (
* <NavigatorIOS
* initialRoute={{
* component: MyScene,
* title: 'My Initial Scene',
* }}
* style={{flex: 1}}
* />
* );
* }
* }
*
* class MyScene extends Component {
* static propTypes = {
* title: PropTypes.string.isRequired,
* navigator: PropTypes.object.isRequired,
* }
*
* constructor(props, context) {
* super(props, context);
* this._onForward = this._onForward.bind(this);
* this._onBack = this._onBack.bind(this);
* }
*
* _onForward() {
* this.props.navigator.push({
* title: 'Scene ' + nextIndex,
* });
* }
*
* render() {
* return (
* <View>
* <Text>Current Scene: { this.props.title }</Text>
* <TouchableHighlight onPress={this._onForward}>
* <Text>Tap me to load the next scene</Text>
* </TouchableHighlight>
* </View>
* )
* }
* }
* ```
*
* Now MyView will be rendered by the navigator. It will receive the route
* object in the `route` prop, a navigator, and all of the props specified in
* `passProps`.
* In this code, the navigator renders the component specified in initialRoute,
* which in this case is `MyScene`. This component will receive a `route` prop
* and a `navigator` prop representing the navigator. The navigator's navigation
* bar will render the title for the current scene, "My Initial Scene".
*
* See the initialRoute propType for a complete definition of a route.
*
* #### Navigator
*
* A `navigator` is an object of navigation functions that a view can call. It
* is passed as a prop to any component rendered by NavigatorIOS.
* You can optionally pass in a `passProps` property to your `initialRoute`.
* `NavigatorIOS` passes this in as props to the rendered component:
*
* ```
* var MyView = React.createClass({
* _handleBackButtonPress: function() {
* initialRoute={{
* component: MyScene,
* title: 'My Initial Scene',
* passProps: { myProp: 'foo' }
* }}
* ```
*
* You can then access the props passed in via `{this.props.myProp}`.
*
* #### Handling Navigation
*
* To trigger navigation functionality such as pushing or popping a view, you
* have access to a `navigator` object. The object is passed in as a prop to any
* component that is rendered by `NavigatorIOS`. You can then call the
* relevant methods to perform the navigation action you need:
*
* ```
* class MyView extends Component {
* _handleBackPress() {
* this.props.navigator.pop();
* },
* _handleNextButtonPress: function() {
* }
*
* _handleNextPress(nextRoute) {
* this.props.navigator.push(nextRoute);
* },
* ...
* });
* }
*
* render() {
* const nextRoute = {
* component: MyView,
* title: 'Bar That',
* passProps: { myProp: 'bar' }
* };
* return(
* <TouchableHighlight onPress={() => this._handleNextPress(nextRoute)}>
* <Text style={{marginTop: 200, alignSelf: 'center'}}>
* See you on the other nav {this.props.myProp}!
* </Text>
* </TouchableHighlight>
* );
* }
* }
* ```
*
* Navigator functions are also available on the NavigatorIOS component:
* You can also trigger navigator functionality from the `NavigatorIOS`
* component:
*
* ```
* var MyView = React.createClass({
* _handleNavigationRequest: function() {
* this.refs.nav.push(otherRoute);
* },
* render: () => (
* <NavigatorIOS
* ref="nav"
* initialRoute={...}
* />
* ),
* });
* class NavvyIOS extends Component {
* _handleNavigationRequest() {
* this.refs.nav.push({
* component: MyView,
* title: 'Genius',
* passProps: { myProp: 'genius' },
* });
* }
*
* render() {
* return (
* <NavigatorIOS
* ref='nav'
* initialRoute={{
* component: MyView,
* title: 'Foo This',
* passProps: { myProp: 'foo' },
* rightButtonTitle: 'Add',
* onRightButtonPress: () => this._handleNavigationRequest(),
* }}
* style={{flex: 1}}
* />
* );
* }
* }
* ```
*
* Props passed to the NavigatorIOS component will set the default configuration
* The code above adds a `_handleNavigationRequest` private method that is
* invoked from the `NavigatorIOS` component when the right navigation bar item
* is pressed. To get access to the navigator functionality, a reference to it
* is saved in the `ref` prop and later referenced to push a new scene into the
* navigation stack.
*
* #### Navigation Bar Configuration
*
* Props passed to `NavigatorIOS` will set the default configuration
* for the navigation bar. Props passed as properties to a route object will set
* the configuration for that route's navigation bar, overriding any props
* passed to the NavigatorIOS component.
* passed to the `NavigatorIOS` component.
*
* ```
* _handleNavigationRequest() {
* this.refs.nav.push({
* //...
* passProps: { myProp: 'genius' },
* barTintColor: '#996699',
* });
* }
*
* render() {
* return (
* <NavigatorIOS
* //...
* style={{flex: 1}}
* barTintColor='#ffffcc'
* />
* );
* }
* ```
*
* In the example above the navigation bar color is changed when the new route
* is pushed.
*
*/
var NavigatorIOS = React.createClass({
@@ -170,9 +283,9 @@ var NavigatorIOS = React.createClass({
propTypes: {
/**
* NavigatorIOS uses "route" objects to identify child views, their props,
* and navigation bar configuration. "push" and all the other navigation
* operations expect routes to be like this:
* NavigatorIOS uses `route` objects to identify child views, their props,
* and navigation bar configuration. Navigation operations such as push
* operations expect routes to look like this the `initialRoute`.
*/
initialRoute: PropTypes.shape({
/**
@@ -181,139 +294,159 @@ var NavigatorIOS = React.createClass({
component: PropTypes.func.isRequired,
/**
* The title displayed in the nav bar and back button for this route
* The title displayed in the navigation bar and the back button for this
* route.
*/
title: PropTypes.string.isRequired,
/**
* Specify additional props passed to the component. NavigatorIOS will
* automatically provide "route" and "navigator" components
* If set, a title image will appear instead of the text title.
*/
titleImage: Image.propTypes.source,
/**
* Use this to specify additional props to pass to the rendered
* component. `NavigatorIOS` will automatically pass in `route` and
* `navigator` props to the comoponent.
*/
passProps: PropTypes.object,
/**
* If set, the left header button image will appear with this source. Note
* that this doesn't apply for the header of the current view, but the
* ones of the views that are pushed afterward.
* If set, the left navigation button image will be displayed using this
* source. Note that this doesn't apply to the header of the current
* view, but to those views that are subsequently pushed.
*/
backButtonIcon: Image.propTypes.source,
/**
* If set, the left header button will appear with this name. Note that
* this doesn't apply for the header of the current view, but the ones
* of the views that are pushed afterward.
* If set, the left navigation button text will be set to this. Note that
* this doesn't apply to the left button of the current view, but to
* those views that are subsequently pushed
*/
backButtonTitle: PropTypes.string,
/**
* If set, the left header button image will appear with this source
* If set, the left navigation button image will be displayed using
* this source.
*/
leftButtonIcon: Image.propTypes.source,
/**
* If set, the left header button will appear with this name
* If set, the left navigation button will display this text.
*/
leftButtonTitle: PropTypes.string,
/**
* Called when the left header button is pressed
* This function will be invoked when the left navigation bar item is
* pressed.
*/
onLeftButtonPress: PropTypes.func,
/**
* If set, the right header button image will appear with this source
* If set, the right navigation button image will be displayed using
* this source.
*/
rightButtonIcon: Image.propTypes.source,
/**
* If set, the right header button will appear with this name
* If set, the right navigation button will display this text.
*/
rightButtonTitle: PropTypes.string,
/**
* Called when the right header button is pressed
* This function will be invoked when the right navigation bar item is
* pressed.
*/
onRightButtonPress: PropTypes.func,
/**
* Styles for the navigation item containing the component
* Styles for the navigation item containing the component.
*/
wrapperStyle: View.propTypes.style,
/**
* A Boolean value that indicates whether the navigation bar is hidden
* Boolean value that indicates whether the navigation bar is hidden.
*/
navigationBarHidden: PropTypes.bool,
/**
* A Boolean value that indicates whether to hide the 1px hairline shadow
* Boolean value that indicates whether to hide the 1px hairline
* shadow.
*/
shadowHidden: PropTypes.bool,
/**
* The color used for buttons in the navigation bar
* The color used for the buttons in the navigation bar.
*/
tintColor: PropTypes.string,
/**
* The background color of the navigation bar
* The background color of the navigation bar.
*/
barTintColor: PropTypes.string,
/**
* The text color of the navigation bar title
* The text color of the navigation bar title.
*/
titleTextColor: PropTypes.string,
/**
* A Boolean value that indicates whether the navigation bar is translucent
* Bboolean value that indicates whether the navigation bar is
* translucent.
*/
translucent: PropTypes.bool,
}).isRequired,
/**
* A Boolean value that indicates whether the navigation bar is hidden by default
* Boolean value that indicates whether the navigation bar is hidden
* by default.
*/
navigationBarHidden: PropTypes.bool,
/**
* A Boolean value that indicates whether to hide the 1px hairline shadow by default
* Boolean value that indicates whether to hide the 1px hairline shadow
* by default.
*/
shadowHidden: PropTypes.bool,
/**
* The default wrapper style for components in the navigator.
* A common use case is to set the backgroundColor for every page
* A common use case is to set the `backgroundColor` for every scene.
*/
itemWrapperStyle: View.propTypes.style,
/**
* The default color used for buttons in the navigation bar
* The default color used for the buttons in the navigation bar.
*/
tintColor: PropTypes.string,
/**
* The default background color of the navigation bar
* The default background color of the navigation bar.
*/
barTintColor: PropTypes.string,
/**
* The default text color of the navigation bar title
* The default text color of the navigation bar title.
*/
titleTextColor: PropTypes.string,
/**
* A Boolean value that indicates whether the navigation bar is translucent by default
* Boolean value that indicates whether the navigation bar is
* translucent by default
*/
translucent: PropTypes.bool,
/**
* A Boolean value that indicates whether the interactive pop gesture is enabled. Useful
* for enabling/disabling the back swipe navigation gesture. If this prop is not provided,
* the default behavior is for the back swipe gesture to be enabled when the navigation bar
* is shown and disabled when the navigation bar is hidden. Once you've provided
* the interactivePopGestureEnabled prop, you can never restore the default behavior.
* Boolean value that indicates whether the interactive pop gesture is
* enabled. This is useful for enabling/disabling the back swipe navigation
* gesture.
*
* If this prop is not provided, the default behavior is for the back swipe
* gesture to be enabled when the navigation bar is shown and disabled when
* the navigation bar is hidden. Once you've provided the
* `interactivePopGestureEnabled` prop, you can never restore the default
* behavior.
*/
interactivePopGestureEnabled: PropTypes.bool,
@@ -488,7 +621,8 @@ var NavigatorIOS = React.createClass({
},
/**
* Navigate forward to a new route
* Navigate forward to a new route.
* @param route The new route to navigate to.
*/
push: function(route: Route) {
invariant(!!route, 'Must supply route to push');
@@ -513,7 +647,8 @@ var NavigatorIOS = React.createClass({
},
/**
* Go back N pages at once. When N=1, behavior matches `pop()`
* Go back N scenes at once. When N=1, behavior matches `pop()`.
* @param n The number of scenes to pop.
*/
popN: function(n: number) {
if (n === 0) {
@@ -537,7 +672,7 @@ var NavigatorIOS = React.createClass({
},
/**
* Go back one page
* Pop back to the previous scene.
*/
pop: function() {
this.popN(1);
@@ -546,8 +681,9 @@ var NavigatorIOS = React.createClass({
/**
* Replace a route in the navigation stack.
*
* `index` specifies the route in the stack that should be replaced.
* If it's negative, it counts from the back.
* @param route The new route that will replace the specified one.
* @param index The route into the stack that should be replaced.
* If it is negative, it counts from the back of the stack.
*/
replaceAtIndex: function(route: Route, index: number) {
invariant(!!route, 'Must supply route to replace');
@@ -578,29 +714,32 @@ var NavigatorIOS = React.createClass({
},
/**
* Replace the route for the current page and immediately
* Replace the route for the current scene and immediately
* load the view for the new route.
* @param route The new route to navigate to.
*/
replace: function(route: Route) {
this.replaceAtIndex(route, -1);
},
/**
* Replace the route/view for the previous page.
* Replace the route/view for the previous scene.
* @param route The new route to will replace the previous scene.
*/
replacePrevious: function(route: Route) {
this.replaceAtIndex(route, -2);
},
/**
* Go back to the top item
* Go back to the topmost item in the navigation stack.
*/
popToTop: function() {
this.popToRoute(this.state.routeStack[0]);
},
/**
* Go back to the item for a particular route object
* Go back to the item for a particular route object.
* @param route The new route to navigate to.
*/
popToRoute: function(route: Route) {
var indexOfRoute = this.state.routeStack.indexOf(route);
@@ -614,6 +753,7 @@ var NavigatorIOS = React.createClass({
/**
* Replaces the previous route/view and transitions back to it.
* @param route The new route that replaces the previous scene.
*/
replacePreviousAndPop: function(route: Route) {
// Make sure all previous requests are caught up first. Otherwise reject.
@@ -633,7 +773,8 @@ var NavigatorIOS = React.createClass({
},
/**
* Replaces the top item and popToTop
* Replaces the top item and pop to it.
* @param route The new route that will replace the topmost item.
*/
resetTo: function(route: Route) {
invariant(!!route, 'Must supply route to push');
@@ -19,14 +19,35 @@ const processColor = require('processColor');
const StatusBarManager = require('NativeModules').StatusBarManager;
/**
* Status bar style
*/
export type StatusBarStyle = $Enum<{
/**
* Default status bar style
*/
'default': string,
/**
* Dark background style
*/
'light-content': string,
}>;
/**
* Status bar animation
*/
export type StatusBarAnimation = $Enum<{
/**
* No animation
*/
'none': string,
/**
* Fade animation
*/
'fade': string,
/**
* Slide animation
*/
'slide': string,
}>;
@@ -135,6 +156,13 @@ const StatusBar = React.createClass({
// Provide an imperative API as static functions of the component.
// See the corresponding prop for more detail.
/**
* Show or hide the status bar
* @param hidden The dialog's title.
* @param animation Optional animation when
* changing the status bar hidden property.
*/
setHidden(hidden: boolean, animation?: StatusBarAnimation) {
animation = animation || 'none';
StatusBar._defaultProps.hidden.value = hidden;
@@ -145,6 +173,11 @@ const StatusBar = React.createClass({
}
},
/**
* Set the status bar style
* @param style Status bar style to set
* @param animated Animate the style change.
*/
setBarStyle(style: StatusBarStyle, animated?: boolean) {
if (Platform.OS !== 'ios') {
console.warn('`setBarStyle` is only available on iOS');
@@ -155,6 +188,10 @@ const StatusBar = React.createClass({
StatusBarManager.setStyle(style, animated);
},
/**
* Control the visibility of the network activity indicator
* @param visible Show the indicator.
*/
setNetworkActivityIndicatorVisible(visible: boolean) {
if (Platform.OS !== 'ios') {
console.warn('`setNetworkActivityIndicatorVisible` is only available on iOS');
@@ -164,6 +201,11 @@ const StatusBar = React.createClass({
StatusBarManager.setNetworkActivityIndicatorVisible(visible);
},
/**
* Set the background color for the status bar
* @param color Background color.
* @param animated Animate the style change.
*/
setBackgroundColor(color: string, animated?: boolean) {
if (Platform.OS !== 'android') {
console.warn('`setBackgroundColor` is only available on Android');
@@ -174,6 +216,10 @@ const StatusBar = React.createClass({
StatusBarManager.setColor(processColor(color), animated);
},
/**
* Control the translucency of the status bar
* @param translucent Set as translucent.
*/
setTranslucent(translucent: boolean) {
if (Platform.OS !== 'android') {
console.warn('`setTranslucent` is only available on Android');
+153 -67
View File
@@ -61,12 +61,29 @@ type Event = Object;
* such as `onSubmitEditing` and `onFocus` that can be subscribed to. A simple
* example:
*
* ```
* <TextInput
* style={{height: 40, borderColor: 'gray', borderWidth: 1}}
* onChangeText={(text) => this.setState({text})}
* value={this.state.text}
* />
* ```ReactNativeWebPlayer
* import React, { Component } from 'react';
* import { AppRegistry, TextInput } from 'react-native';
*
* class UselessTextInput extends Component {
* constructor(props) {
* super(props);
* this.state = { text: 'Useless Placeholder' };
* }
*
* render() {
* return (
* <TextInput
* style={{height: 40, borderColor: 'gray', borderWidth: 1}}
* onChangeText={(text) => this.setState({text})}
* value={this.state.text}
* />
* );
* }
* }
*
* // App registration and rendering
* AppRegistry.registerComponent('AwesomeProject', () => UselessTextInput);
* ```
*
* Note that some props are only available with `multiline={true/false}`.
@@ -75,11 +92,64 @@ type Event = Object;
* `multiline=false`. To achieve the same effect, you can wrap your `TextInput`
* in a `View`:
*
* ```ReactNativeWebPlayer
* import React, { Component } from 'react';
* import { AppRegistry, View, TextInput } from 'react-native';
*
* class UselessTextInput extends Component {
* render() {
* return (
* <TextInput
* {...this.props} // Inherit any props passed to it; e.g., multiline, numberOfLines below
* editable = {true}
* maxLength = {40}
* />
* );
* }
* }
*
* class UselessTextInputMultiline extends Component {
* constructor(props) {
* super(props);
* this.state = {
* text: 'Useless Multiline Placeholder',
* };
* }
*
* // If you type something in the text box that is a color, the background will change to that
* // color.
* render() {
* return (
* <View style={{
* backgroundColor: this.state.text,
* borderBottomColor: '#000000',
* borderBottomWidth: 1 }}
* >
* <UselessTextInput
* multiline = {true}
* numberOfLines = {4}
* onChangeText={(text) => this.setState({text})}
* value={this.state.text}
* />
* </View>
* );
* }
* }
*
* // App registration and rendering
* AppRegistry.registerComponent(
* 'AwesomeProject',
* () => UselessTextInputMultiline
* );
* ```
* <View style={{ borderBottomColor: '#000000', borderBottomWidth: 1, }}>
* <TextInput {...props} />
* </View>
* ```
*
* `TextInput` 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.
*
*/
var TextInput = React.createClass({
statics: {
@@ -90,12 +160,12 @@ var TextInput = React.createClass({
propTypes: {
...View.propTypes,
/**
* Can tell TextInput to automatically capitalize certain characters.
* Can tell `TextInput` to automatically capitalize certain characters.
*
* - characters: all characters,
* - words: first letter of each word
* - sentences: first letter of each sentence (default)
* - none: don't auto capitalize anything
* - `characters`: all characters.
* - `words`: first letter of each word.
* - `sentences`: first letter of each sentence (*default*).
* - `none`: don't auto capitalize anything.
*/
autoCapitalize: PropTypes.oneOf([
'none',
@@ -104,16 +174,16 @@ var TextInput = React.createClass({
'characters',
]),
/**
* If false, disables auto-correct. The default value is true.
* If `false`, disables auto-correct. The default value is `true`.
*/
autoCorrect: PropTypes.bool,
/**
* If true, focuses the input on componentDidMount.
* The default value is false.
* If `true`, focuses the input on `componentDidMount`.
* The default value is `false`.
*/
autoFocus: PropTypes.bool,
/**
* If false, text is not editable. The default value is true.
* If `false`, text is not editable. The default value is `true`.
*/
editable: PropTypes.bool,
/**
@@ -121,9 +191,9 @@ var TextInput = React.createClass({
*
* The following values work across platforms:
*
* - default
* - numeric
* - email-address
* - `default`
* - `numeric`
* - `email-address`
*/
keyboardType: PropTypes.oneOf([
// Cross-platform
@@ -154,27 +224,33 @@ var TextInput = React.createClass({
* Determines how the return key should look. On Android you can also use
* `returnKeyLabel`.
*
* *Cross platform*
*
* The following values work across platforms:
*
* - done
* - go
* - next
* - search
* - send
* - `done`
* - `go`
* - `next`
* - `search`
* - `send`
*
* *Android Only*
*
* The following values work on Android only:
*
* - none
* - previous
* - `none`
* - `previous`
*
* *iOS Only*
*
* The following values work on iOS only:
*
* - default
* - emergency-call
* - google
* - join
* - route
* - yahoo
* - `default`
* - `emergency-call`
* - `google`
* - `join`
* - `route`
* - `yahoo`
*/
returnKeyType: PropTypes.oneOf([
// Cross-platform
@@ -205,28 +281,28 @@ var TextInput = React.createClass({
*/
maxLength: PropTypes.number,
/**
* Sets the number of lines for a TextInput. Use it with multiline set to
* true to be able to fill the lines.
* Sets the number of lines for a `TextInput`. Use it with multiline set to
* `true` to be able to fill the lines.
* @platform android
*/
numberOfLines: PropTypes.number,
/**
* If true, the keyboard disables the return key when there is no text and
* automatically enables it when there is text. The default value is false.
* If `true`, the keyboard disables the return key when there is no text and
* automatically enables it when there is text. The default value is `false`.
* @platform ios
*/
enablesReturnKeyAutomatically: PropTypes.bool,
/**
* If true, the text input can be multiple lines.
* The default value is false.
* If `true`, the text input can be multiple lines.
* The default value is `false`.
*/
multiline: PropTypes.bool,
/**
* Callback that is called when the text input is blurred
* Callback that is called when the text input is blurred.
*/
onBlur: PropTypes.func,
/**
* Callback that is called when the text input is focused
* Callback that is called when the text input is focused.
*/
onFocus: PropTypes.func,
/**
@@ -243,18 +319,18 @@ var TextInput = React.createClass({
*/
onEndEditing: PropTypes.func,
/**
* Callback that is called when the text input selection is changed
* Callback that is called when the text input selection is changed.
*/
onSelectionChange: PropTypes.func,
/**
* Callback that is called when the text input's submit button is pressed.
* Invalid if multiline={true} is specified.
* Invalid if `multiline={true}` is specified.
*/
onSubmitEditing: PropTypes.func,
/**
* Callback that is called when a key is pressed.
* Pressed key value is passed as an argument to the callback handler.
* Fires before onChange callbacks.
* Fires before `onChange` callbacks.
* @platform ios
*/
onKeyPress: PropTypes.func,
@@ -263,32 +339,42 @@ var TextInput = React.createClass({
*/
onLayout: PropTypes.func,
/**
* The string that will be rendered before text input has been entered
* The string that will be rendered before text input has been entered.
*/
placeholder: PropTypes.string,
/**
* The text color of the placeholder string
* The text color of the placeholder string.
*/
placeholderTextColor: PropTypes.string,
/**
* If true, the text input obscures the text entered so that sensitive text
* like passwords stay secure. The default value is false.
* If `true`, the text input obscures the text entered so that sensitive text
* like passwords stay secure. The default value is `false`.
*/
secureTextEntry: PropTypes.bool,
/**
* The highlight (and cursor on ios) color of the text input
* The highlight (and cursor on iOS) color of the text input.
*/
selectionColor: PropTypes.string,
/**
* See DocumentSelectionState.js, some state that is responsible for
* maintaining selection information for a document
* An instance of `DocumentSelectionState`, this is some state that is responsible for
* maintaining selection information for a document.
*
* Some functionality that can be performed with this instance is:
*
* - `blur()`
* - `focus()`
* - `update()`
*
* > You can reference `DocumentSelectionState` in
* > [`vendor/document/selection/DocumentSelectionState.js`](https://github.com/facebook/react-native/blob/master/Libraries/vendor/document/selection/DocumentSelectionState.js)
*
* @platform ios
*/
selectionState: PropTypes.instanceOf(DocumentSelectionState),
/**
* The value to show for the text input. TextInput is a controlled
* The value to show for the text input. `TextInput` is a controlled
* component, which means the native value will be forced to match this
* value prop if provided. For most uses this works great, but in some
* value prop if provided. For most uses, this works great, but in some
* cases this may cause flickering - one common cause is preventing edits
* by keeping value the same. In addition to simply setting the same value,
* either set `editable={false}`, or set/update `maxLength` to prevent
@@ -297,12 +383,12 @@ var TextInput = React.createClass({
value: PropTypes.string,
/**
* Provides an initial value that will change when the user starts typing.
* Useful for simple use-cases where you don't want to deal with listening
* Useful for simple use-cases where you do not want to deal with listening
* to events and updating the value prop to keep the controlled state in sync.
*/
defaultValue: PropTypes.string,
/**
* When the clear button should appear on the right side of the text view
* When the clear button should appear on the right side of the text view.
* @platform ios
*/
clearButtonMode: PropTypes.oneOf([
@@ -312,28 +398,28 @@ var TextInput = React.createClass({
'always',
]),
/**
* If true, clears the text field automatically when editing begins
* If `true`, clears the text field automatically when editing begins.
* @platform ios
*/
clearTextOnFocus: PropTypes.bool,
/**
* If true, all text will automatically be selected on focus
* If `true`, all text will automatically be selected on focus.
*/
selectTextOnFocus: PropTypes.bool,
/**
* If true, the text field will blur when submitted.
* If `true`, the text field will blur when submitted.
* The default value is true for single-line fields and false for
* multiline fields. Note that for multiline fields, setting blurOnSubmit
* to true means that pressing return will blur the field and trigger the
* onSubmitEditing event instead of inserting a newline into the field.
* multiline fields. Note that for multiline fields, setting `blurOnSubmit`
* to `true` means that pressing return will blur the field and trigger the
* `onSubmitEditing` event instead of inserting a newline into the field.
*/
blurOnSubmit: PropTypes.bool,
/**
* Styles
* [Styles](/react-native/docs/style.html)
*/
style: Text.propTypes.style,
/**
* The color of the textInput underline.
* The color of the `TextInput` underline.
* @platform android
*/
underlineColorAndroid: PropTypes.string,
@@ -353,7 +439,7 @@ var TextInput = React.createClass({
{})) : Object),
/**
* Returns if the input is currently focused.
* Returns `true` if the input is currently focused; `false` otherwise.
*/
isFocused: function(): boolean {
return TextInputState.currentlyFocusedField() ===
@@ -407,7 +493,7 @@ var TextInput = React.createClass({
},
/**
* Removes all text from the input.
* Removes all text from the `TextInput`.
*/
clear: function() {
this.setNativeProps({text: ''});
+214 -57
View File
@@ -66,26 +66,56 @@ const statics = {
};
/**
* The most fundamental component for building UI, `View` is a
* container that supports layout with flexbox, style, some touch handling, and
* accessibility controls, and is designed to be nested inside other views and
* to have 0 to many children of any type. `View` maps directly to the native
* view equivalent on whatever platform React is running on, whether that is a
* `UIView`, `<div>`, `android.view`, etc. This example creates a `View` that
* wraps two colored boxes and custom component in a row with padding.
* The most fundamental component for building a UI, `View` is a container that supports layout with
* [flexbox](/react-native/docs/flexbox.html), [style](/react-native/docs/style.html),
* [some touch handling](/react-native/docs/handling-touches.html), and
* [accessibility](/react-native/docs/accessibility.html) controls. `View` maps directly to the
* native view equivalent on whatever platform React Native is running on, whether that is a
* `UIView`, `<div>`, `android.view`, etc.
*
* ```
* <View style={{flexDirection: 'row', height: 100, padding: 20}}>
* <View style={{backgroundColor: 'blue', flex: 0.3}} />
* <View style={{backgroundColor: 'red', flex: 0.5}} />
* <MyCustomComponent {...customProps} />
* </View>
* `View` is designed to be nested inside other views and can have 0 to many children of any type.
*
* This example creates a `View` that wraps two colored boxes and a text component in a row with
* padding.
*
* ```javascript
* class ViewColoredBoxesWithText extends Component {
* render() {
* return (
* <View style={{flexDirection: 'row', height: 100, padding: 20}}>
* <View style={{backgroundColor: 'blue', flex: 0.3}} />
* <View style={{backgroundColor: 'red', flex: 0.5}} />
* <Text>Hello World!</Text>
* </View>
* );
* }
* }
* ```
*
* `View`s are designed to be used with `StyleSheet`s for clarity and
* performance, although inline styles are also supported.
* > `View`s are designed to be used with [`StyleSheet`](/react-native/docs/style.html) for clarity
* > and performance, although inline styles are also supported.
*
* ### Synthetic Touch Events
*
* For `View` repsonder props (e.g., `onResponderMove`), the synthetic touch event passed to them
* are of 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.
*/
const View = React.createClass({
// TODO: We should probably expose the mixins, viewConfig, and statics publicly. For example,
// one of the props is of type AccessibilityComponentType. That is defined as a const[] above,
// but it is not rendered by the docs, since `statics` below is not rendered. So its Possible
// values had to be hardcoded.
mixins: [NativeMethodsMixin],
/**
@@ -103,7 +133,7 @@ const View = React.createClass({
propTypes: {
/**
* When true, indicates that the view is an accessibility element. By default,
* When `true`, indicates that the view is an accessibility element. By default,
* all the touchable elements are accessible.
*/
accessible: PropTypes.bool,
@@ -111,13 +141,21 @@ const View = React.createClass({
/**
* Overrides the text that's read by the screen reader when the user interacts
* with the element. By default, the label is constructed by traversing all the
* children and accumulating all the Text nodes separated by space.
* children and accumulating all the `Text` nodes separated by space.
*/
accessibilityLabel: PropTypes.string,
/**
* Indicates to accessibility services to treat UI component like a
* native one. Works for Android only.
*
* Possible values are one of:
*
* - `'none'`
* - `'button'`
* - `'radiobutton_checked'`
* - `'radiobutton_unchecked'`
*
* @platform android
*/
accessibilityComponentType: PropTypes.oneOf(AccessibilityComponentType),
@@ -125,8 +163,15 @@ const View = React.createClass({
/**
* Indicates to accessibility services whether the user should be notified
* when this view changes. Works for Android API >= 19 only.
* See http://developer.android.com/reference/android/view/View.html#attr_android:accessibilityLiveRegion
* for references.
* Possible values:
*
* - `'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.
*
* See the [Android `View` docs](http://developer.android.com/reference/android/view/View.html#attr_android:accessibilityLiveRegion)
* for reference.
*
* @platform android
*/
accessibilityLiveRegion: PropTypes.oneOf([
@@ -139,16 +184,19 @@ const View = React.createClass({
* Controls how view is important for accessibility which is if it
* fires accessibility events and if it is reported to accessibility services
* that query the screen. Works for Android only.
* See http://developer.android.com/reference/android/R.attr.html#importantForAccessibility
* for references.
*
* Possible values:
* 'auto' - The system determines whether the view is important for accessibility -
*
* - `'auto'` - The system determines whether the view is important for accessibility -
* default (recommended).
* 'yes' - The view is important for accessibility.
* 'no' - The view is not important for accessibility.
* 'no-hide-descendants' - The view is not important for accessibility,
* - `'yes'` - The view is important for accessibility.
* - `'no'` - The view is not important for accessibility.
* - `'no-hide-descendants'` - The view is not important for accessibility,
* nor are any of its descendant views.
*
* See the [Android `importantForAccessibility` docs]( [http://developer.android.com/reference/android/R.attr.html#importantForAccessibility)
* for reference.
*
* @platform android
*/
importantForAccessibility: PropTypes.oneOf([
@@ -160,7 +208,33 @@ const View = React.createClass({
/**
* Provides additional traits to screen reader. By default no traits are
* provided unless specified otherwise in element
* provided unless specified otherwise in element.
*
* You can provide one trait or an array of many traits.
*
* Possible values for `AccessibilityTraits` are:
*
* - `'none'` - The element has no traits.
* - `'button'` - The element should be treated as a button.
* - `'link'` - The element should be treated as a link.
* - `'header'` - The element is a header that divides content into sections.
* - `'search'` - The element should be treated as a search field.
* - `'image'` - The element should be treated as an image.
* - `'selected'` - The element is selected.
* - `'plays'` - The element plays sound.
* - `'key'` - The element should be treated like a keyboard key.
* - `'text'` - The element should be treated as text.
* - `'summary'` - The element provides app summary information.
* - `'disabled'` - The element is disabled.
* - `'frequentUpdates'` - The element frequently changes its value.
* - `'startsMedia'` - The element starts a media session.
* - `'adjustable'` - The element allows adjustment over a range of values.
* - `'allowsDirectInteraction'` - The element allows direct touch interaction for VoiceOver users.
* - `'pageTurn'` - Informs VoiceOver that it should scroll to the next page when it finishes reading the contents of the element.
*
* See the [Accessibility guide](/react-native/docs/accessibility.html#accessibilitytraits-ios)
* for more information.
*
* @platform ios
*/
accessibilityTraits: PropTypes.oneOfType([
@@ -175,14 +249,15 @@ const View = React.createClass({
onAccessibilityTap: PropTypes.func,
/**
* When `accessible` is true, the system will invoke this function when the
* When `accessible` is `true`, the system will invoke this function when the
* user performs the magic tap gesture.
*/
onMagicTap: PropTypes.func,
/**
* Used to locate this view in end-to-end tests. NB: disables the 'layout-only
* view removal' optimization for this view!
* Used to locate this view in end-to-end tests.
*
* > This disables the 'layout-only view removal' optimization for this view!
*/
testID: PropTypes.string,
@@ -191,34 +266,113 @@ const View = React.createClass({
* `TouchableHighlight` or `TouchableOpacity`. Check out `Touchable.js`,
* `ScrollResponder.js` and `ResponderEventPlugin.js` for more discussion.
*/
/**
* The View is now responding for touch events. This is the time to highlight and show the user
* what is happening.
*
* `View.props.onResponderGrant: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderGrant: PropTypes.func,
/**
* The user is moving their finger.
*
* `View.props.onResponderMove: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderMove: PropTypes.func,
/**
* Another responder is already active and will not release it to that `View` asking to be
* the responder.
*
* `View.props.onResponderReject: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderReject: PropTypes.func,
/**
* Fired at the end of the touch.
*
* `View.props.onResponderRelease: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderRelease: PropTypes.func,
/**
* 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 (e.g., happens
* with control center/ notification center on iOS)
*
* `View.props.onResponderTerminate: (event) => {}`, where `event` is a synthetic touch event as
* described above.
*/
onResponderTerminate: PropTypes.func,
/**
* Some other `View` wants to become responder and is asking this `View` to release its
* responder. Returning `true` allows its release.
*
* `View.props.onResponderTerminationRequest: (event) => {}`, where `event` is a synthetic touch
* event as described above.
*/
onResponderTerminationRequest: PropTypes.func,
/**
* Does this view want to become responder on the start of a touch?
*
* `View.props.onStartShouldSetResponder: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onStartShouldSetResponder: PropTypes.func,
/**
* If a parent `View` wants to prevent a child `View` from becoming responder on a touch start,
* it should have this handler which returns `true`.
*
* `View.props.onStartShouldSetResponderCapture: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onStartShouldSetResponderCapture: PropTypes.func,
/**
* Does this view want to "claim" touch responsiveness? This is called for every touch move on
* the `View` when it is not the responder.
*
* `View.props.onMoveShouldSetResponder: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onMoveShouldSetResponder: PropTypes.func,
/**
* If a parent `View` wants to prevent a child `View` from becoming responder on a move,
* it should have this handler which returns `true`.
*
* `View.props.onMoveShouldSetResponderCapture: (event) => [true | false]`, where `event` is a
* synthetic touch event as described above.
*/
onMoveShouldSetResponderCapture: PropTypes.func,
/**
* This defines how far a touch event can start away from the view.
* Typical interface guidelines recommend touch targets that are at least
* 30 - 40 points/density-independent pixels. If a Touchable view has a
* height of 20 the touchable height can be extended to 40 with
* `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`
* ** NOTE **
* The touch area never extends past the parent view bounds and the Z-index
* of sibling views always takes precedence if a touch hits two overlapping
* views.
* 30 - 40 points/density-independent pixels.
*
* For example, if a touchable view has a height of 20 the touchable height can be extended to
* 40 with `hitSlop={{top: 10, bottom: 10, left: 0, right: 0}}`
*
* > The touch area never extends past the parent view bounds and the Z-index
* > of sibling views always takes precedence if a touch hits two overlapping
* > views.
*/
hitSlop: EdgeInsetsPropType,
/**
* Invoked on mount and layout changes with
* Invoked on mount and layout changes with:
*
* {nativeEvent: { layout: {x, y, width, height}}}.
* `{nativeEvent: { layout: {x, y, width, height}}}`
*
* This event is fired immediately once the layout has been calculated, but
* the new layout may not yet be reflected on the screen at the time the
@@ -227,11 +381,11 @@ const View = React.createClass({
onLayout: PropTypes.func,
/**
* Controls whether the View can be the target of touch events.
* Controls whether the `View` can be the target of touch events.
*
* - 'auto': The View can be the target of touch events.
* - 'none': The View is never the target of touch events.
* - 'box-none': The View is never the target of touch events but it's
* - `'auto'`: The View can be the target of touch events.
* - `'none'`: The View is never the target of touch events.
* - `'box-none'`: The View is never the target of touch events but it's
* subviews can be. It behaves like if the view had the following classes
* in CSS:
* ```
@@ -242,7 +396,7 @@ const View = React.createClass({
* pointer-events: all;
* }
* ```
* - 'box-only': The view can be the target of touch events but it's
* - `'box-only'`: The view can be the target of touch events but it's
* subviews cannot be. It behaves like if the view had the following classes
* in CSS:
* ```
@@ -253,12 +407,12 @@ const View = React.createClass({
* pointer-events: none;
* }
* ```
* > Since `pointerEvents` does not affect layout/appearance, and we are
* > already deviating from the spec by adding additional modes, we opt to not
* > include `pointerEvents` on `style`. On some platforms, we would need to
* > implement it as a `className` anyways. Using `style` or not is an
* > implementation detail of the platform.
*/
// Since `pointerEvents` does not affect layout/appearance, and we are
// already deviating from the spec by adding additional modes, we opt to not
// include `pointerEvents` on `style`. On some platforms, we would need to
// implement it as a `className` anyways. Using `style` or not is an
// implementation detail of the platform.
pointerEvents: PropTypes.oneOf([
'box-none',
'none',
@@ -268,17 +422,17 @@ const View = React.createClass({
style: stylePropType,
/**
* This is a special performance property exposed by RCTView and is useful
* This is a special performance property exposed by `RCTView` and is useful
* for scrolling content when there are many subviews, most of which are
* offscreen. For this property to be effective, it must be applied to a
* view that contains many subviews that extend outside its bound. The
* subviews must also have overflow: hidden, as should the containing view
* subviews must also have `overflow: hidden`, as should the containing view
* (or one of its superviews).
*/
removeClippedSubviews: PropTypes.bool,
/**
* Whether this view should render itself (and all of its children) into a
* Whether this `View` should render itself (and all of its children) into a
* single hardware texture on the GPU.
*
* On Android, this is useful for animations and interactions that only
@@ -288,12 +442,13 @@ const View = React.createClass({
* different parameters. The downside is that this can use up limited video
* memory, so this prop should be set back to false at the end of the
* interaction/animation.
*
* @platform android
*/
renderToHardwareTextureAndroid: PropTypes.bool,
/**
* Whether this view should be rendered as a bitmap before compositing.
* Whether this `View` should be rendered as a bitmap before compositing.
*
* On iOS, this is useful for animations and interactions that do not
* modify this component's dimensions nor its children; for example, when
@@ -303,6 +458,7 @@ const View = React.createClass({
*
* Rasterization incurs an off-screen drawing pass and the bitmap consumes
* memory. Test and measure when using this property.
*
* @platform ios
*/
shouldRasterizeIOS: PropTypes.bool,
@@ -311,20 +467,21 @@ const View = React.createClass({
* Views that are only used to layout their children or otherwise don't draw
* anything may be automatically removed from the native hierarchy as an
* optimization. Set this property to `false` to disable this optimization and
* ensure that this View exists in the native view hierarchy.
* ensure that this `View` exists in the native view hierarchy.
*
* @platform android
*/
collapsable: PropTypes.bool,
/**
* Whether this view needs to rendered offscreen and composited with an alpha
* Whether this `View` needs to rendered offscreen and composited with an alpha
* in order to preserve 100% correct colors and blending behavior. The default
* (false) falls back to drawing the component and its children with an alpha
* (`false`) falls back to drawing the component and its children with an alpha
* applied to the paint used to draw each element instead of rendering the full
* component offscreen and compositing it back with an alpha value. This default
* may be noticeable and undesired in the case where the View you are setting
* may be noticeable and undesired in the case where the `View` you are setting
* an opacity on has multiple overlapping elements (e.g. multiple overlapping
* Views, or text and a background).
* `View`s, or text and a background).
*
* Rendering offscreen to preserve correct alpha behavior is extremely
* expensive and hard to debug for non-native developers, which is why it is
+82 -31
View File
@@ -82,7 +82,26 @@ var defaultRenderError = (errorDomain, errorCode, errorDesc) => (
);
/**
* Renders a native WebView.
* `WebView` renders web content in a native view.
*
*```
* import React, { Component } from 'react';
* import { WebView } from 'react-native';
*
* class MyWeb extends Component {
* render() {
* return (
* <WebView
* source={{uri: 'https://github.com/facebook/react-native'}}
* style={{marginTop: 20}}
* />
* );
* }
* }
*```
*
* You can use this component to navigate back and forth in the web view's
* history and configure various properties for the web content.
*/
var WebView = React.createClass({
statics: {
@@ -109,7 +128,7 @@ var WebView = React.createClass({
source: PropTypes.oneOfType([
PropTypes.shape({
/*
* The URI to load in the WebView. Can be a local or remote file.
* The URI to load in the `WebView`. Can be a local or remote file.
*/
uri: PropTypes.string,
/*
@@ -155,96 +174,125 @@ var WebView = React.createClass({
*/
renderLoading: PropTypes.func,
/**
* Invoked when load finish
* Function that is invoked when the `WebView` has finished loading.
*/
onLoad: PropTypes.func,
/**
* Invoked when load either succeeds or fails
* Function that is invoked when the `WebView` load succeeds or fails.
*/
onLoadEnd: PropTypes.func,
/**
* Invoked on load start
* Function that is invoked when the `WebView` starts loading.
*/
onLoadStart: PropTypes.func,
/**
* Invoked when load fails
* Function that is invoked when the `WebView` load fails.
*/
onError: PropTypes.func,
/**
* Boolean value that determines whether the web view bounces
* when it reaches the edge of the content. The default value is `true`.
* @platform ios
*/
bounces: PropTypes.bool,
/**
* A floating-point number that determines how quickly the scroll view
* decelerates after the user lifts their finger. You may also use string
* shortcuts `"normal"` and `"fast"` which match the underlying iOS settings
* for `UIScrollViewDecelerationRateNormal` and
* `UIScrollViewDecelerationRateFast` respectively.
* decelerates after the user lifts their finger. You may also use the
* string shortcuts `"normal"` and `"fast"` which match the underlying iOS
* settings for `UIScrollViewDecelerationRateNormal` and
* `UIScrollViewDecelerationRateFast` respectively:
*
* - normal: 0.998
* - fast: 0.99 (the default for iOS WebView)
* - fast: 0.99 (the default for iOS web view)
* @platform ios
*/
decelerationRate: ScrollView.propTypes.decelerationRate,
/**
* Boolean value that determines whether scrolling is enabled in the
* `WebView`. The default value is `true`.
* @platform ios
*/
scrollEnabled: PropTypes.bool,
/**
* Controls whether to adjust the content inset for web views that are
* placed behind a navigation bar, tab bar, or toolbar. The default value
* is `true`.
*/
automaticallyAdjustContentInsets: PropTypes.bool,
/**
* The amount by which the web view content is inset from the edges of
* the scroll view. Defaults to {top: 0, left: 0, bottom: 0, right: 0}.
*/
contentInset: EdgeInsetsPropType,
/**
* Function that is invoked when the `WebView` loading starts or ends.
*/
onNavigationStateChange: PropTypes.func,
startInLoadingState: PropTypes.bool, // force WebView to show loadingView on first load
/**
* Boolean value that forces the `WebView` to show the loading view
* on the first load.
*/
startInLoadingState: PropTypes.bool,
/**
* The style to apply to the `WebView`.
*/
style: View.propTypes.style,
/**
* Used on Android only, JS is enabled by default for WebView on iOS
* Boolean value to enable JavaScript in the `WebView`. Used on Android only
* as JavaScript is enabled by default on iOS. The default value is `true`.
* @platform android
*/
javaScriptEnabled: PropTypes.bool,
/**
* Used on Android only, controls whether DOM Storage is enabled or not
* Boolean value to control whether DOM Storage is enabled. Used only in
* Android.
* @platform android
*/
domStorageEnabled: PropTypes.bool,
/**
* Sets the JS to be injected when the webpage loads.
* Set this to provide JavaScript that will be injected into the web page
* when the view loads.
*/
injectedJavaScript: PropTypes.string,
/**
* Sets the user-agent for this WebView. The user-agent can also be set in native using
* WebViewConfig. This prop will overwrite that config.
* Sets the user-agent for the `WebView`.
* @platform android
*/
userAgent: PropTypes.string,
/**
* Sets whether the webpage scales to fit the view and the user can change the scale.
* Boolean that controls whether the web content is scaled to fit
* the view and enables the user to change the scale. The default value
* is `true`.
*/
scalesPageToFit: PropTypes.bool,
/**
* Allows custom handling of any webview requests by a JS handler. Return true
* or false from this method to continue loading the request.
* Function that allows custom handling of any web view requests. Return
* `true` from the function to continue loading the request and `false`
* to stop loading.
* @platform ios
*/
onShouldStartLoadWithRequest: PropTypes.func,
/**
* Determines whether HTML5 videos play inline or use the native full-screen
* controller.
* default value `false`
* **NOTE** : "In order for video to play inline, not only does this
* property need to be set to true, but the video element in the HTML
* document must also include the webkit-playsinline attribute."
* Boolean that determines whether HTML5 videos play inline or use the
* native full-screen controller. The default value is `false`.
*
* **NOTE** : In order for video to play inline, not only does this
* property need to be set to `true`, but the video element in the HTML
* document must also include the `webkit-playsinline` attribute.
* @platform ios
*/
allowsInlineMediaPlayback: PropTypes.bool,
/**
* Determines whether HTML5 audio & videos require the user to tap before they can
* start playing. The default value is `false`.
* Boolean that determines whether HTML5 audio and video requires the user
* to tap them before they start playing. The default value is `false`.
*/
mediaPlaybackRequiresUserAction: PropTypes.bool,
},
@@ -337,7 +385,7 @@ var WebView = React.createClass({
},
/**
* Go forward one page in the webview's history.
* Go forward one page in the web view's history.
*/
goForward: function() {
UIManager.dispatchViewManagerCommand(
@@ -348,7 +396,7 @@ var WebView = React.createClass({
},
/**
* Go back one page in the webview's history.
* Go back one page in the web view's history.
*/
goBack: function() {
UIManager.dispatchViewManagerCommand(
@@ -369,6 +417,9 @@ var WebView = React.createClass({
);
},
/**
* Stop loading the current page.
*/
stopLoading: function() {
UIManager.dispatchViewManagerCommand(
this.getWebViewHandle(),
@@ -388,7 +439,7 @@ var WebView = React.createClass({
},
/**
* Returns the native webview node.
* Returns the native `WebView` node.
*/
getWebViewHandle: function(): any {
return ReactNative.findNodeHandle(this.refs[RCT_WEBVIEW_REF]);
+195 -58
View File
@@ -129,54 +129,175 @@ var GESTURE_ACTIONS = [
];
/**
* Use `Navigator` to transition between different scenes in your app. To
* accomplish this, provide route objects to the navigator to identify each
* scene, and also a `renderScene` function that the navigator can use to
* render the scene for a given route.
* `Navigator` handles the transition between different scenes in your app.
* It is implemented in JavaScript and is available on both iOS and Android. If
* you are targeting iOS only, you may also want to consider using
* [`NavigatorIOS`](docs/navigatorios.html) as it leverages native UIKit
* navigation.
*
* To change the animation or gesture properties of the scene, provide a
* `configureScene` prop to get the config object for a given route. See
* `Navigator.SceneConfigs` for default animations and more info on
* scene config options.
*
* ### Basic Usage
* To set up the `Navigator` you provide one or more objects called routes,
* to identify each scene. You also provide a `renderScene` function that
* renders the scene for each route object.
*
* ```
* <Navigator
* initialRoute={{name: 'My First Scene', index: 0}}
* renderScene={(route, navigator) =>
* <MySceneComponent
* name={route.name}
* onForward={() => {
* var nextIndex = route.index + 1;
* navigator.push({
* name: 'Scene ' + nextIndex,
* index: nextIndex,
* });
* }}
* onBack={() => {
* if (route.index > 0) {
* import React, { Component } from 'react';
* import { Text, Navigator } from 'react-native';
*
* export default class NavAllDay extends Component {
* render() {
* return (
* <Navigator
* initialRoute={{ title: 'Awesome Scene', index: 0 }}
* renderScene={(route, navigator) =>
* <Text>Hello {route.title}!</Text>
* }
* style={{padding: 100}}
* />
* );
* }
* }
* ```
*
* In the above example, `initialRoute` is used to specify the first route. It
* contains a `title` property that identifies the route. The `renderScene`
* prop returns a function that displays text based on the route's title.
*
* ### Additional Scenes
*
* The first example demonstrated one scene. To set up multiple scenes, you pass
* the `initialRouteStack` prop to `Navigator`:
*
* ```
* render() {
* const routes = [
* {title: 'First Scene', index: 0},
* {title: 'Second Scene', index: 1},
* ];
* return (
* <Navigator
* initialRoute={routes[0]}
* initialRouteStack={routes}
* renderScene={(route, navigator) =>
* <TouchableHighlight onPress={() => {
* if (route.index === 0) {
* navigator.push(routes[1]);
* } else {
* navigator.pop();
* }
* }}
* />
* }
* />
* }}>
* <Text>Hello {route.title}!</Text>
* </TouchableHighlight>
* }
* style={{padding: 100}}
* />
* );
* }
* ```
*
* In the above example, a `routes` variable is defined with two route objects
* representing two scenes. Each route has an `index` property that is used to
* manage the scene being rendered. The `renderScene` method is changed to
* either push or pop the navigator depending on the current route's index.
* Finally, the `Text` component in the scene is now wrapped in a
* `TouchableHighlight` component to help trigger the navigator transitions.
*
* ### Navigation Bar
*
* You can optionally pass in your own navigation bar by returning a
* `Navigator.NavigationBar` component to the `navigationBar` prop in
* `Navigator`. You can configure the navigation bar properties, through
* the `routeMapper` prop. There you set up the left, right, and title
* properties of the navigation bar:
*
* ```
* <Navigator
* renderScene={(route, navigator) =>
* // ...
* }
* navigationBar={
* <Navigator.NavigationBar
* routeMapper={{
* LeftButton: (route, navigator, index, navState) =>
* { return (<Text>Cancel</Text>); },
* RightButton: (route, navigator, index, navState) =>
* { return (<Text>Done</Text>); },
* Title: (route, navigator, index, navState) =>
* { return (<Text>Awesome Nav Bar</Text>); },
* }}
* style={{backgroundColor: 'gray'}}
* />
* }
* />
* ```
*
* When configuring the left, right, and title items for the navigation bar,
* you have access to info such as the current route object and navigation
* state. This allows you to customize the title for each scene as well as
* the buttons. For example, you can choose to hide the left button for one of
* the scenes.
*
* Typically you want buttons to represent the left and right buttons. Building
* on the previous example, you can set this up as follows:
*
* ```
* LeftButton: (route, navigator, index, navState) =>
* {
* if (route.index === 0) {
* return null;
* } else {
* return (
* <TouchableHighlight onPress={() => navigator.pop()}>
* <Text>Back</Text>
* </TouchableHighlight>
* );
* }
* },
* ```
*
* This sets up a left navigator bar button that's visible on scenes after the
* the first one. When the button is tapped the navigator is popped.
*
* Another type of navigation bar, with breadcrumbs, is provided by
* `Navigator.BreadcrumbNavigationBar`. You can also provide your own navigation
* bar by passing it through the `navigationBar` prop. See the
* [UIExplorer](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer)
* demo to try out both built-in navigation bars out and see how to use them.
*
* ### Scene Transitions
*
* To change the animation or gesture properties of the scene, provide a
* `configureScene` prop to get the config object for a given route:
*
* ```
* <Navigator
* renderScene={(route, navigator) =>
* // ...
* }
* configureScene={(route, routeStack) =>
* Navigator.SceneConfigs.FloatFromBottom}
* />
* ```
* In the above example, the newly pushed scene will float up from the bottom.
* See `Navigator.SceneConfigs` for default animations and more info on
* available [scene config options](/react-native/docs/navigator.html#configurescene).
*/
var Navigator = React.createClass({
propTypes: {
/**
* Optional function that allows configuration about scene animations and
* gestures. Will be invoked with the route and the routeStack and should
* return a scene configuration object
* Optional function where you can configure scene animations and
* gestures. Will be invoked with `route` and `routeStack` parameters,
* where `route` corresponds to the current scene being rendered by the
* `Navigator` and `routeStack` is the set of currently mounted routes
* that the navigator could transition to.
*
* The function should return a scene configuration object.
*
* ```
* (route, routeStack) => Navigator.SceneConfigs.FloatFromRight
* ```
*
* Available options are:
* Available scene configutation options are:
*
* - Navigator.SceneConfigs.PushFromRight (default)
* - Navigator.SceneConfigs.FloatFromRight
@@ -194,7 +315,7 @@ var Navigator = React.createClass({
/**
* Required function which renders the scene for a given route. Will be
* invoked with the route and the navigator object
* invoked with the `route` and the `navigator` object.
*
* ```
* (route, navigator) =>
@@ -204,45 +325,53 @@ var Navigator = React.createClass({
renderScene: PropTypes.func.isRequired,
/**
* Specify a route to start on. A route is an object that the navigator
* will use to identify each scene to render. `initialRoute` must be
* a route in the `initialRouteStack` if both props are provided. The
* `initialRoute` will default to the last item in the `initialRouteStack`.
* The initial route for navigation. A route is an object that the navigator
* will use to identify each scene it renders.
*
* If both `initialRoute` and `initialRouteStack` props are passed to
* `Navigator`, then `initialRoute` must be in a route in
* `initialRouteStack`. If `initialRouteStack` is passed as a prop but
* `initialRoute` is not, then `initialRoute` will default internally to
* the last item in `initialRouteStack`.
*/
initialRoute: PropTypes.object,
/**
* Provide a set of routes to initially mount. Required if no initialRoute
* is provided. Otherwise, it will default to an array containing only the
* `initialRoute`
* Pass this in to provide a set of routes to initially mount. This prop
* is required if `initialRoute` is not provided to the navigator. If this
* prop is not passed in, it will default internally to an array
* containing only `initialRoute`.
*/
initialRouteStack: PropTypes.arrayOf(PropTypes.object),
/**
* Will emit the target route upon mounting and before each nav transition
* Pass in a function to get notified with the target route when
* the navigator component is mounted and before each navigator transition.
*/
onWillFocus: PropTypes.func,
/**
* Will be called with the new route of each scene after the transition is
* complete or after the initial mounting
* complete or after the initial mounting.
*/
onDidFocus: PropTypes.func,
/**
* Optionally provide a component as navigation bar that persists across scene
* transitions. The component will receive two props: `navigator` and `navState`.
* It will be rerendered when the routes change.
* Use this to provide an optional component representing a navigation bar
* that is persisted across scene transitions. This component will receive
* two props: `navigator` and `navState` representing the navigator
* component and its state. The component is re-rendered when the route
* changes.
*/
navigationBar: PropTypes.node,
/**
* Optionally provide the navigator object from a parent Navigator
* Optionally pass in the navigator object from a parent `Navigator`.
*/
navigator: PropTypes.object,
/**
* Styles to apply to the container of each scene
* Styles to apply to the container of each scene.
*/
sceneStyle: View.propTypes.style,
},
@@ -348,11 +477,10 @@ var Navigator = React.createClass({
/**
* Reset every scene with an array of routes.
*
* @param {RouteStack} nextRouteStack Next route stack to reinitialize. This
* doesn't accept stack item `id`s, which implies that all existing items are
* destroyed, and then potentially recreated according to `routeStack`. Does
* not animate, immediately replaces and rerenders navigation bar and stack
* items.
* @param {RouteStack} nextRouteStack Next route stack to reinitialize.
* All existing route stacks are destroyed an potentially recreated. There
* is no accompanying animation and this method immediately replaces and
* re-renders the navigation bar and the stack items.
*/
immediatelyResetRouteStack: function(nextRouteStack) {
var destIndex = nextRouteStack.length - 1;
@@ -889,7 +1017,9 @@ var Navigator = React.createClass({
},
/**
* Transition to an existing scene without unmounting
* Transition to an existing scene without unmounting.
* @param {object} route Route to transition to. The specified route must
* be in the currently mounted set of routes defined in `routeStack`.
*/
jumpTo: function(route) {
var destIndex = this.state.routeStack.indexOf(route);
@@ -916,7 +1046,8 @@ var Navigator = React.createClass({
/**
* Navigate forward to a new scene, squashing any scenes that you could
* `jumpForward` to.
* jump forward to.
* @param {object} route Route to push into the navigator stack.
*/
push: function(route) {
invariant(!!route, 'Must supply route to push');
@@ -980,10 +1111,11 @@ var Navigator = React.createClass({
},
/**
* Replace a scene as specified by an index
*
* `index` specifies the route in the stack that should be replaced.
* If it's negative, it counts from the back.
* Replace a scene as specified by an index.
* @param {object} route Route representing the new scene to render.
* @param {number} index The route in the stack that should be replaced.
* If negative, it counts from the back of the stack.
* @param {Function} cb Callback function when the scene has been replaced.
*/
replaceAtIndex: function(route, index, cb) {
invariant(!!route, 'Must supply route to replace');
@@ -1016,6 +1148,7 @@ var Navigator = React.createClass({
/**
* Replace the current scene with a new route.
* @param {object} route Route that replaces the current scene.
*/
replace: function(route) {
this.replaceAtIndex(route, this.state.presentedIndex);
@@ -1023,6 +1156,7 @@ var Navigator = React.createClass({
/**
* Replace the previous scene.
* @param {object} route Route that replaces the previous scene.
*/
replacePrevious: function(route) {
this.replaceAtIndex(route, this.state.presentedIndex - 1);
@@ -1038,6 +1172,7 @@ var Navigator = React.createClass({
/**
* Pop to a particular scene, as specified by its route.
* All scenes after it will be unmounted.
* @param {object} route Route to pop to.
*/
popToRoute: function(route) {
var indexOfRoute = this.state.routeStack.indexOf(route);
@@ -1051,6 +1186,7 @@ var Navigator = React.createClass({
/**
* Replace the previous scene and pop to it.
* @param {object} route Route that replaces the previous scene.
*/
replacePreviousAndPop: function(route) {
if (this.state.routeStack.length < 2) {
@@ -1062,6 +1198,7 @@ var Navigator = React.createClass({
/**
* Navigate to a new scene and reset route stack.
* @param {object} route Route to navigate to.
*/
resetTo: function(route) {
invariant(!!route, 'Must supply route to push');
+100 -40
View File
@@ -34,27 +34,72 @@ const ImageViewManager = NativeModules.ImageViewManager;
* including network images, static resources, temporary local images, and
* images from local disk, such as the camera roll.
*
* Example usage:
* This exmaples shows both fetching and displaying an image from local storage as well as on from
* network.
*
* ```ReactNativeWebPlayer
* import React, { Component } from 'react';
* import { AppRegistry, View, Image } from 'react-native';
*
* class DisplayAnImage extends Component {
* render() {
* return (
* <View>
* <Image
* source={require('./img/favicon.png')}
* />
* <Image
* source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
* />
* </View>
* );
* }
* }
*
* // App registration and rendering
* AppRegistry.registerComponent('DisplayAnImage', () => DisplayAnImage);
* ```
* renderImages: function() {
* return (
* <View>
* <Image
* style={styles.icon}
* source={require('./myIcon.png')}
* />
* <Image
* style={styles.logo}
* source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
* />
* </View>
* );
* },
*
* You can also add `style` to an image:
*
* ```ReactNativeWebPlayer
* import React, { Component } from 'react';
* import { AppRegistry, View, Image, StyleSheet} from 'react-native';
*
* const styles = StyleSheet.create({
* stretch: {
* width: 50,
* height: 200
* }
* });
*
*class DisplayAnImageWithStyle extends Component {
* render() {
* return (
* <View>
* <Image
* style={styles.stretch}
* source={require('./img/favicon.png')}
* />
* </View>
* );
* }
* }
*
* // App registration and rendering
* AppRegistry.registerComponent(
* 'DisplayAnImageWithStyle',
* () => DisplayAnImageWithStyle
* );
* ```
*/
const Image = React.createClass({
propTypes: {
/**
* > `ImageResizeMode` is an `Enum` for different image resizing modes, set via the
* > `resizeMode` style property on `Image` components. The values are `contain`, `cover`,
* > `stretch`, `center`, `repeat`.
*/
style: StyleSheetPropType(ImageStylePropTypes),
/**
* The image source (either a remote URL or a local file resource).
@@ -62,29 +107,26 @@ const Image = React.createClass({
source: ImageSourcePropType,
/**
* A static image to display while loading the image source.
*
* - `uri` - a string representing the resource identifier for the image, which
* should be either a local file path or the name of a static image resource
* (which should be wrapped in the `require('./path/to/image.png')` function).
* - `width`, `height` - can be specified if known at build time, in which case
* these will be used to set the default `<Image/>` component dimensions.
* - `scale` - used to indicate the scale factor of the image. Defaults to 1.0 if
* unspecified, meaning that one image pixel equates to one display point / DIP.
* - `number` - Opaque type returned by something like `require('./image.jpg')`.
*
* @platform ios
*/
defaultSource: PropTypes.oneOfType([
// TODO: Tooling to support documenting these directly and having them display in the docs.
PropTypes.shape({
/**
* `uri` is a string representing the resource identifier for the image, which
* should be either a local file path or the name of a static image resource
* (which should be wrapped in the `require('./path/to/image.png')` function).
*/
uri: PropTypes.string,
/**
* `width` and `height` can be specified if known at build time, in which case
* these will be used to set the default `<Image/>` component dimensions.
*/
width: PropTypes.number,
height: PropTypes.number,
/**
* `scale` is used to indicate the scale factor of the image. Defaults to 1.0 if
* unspecified, meaning that one image pixel equates to one display point / DIP.
*/
scale: PropTypes.number,
}),
// Opaque type returned by require('./image.jpg')
PropTypes.number,
]),
/**
@@ -105,10 +147,11 @@ const Image = React.createClass({
blurRadius: PropTypes.number,
/**
* When the image is resized, the corners of the size specified
* by capInsets will stay a fixed size, but the center content and borders
* by `capInsets` will stay a fixed size, but the center content and borders
* of the image will be stretched. This is useful for creating resizable
* rounded buttons, shadows, and other resizable assets. More info on
* [Apple documentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/index.html#//apple_ref/occ/instm/UIImage/resizableImageWithCapInsets)
* rounded buttons, shadows, and other resizable assets. More info in the
* [official Apple documentation](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UIImage_Class/index.html#//apple_ref/occ/instm/UIImage/resizableImageWithCapInsets).
*
* @platform ios
*/
capInsets: EdgeInsetsPropType,
@@ -116,16 +159,19 @@ const Image = React.createClass({
* Determines how to resize the image when the frame doesn't match the raw
* image dimensions.
*
* 'cover': Scale the image uniformly (maintain the image's aspect ratio)
* - `cover`: Scale the image uniformly (maintain the image's aspect ratio)
* so that both dimensions (width and height) of the image will be equal
* to or larger than the corresponding dimension of the view (minus padding).
*
* 'contain': Scale the image uniformly (maintain the image's aspect ratio)
* - `contain`: Scale the image uniformly (maintain the image's aspect ratio)
* so that both dimensions (width and height) of the image will be equal to
* or less than the corresponding dimension of the view (minus padding).
*
* 'stretch': Scale width and height independently, This may change the
* - `stretch`: Scale width and height independently, This may change the
* aspect ratio of the src.
*
* - `repeat`: Repeat the image to cover the frame of the view. The
* image will keep it's size and aspect ratio. (iOS only)
*/
resizeMode: PropTypes.oneOf(['cover', 'contain', 'stretch']),
/**
@@ -139,25 +185,27 @@ const Image = React.createClass({
*/
onLayout: PropTypes.func,
/**
* Invoked on load start
* Invoked on load start.
*
* e.g., `onLoadStart={(e) => this.setState({loading: true})}`
*/
onLoadStart: PropTypes.func,
/**
* Invoked on download progress with `{nativeEvent: {loaded, total}}`
* Invoked on download progress with `{nativeEvent: {loaded, total}}`.
* @platform ios
*/
onProgress: PropTypes.func,
/**
* Invoked on load error with `{nativeEvent: {error}}`
* Invoked on load error with `{nativeEvent: {error}}`.
* @platform ios
*/
onError: PropTypes.func,
/**
* Invoked when load completes successfully
* Invoked when load completes successfully.
*/
onLoad: PropTypes.func,
/**
* Invoked when load either succeeds or fails
* Invoked when load either succeeds or fails.
*/
onLoadEnd: PropTypes.func,
},
@@ -175,6 +223,14 @@ const Image = React.createClass({
* does not fully load/download the image data. A proper, supported way to
* preload images will be provided as a separate API.
*
* @param uri The location of the image.
* @param success The function that will be called if the image was sucessfully found and width
* and height retrieved.
* @param failure The function that will be called if there was an error, such as failing to
* to retrieve the image.
*
* @returns void
*
* @platform ios
*/
getSize: function(
@@ -189,6 +245,10 @@ const Image = React.createClass({
/**
* Prefetches a remote image for later use by downloading it to the disk
* cache
*
* @param url The remote location of the image.
*
* @return The prefetched image.
*/
prefetch(url: string) {
return ImageViewManager.prefetchImage(url);
+9 -6
View File
@@ -15,12 +15,12 @@ const infoLog = require('infoLog');
const invariant = require('fbjs/lib/invariant');
type SimpleTask = {
name: string;
run: () => void;
name: string,
run: () => void,
};
type PromiseTask = {
name: string;
gen: () => Promise<any>;
name: string,
gen: () => Promise<any>,
};
export type Task = Function | SimpleTask | PromiseTask;
@@ -75,7 +75,7 @@ class TaskQueue {
...queue,
tasks: queue.tasks.filter((task) => tasksToCancel.indexOf(task) === -1),
}))
.filter((queue) => queue.tasks.length > 0);
.filter((queue, idx) => (queue.tasks.length > 0 || idx === 0));
}
/**
@@ -151,7 +151,10 @@ class TaskQueue {
DEBUG && infoLog('exec gen task ' + task.name);
task.gen()
.then(() => {
DEBUG && infoLog('onThen for gen task ' + task.name, {stackIdx, queueStackSize: this._queueStack.length});
DEBUG && infoLog(
'onThen for gen task ' + task.name,
{stackIdx, queueStackSize: this._queueStack.length},
);
this._queueStack[stackIdx].popable = true;
this.hasTasksToProcess() && this._onMoreTasks();
})
@@ -142,4 +142,13 @@ describe('TaskQueue', () => {
expectToBeCalledOnce(task4);
expect(taskQueue.hasTasksToProcess()).toBe(false);
});
it('should not crash when last task is cancelled', () => {
const task1 = jest.fn();
taskQueue.enqueue(task1);
taskQueue.cancelTasks([task1]);
clearTaskQueue(taskQueue);
expect(task1).not.toBeCalled();
expect(taskQueue.hasTasksToProcess()).toBe(false);
});
});
+78 -14
View File
@@ -23,29 +23,93 @@ const requireNativeComponent = require('requireNativeComponent');
const RCTModalHostView = requireNativeComponent('RCTModalHostView', null);
/**
* A Modal component covers the native view (e.g. UIViewController, Activity)
* that contains the React Native root.
* The Modal component is a simple way to present content above an enclosing view.
*
* Use Modal in hybrid apps that embed React Native; Modal allows the portion of
* your app written in React Native to present content above the enclosing
* native view hierarchy.
* _Note: If you need more control over how to present modals over the rest of your app,
* then consider using a top-level Navigator. Go [here](/react-native/docs/navigator-comparison.html) to compare navigation options._
*
* In apps written with React Native from the root view down, you should use
* Navigator instead of Modal. With a top-level Navigator, you have more control
* over how to present the modal scene over the rest of your app by using the
* configureScene property.
* ```javascript
* import React, { Component } from 'react';
* import { Modal, Text, TouchableHighlight, View } from 'react-native';
*
* class ModalExample extends Component {
*
* constructor(props) {
* super(props);
* this.state = {modalVisible: false};
* }
*
* setModalVisible(visible) {
* this.setState({modalVisible: visible});
* }
*
* render() {
* return (
* <View style={{marginTop: 22}}>
* <Modal
* animationType={"slide"}
* transparent={false}
* visible={this.state.modalVisible}
* onRequestClose={() => {alert("Modal has been closed.")}}
* >
* <View style={{marginTop: 22}}>
* <View>
* <Text>Hello World!</Text>
*
* <TouchableHighlight onPress={() => {
* this.setModalVisible(!this.state.modalVisible)
* }}>
* <Text>Hide Modal</Text>
* </TouchableHighlight>
*
* </View>
* </View>
* </Modal>
*
* <TouchableHighlight onPress={() => {
* this.setModalVisible(true)
* }}>
* <Text>Show Modal</Text>
* </TouchableHighlight>
*
* </View>
* );
* }
* }
* ```
*/
class Modal extends React.Component {
static propTypes = {
/**
* The `animationType` prop controls how the modal animates.
*
* - `slide` slides in from the bottom
* - `fade` fades into view
* - `none` appears without an animation
*/
animationType: PropTypes.oneOf(['none', 'slide', 'fade']),
/**
* The `transparent` prop determines whether your modal will fill the entire view. Setting this to `true` will render the modal over a transparent background.
*/
transparent: PropTypes.bool,
/**
* The `visible` prop determines whether your modal is visible.
*/
visible: PropTypes.bool,
/**
* The `onRequestClose` prop allows passing a function that will be called once the modal has been dismissed.
*
* _On the Android platform, this is a required function._
*/
onRequestClose: Platform.OS === 'android' ? PropTypes.func.isRequired : PropTypes.func,
/**
* The `onShow` prop allows passing a function that will be called once the modal has been shown.
*/
onShow: PropTypes.func,
animated: deprecatedPropType(
PropTypes.bool,
'Use the `animationType` prop instead.'
),
animationType: PropTypes.oneOf(['none', 'slide', 'fade']),
transparent: PropTypes.bool,
visible: PropTypes.bool,
onRequestClose: Platform.OS === 'android' ? PropTypes.func.isRequired : PropTypes.func,
onShow: PropTypes.func,
};
static defaultProps = {
@@ -19,6 +19,8 @@ const React = require('React');
const StyleSheet = require('StyleSheet');
const View = require('View');
const invariant = require('fbjs/lib/invariant');
import type {
NavigationAnimatedValue,
NavigationLayout,
@@ -33,7 +35,7 @@ type Props = {
navigationState: NavigationState,
onTransitionEnd: () => void,
onTransitionStart: () => void,
render: (props: NavigationTransitionProps) => any,
render: (a: NavigationTransitionProps, b: ?NavigationTransitionProps) => any,
style: any,
};
@@ -56,9 +58,10 @@ function isSceneNotStale(scene: NavigationScene): boolean {
}
class NavigationTransitioner extends React.Component<any, Props, State> {
_onLayout: (event: any) => void;
_onTransitionEnd: () => void;
_prevTransitionProps: ?NavigationTransitionProps;
_transitionProps: NavigationTransitionProps;
props: Props;
state: State;
@@ -90,6 +93,9 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
progress: new Animated.Value(1),
scenes: NavigationScenesReducer([], this.props.navigationState),
};
this._prevTransitionProps = null;
this._transitionProps = buildTransitionProps(props, this.state);
}
componentWillMount(): void {
@@ -108,15 +114,21 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
return;
}
const nextState = {
...this.state,
scenes: nextScenes,
};
this._prevTransitionProps = this._transitionProps;
this._transitionProps = buildTransitionProps(nextProps, nextState);
const {
position,
progress,
} = this.state;
} = nextState;
// update scenes.
this.setState({
scenes: nextScenes,
});
this.setState(nextState);
// get the transition spec.
const transitionUserSpec = nextProps.configureTransition ?
@@ -153,7 +165,10 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
}
// play the transition.
nextProps.onTransitionStart && nextProps.onTransitionStart();
nextProps.onTransitionStart && nextProps.onTransitionStart(
this._transitionProps,
this._prevTransitionProps,
);
Animated.parallel(animations).start(this._onTransitionEnd);
}
@@ -162,7 +177,7 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
<View
onLayout={this._onLayout}
style={[styles.main, this.props.style]}>
{this.props.render(this._buildTransitionProps())}
{this.props.render(this._transitionProps, this._prevTransitionProps)}
</View>
);
}
@@ -180,39 +195,72 @@ class NavigationTransitioner extends React.Component<any, Props, State> {
layout.height.setValue(height);
layout.width.setValue(width);
this.setState({ layout });
const nextState = {
...this.state,
layout,
};
this._transitionProps = buildTransitionProps(this.props, nextState);
this.setState(nextState);
}
_onTransitionEnd(): void {
const scenes = this.state.scenes.filter(isSceneNotStale);
if (scenes.length !== this.state.scenes.length) {
this.setState({ scenes });
}
this.props.onTransitionEnd && this.props.onTransitionEnd();
}
const prevTransitionProps = this._prevTransitionProps;
this._prevTransitionProps = null;
_buildTransitionProps(): NavigationTransitionProps {
const {
navigationState,
} = this.props;
const {
layout,
position,
progress,
scenes,
} = this.state;
return {
layout,
navigationState,
position,
progress,
scenes,
const nextState = {
...this.state,
scenes: this.state.scenes.filter(isSceneNotStale),
};
this._transitionProps = buildTransitionProps(this.props, nextState);
this.setState(nextState);
this.props.onTransitionEnd && this.props.onTransitionEnd(
this._transitionProps,
prevTransitionProps,
);
}
}
function buildTransitionProps(
props: Props,
state: State,
): NavigationTransitionProps {
const {
navigationState,
} = props;
const {
layout,
position,
progress,
scenes,
} = state;
return {
layout,
navigationState,
position,
progress,
scenes,
scene: findActiveScene(scenes, navigationState.index),
};
}
function findActiveScene(
scenes: Array<NavigationScene>,
index: number,
): NavigationScene {
for (let ii = 0, jj = scenes.length; ii < jj; ii++) {
const scene = scenes[ii];
if (!scene.isStale && scene.index === index) {
return scene;
}
}
invariant(false, 'scenes must have an active scene');
}
const styles = StyleSheet.create({
main: {
flex: 1,
@@ -64,19 +64,16 @@ export type NavigationTransitionProps = {
// All the scenes of the transitioner.
scenes: Array<NavigationScene>,
};
export type NavigationSceneRendererProps = {
layout: NavigationLayout,
navigationState: NavigationState,
position: NavigationAnimatedValue,
progress: NavigationAnimatedValue,
scenes: Array<NavigationScene>,
// The scene to render.
// The active scene, corresponding to the route at
// `navigationState.routes[navigationState.index]`.
scene: NavigationScene,
};
// Similar to `NavigationTransitionProps`, except that the prop `scene`
// represents the scene for the renderer to render.
export type NavigationSceneRendererProps = NavigationTransitionProps;
export type NavigationPanPanHandlers = {
onMoveShouldSetResponder: Function,
onMoveShouldSetResponderCapture: Function,
+135 -56
View File
@@ -9,6 +9,7 @@
* @providesModule AsyncStorage
* @noflow
* @flow-weak
* @jsdoc
*/
'use strict';
@@ -21,18 +22,45 @@ var RCTAsyncFileStorage = NativeModules.AsyncLocalStorage;
var RCTAsyncStorage = RCTAsyncRocksDBStorage || RCTAsyncSQLiteStorage || RCTAsyncFileStorage;
/**
* AsyncStorage is a simple, asynchronous, persistent, key-value storage
* @class
* @description
* `AsyncStorage` is a simple, asynchronous, persistent, key-value storage
* system that is global to the app. It should be used instead of LocalStorage.
*
* It is recommended that you use an abstraction on top of AsyncStorage instead
* of AsyncStorage directly for anything more than light usage since it
* operates globally.
* It is recommended that you use an abstraction on top of `AsyncStorage`
* instead of `AsyncStorage` directly for anything more than light usage since
* it operates globally.
*
* On iOS, AsyncStorage is backed by native code that stores small values in a serialized
* dictionary and larger values in separate files. On Android, AsyncStorage will use either
* RocksDB or SQLite based on what is available. This JS code is a simple facade that
* provides a clear JS API, real Error objects, and simple non-multi functions. Each
* method returns a `Promise` object.
* On iOS, `AsyncStorage` is backed by native code that stores small values in a
* serialized dictionary and larger values in separate files. On Android,
* `AsyncStorage` will use either [RocksDB](http://rocksdb.org/) or SQLite
* based on what is available.
*
* The `AsyncStorage` JavaScript code is a simple facade that provides a clear
* JavaScript API, real `Error` objects, and simple non-multi functions. Each
* method in the API returns a `Promise` object.
*
* Persisting data:
* ```
* try {
* await AsyncStorage.setItem('@MySuperStore:key', 'I like to save it.');
* } catch (error) {
* // Error saving data
* }
* ```
*
* Fetching data:
* ```
* try {
* const value = await AsyncStorage.getItem('@MySuperStore:key');
* if (value !== null){
* // We have data!!
* console.log(value);
* }
* } catch (error) {
* // Error retrieving data
* }
* ```
*/
var AsyncStorage = {
_getRequests: ([]: Array<any>),
@@ -40,8 +68,12 @@ var AsyncStorage = {
_immediate: (null: ?number),
/**
* Fetches `key` and passes the result to `callback`, along with an `Error` if
* there is any. Returns a `Promise` object.
* Fetches an item for a `key` and invokes a callback upon completion.
* Returns a `Promise` object.
* @param key Key of the item to fetch.
* @param callback Function that will be called with a result if found or
* any error.
* @returns A `Promise` object.
*/
getItem: function(
key: string,
@@ -63,8 +95,12 @@ var AsyncStorage = {
},
/**
* Sets `value` for `key` and calls `callback` on completion, along with an
* `Error` if there is any. Returns a `Promise` object.
* Sets the value for a `key` and invokes a callback upon completion.
* Returns a `Promise` object.
* @param key Key of the item to set.
* @param value Value to set for the `key`.
* @param callback Function that will be called with any error.
* @returns A `Promise` object.
*/
setItem: function(
key: string,
@@ -85,7 +121,11 @@ var AsyncStorage = {
},
/**
* Removes an item for a `key` and invokes a callback upon completion.
* Returns a `Promise` object.
* @param key Key of the item to remove.
* @param callback Function that will be called with any error.
* @returns A `Promise` object.
*/
removeItem: function(
key: string,
@@ -105,32 +145,39 @@ var AsyncStorage = {
},
/**
* Merges existing value with input value, assuming they are stringified json.
* Returns a `Promise` object. Not supported by all native implementations.
* Merges an existing `key` value with an input value, assuming both values
* are stringified JSON. Returns a `Promise` object.
*
* Example:
* ```javascript
* **NOTE:** This is not supported by all native implementations.
*
* @param key Key of the item to modify.
* @param value New value to merge for the `key`.
* @param callback Function that will be called with any error.
* @returns A `Promise` object.
*
* @example <caption>Example</caption>
* let UID123_object = {
* name: 'Chris',
* age: 30,
* traits: {hair: 'brown', eyes: 'brown'},
* };
// need only define what will be added or updated
* // You only need to define what will be added or updated
* let UID123_delta = {
* age: 31,
* traits: {eyes: 'blue', shoe_size: 10}
* };
*
* AsyncStorage.setItem('UID123', JSON.stringify(UID123_object), () => {
* AsyncStorage.mergeItem('UID123', JSON.stringify(UID123_delta), () => {
* AsyncStorage.getItem('UID123', (err, result) => {
* console.log(result);
* // => {'name':'Chris','age':31,'traits':{'shoe_size':10,'hair':'brown','eyes':'blue'}}
* });
* });
* });
* ```
*
* // Console log result:
* // => {'name':'Chris','age':31,'traits':
* // {'shoe_size':10,'hair':'brown','eyes':'blue'}}
*/
mergeItem: function(
key: string,
@@ -151,9 +198,11 @@ var AsyncStorage = {
},
/**
* Erases *all* AsyncStorage for all clients, libraries, etc. You probably
* don't want to call this - use removeItem or multiRemove to clear only your
* own keys instead. Returns a `Promise` object.
* Erases *all* `AsyncStorage` for all clients, libraries, etc. You probably
* don't want to call this; use `removeItem` or `multiRemove` to clear only
* your app's keys. Returns a `Promise` object.
* @param callback Function that will be called with any error.
* @returns A `Promise` object.
*/
clear: function(callback?: ?(error: ?Error) => void): Promise {
return new Promise((resolve, reject) => {
@@ -169,9 +218,12 @@ var AsyncStorage = {
},
/**
* Gets *all* keys known to the app, for all callers, libraries, etc. Returns a `Promise` object.
* Gets *all* keys known to your app; for all callers, libraries, etc.
* Returns a `Promise` object.
* @param callback Function that will be called the keys found and any error.
* @returns A `Promise` object.
*
* Example: see multiGet for example
* Example: see the `multiGet` example.
*/
getAllKeys: function(callback?: ?(error: ?Error, keys: ?Array<string>) => void): Promise {
return new Promise((resolve, reject) => {
@@ -196,7 +248,7 @@ var AsyncStorage = {
* indicate which key caused the error.
*/
/** Flushes any pending requests using a single multiget */
/** Flushes any pending requests using a single batch call to get the data. */
flushGetRequests: function(): void {
const getRequests = this._getRequests;
const getKeys = this._getKeys;
@@ -225,13 +277,23 @@ var AsyncStorage = {
},
/**
* multiGet invokes callback with an array of key-value pair arrays that
* matches the input format of multiSet. Returns a `Promise` object.
* This allows you to batch the fetching of items given an array of `key`
* inputs. Your callback will be invoked with an array of corresponding
* key-value pairs found:
*
* multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
* ```
* multiGet(['k1', 'k2'], cb) -> cb([['k1', 'val1'], ['k2', 'val2']])
* ```
*
* The method returns a `Promise` object.
*
* @param keys Array of key for the items to get.
* @param callback Function that will be called with a key-value array of
* the results, plus an array of any key-specific errors found.
* @returns A `Promise` object.
*
* @example <caption>Example</caption>
*
* Example:
* ```javascript
* AsyncStorage.getAllKeys((err, keys) => {
* AsyncStorage.multiGet(keys, (err, stores) => {
* stores.map((result, i, store) => {
@@ -241,7 +303,6 @@ var AsyncStorage = {
* });
* });
* });
* ```
*/
multiGet: function(
keys: Array<string>,
@@ -280,12 +341,20 @@ var AsyncStorage = {
},
/**
* multiSet and multiMerge take arrays of key-value array pairs that match
* the output of multiGet, e.g. Returns a `Promise` object.
* Use this as a batch operation for storing multiple key-value pairs. When
* the operation completes you'll get a single callback with any errors:
*
* multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
* ```
* multiSet([['k1', 'val1'], ['k2', 'val2']], cb);
* ```
*
* Example: see multiMerge for an example
* The method returns a `Promise` object.
*
* @param keyValuePairs Array of key-value array for the items to set.
* @param callback Function that will be called with an array of any
* key-specific errors found.
* @returns A `Promise` object.
* Example: see the `multiMerge` example.
*/
multiSet: function(
keyValuePairs: Array<Array<string>>,
@@ -305,16 +374,20 @@ var AsyncStorage = {
},
/**
* Delete all the keys in the `keys` array. Returns a `Promise` object.
* Call this to batch the deletion of all keys in the `keys` array. Returns
* a `Promise` object.
*
* Example:
* ```javascript
* @param keys Array of key for the items to delete.
* @param callback Function that will be called an array of any key-specific
* errors found.
* @returns A `Promise` object.
*
* @example <caption>Example</caption>
* let keys = ['k1', 'k2'];
* AsyncStorage.multiRemove(keys, (err) => {
* // keys k1 & k2 removed, if they existed
* // do most stuff after removal (if you want)
* });
* ```
*/
multiRemove: function(
keys: Array<string>,
@@ -334,42 +407,47 @@ var AsyncStorage = {
},
/**
* Merges existing values with input values, assuming they are stringified
* json. Returns a `Promise` object.
* Batch operation to merge in existing and new values for a given set of
* keys. This assumes that the values are stringified JSON. Returns a
* `Promise` object.
*
* Not supported by all native implementations.
* **NOTE**: This is not supported by all native implementations.
*
* Example:
* ```javascript
// first user, initial values
* @param keyValuePairs Array of key-value array for the items to merge.
* @param callback Function that will be called with an array of any
* key-specific errors found.
* @returns A `Promise` object.
*
* @example <caption>Example</caption>
* // first user, initial values
* let UID234_object = {
* name: 'Chris',
* age: 30,
* traits: {hair: 'brown', eyes: 'brown'},
* };
*
* // first user, delta values
* let UID234_delta = {
* age: 31,
* traits: {eyes: 'blue', shoe_size: 10},
* };
*
* // second user, initial values
* let UID345_object = {
* name: 'Marge',
* age: 25,
* traits: {hair: 'blonde', eyes: 'blue'},
* };
*
* // second user, delta values
* let UID345_delta = {
* age: 26,
* traits: {eyes: 'green', shoe_size: 6},
* };
*
* let multi_set_pairs = [['UID234', JSON.stringify(UID234_object)], ['UID345', JSON.stringify(UID345_object)]]
* let multi_merge_pairs = [['UID234', JSON.stringify(UID234_delta)], ['UID345', JSON.stringify(UID345_delta)]]
*
* AsyncStorage.multiSet(multi_set_pairs, (err) => {
* AsyncStorage.multiMerge(multi_merge_pairs, (err) => {
* AsyncStorage.multiGet(['UID234','UID345'], (err, stores) => {
@@ -377,13 +455,14 @@ var AsyncStorage = {
* let key = store[i][0];
* let val = store[i][1];
* console.log(key, val);
* // => UID234 {"name":"Chris","age":31,"traits":{"shoe_size":10,"hair":"brown","eyes":"blue"}}
* // => UID345 {"name":"Marge","age":26,"traits":{"shoe_size":6,"hair":"blonde","eyes":"green"}}
* });
* });
* });
* });
* ```
*
* // Console log results:
* // => UID234 {"name":"Chris","age":31,"traits":{"shoe_size":10,"hair":"brown","eyes":"blue"}}
* // => UID345 {"name":"Marge","age":26,"traits":{"shoe_size":6,"hair":"blonde","eyes":"green"}}
*/
multiMerge: function(
keyValuePairs: Array<Array<string>>,
+262 -11
View File
@@ -20,48 +20,252 @@ var ReactPropTypes = require('ReactPropTypes');
*
* The implementation in css-layout is slightly different from what the
* Flexbox spec defines - for example, we chose more sensible default
* values. Please refer to the css-layout README for details.
* values. Since our layout docs are generated from the comments in this
* file, please keep a brief comment describing each prop type.
*
* These properties are a subset of our styles that are consumed by the layout
* algorithm and affect the positioning and sizing of views.
*/
var LayoutPropTypes = {
/** `width` sets the width of this component.
*
* It works similarly to `width` in CSS, but in React Native you
* must use logical pixel units, rather than percents, ems, or any of that.
* See http://www.w3schools.com/cssref/pr_dim_width.asp for more details.
*/
width: ReactPropTypes.number,
/** `height` sets the height of this component.
*
* It works similarly to `height` in CSS, but in React Native you
* must use logical pixel units, rather than percents, ems, or any of that.
* See http://www.w3schools.com/cssref/pr_dim_width.asp for more details.
*/
height: ReactPropTypes.number,
/** `top` is the number of logical pixels to offset the top edge of
* this component.
*
* It works similarly to `top` in CSS, but in React Native you must
* use logical pixel units, rather than percents, ems, or any of that.
*
* See https://developer.mozilla.org/en-US/docs/Web/CSS/top
* for more details of how `top` affects layout.
*/
top: ReactPropTypes.number,
/** `left` is the number of logical pixels to offset the left edge of
* this component.
*
* It works similarly to `left` in CSS, but in React Native you must
* use logical pixel units, rather than percents, ems, or any of that.
*
* See https://developer.mozilla.org/en-US/docs/Web/CSS/left
* for more details of how `left` affects layout.
*/
left: ReactPropTypes.number,
/** `right` is the number of logical pixels to offset the right edge of
* this component.
*
* It works similarly to `right` in CSS, but in React Native you must
* use logical pixel units, rather than percents, ems, or any of that.
*
* See https://developer.mozilla.org/en-US/docs/Web/CSS/right
* for more details of how `right` affects layout.
*/
right: ReactPropTypes.number,
/** `bottom` is the number of logical pixels to offset the bottom edge of
* this component.
*
* It works similarly to `bottom` in CSS, but in React Native you must
* use logical pixel units, rather than percents, ems, or any of that.
*
* See https://developer.mozilla.org/en-US/docs/Web/CSS/bottom
* for more details of how `top` affects layout.
*/
bottom: ReactPropTypes.number,
/** `minWidth` is the minimum width for this component, in logical pixels.
*
* It works similarly to `min-width` in CSS, but in React Native you
* must use logical pixel units, rather than percents, ems, or any of that.
*
* See http://www.w3schools.com/cssref/pr_dim_min-width.asp
* for more details.
*/
minWidth: ReactPropTypes.number,
/** `maxWidth` is the maximum width for this component, in logical pixels.
*
* It works similarly to `max-width` in CSS, but in React Native you
* must use logical pixel units, rather than percents, ems, or any of that.
*
* See http://www.w3schools.com/cssref/pr_dim_max-width.asp
* for more details.
*/
maxWidth: ReactPropTypes.number,
/** `minHeight` is the minimum height for this component, in logical pixels.
*
* It works similarly to `min-height` in CSS, but in React Native you
* must use logical pixel units, rather than percents, ems, or any of that.
*
* See http://www.w3schools.com/cssref/pr_dim_min-height.asp
* for more details.
*/
minHeight: ReactPropTypes.number,
/** `maxHeight` is the maximum height for this component, in logical pixels.
*
* It works similarly to `max-height` in CSS, but in React Native you
* must use logical pixel units, rather than percents, ems, or any of that.
*
* See http://www.w3schools.com/cssref/pr_dim_max-height.asp
* for more details.
*/
maxHeight: ReactPropTypes.number,
/** Setting `margin` has the same effect as setting each of
* `marginTop`, `marginLeft`, `marginBottom`, and `marginRight`.
*/
margin: ReactPropTypes.number,
/** Setting `marginVertical` has the same effect as setting both
* `marginTop` and `marginBottom`.
*/
marginVertical: ReactPropTypes.number,
/** Setting `marginHorizontal` has the same effect as setting
* both `marginLeft` and `marginRight`.
*/
marginHorizontal: ReactPropTypes.number,
/** `marginTop` works like `margin-top` in CSS.
* See http://www.w3schools.com/cssref/pr_margin-top.asp
* for more details.
*/
marginTop: ReactPropTypes.number,
/** `marginBottom` works like `margin-bottom` in CSS.
* See http://www.w3schools.com/cssref/pr_margin-bottom.asp
* for more details.
*/
marginBottom: ReactPropTypes.number,
/** `marginLeft` works like `margin-left` in CSS.
* See http://www.w3schools.com/cssref/pr_margin-left.asp
* for more details.
*/
marginLeft: ReactPropTypes.number,
/** `marginRight` works like `margin-right` in CSS.
* See http://www.w3schools.com/cssref/pr_margin-right.asp
* for more details.
*/
marginRight: ReactPropTypes.number,
/** `padding` works like `padding` in CSS.
* It's like setting each of `paddingTop`, `paddingBottom`,
* `paddingLeft`, and `paddingRight` to the same thing.
* See http://www.w3schools.com/css/css_padding.asp
* for more details.
*/
padding: ReactPropTypes.number,
/** Setting `paddingVertical` is like setting both of
* `paddingTop` and `paddingBottom`.
*/
paddingVertical: ReactPropTypes.number,
/** Setting `paddingHorizontal` is like setting both of
* `paddingLeft` and `paddingRight`.
*/
paddingHorizontal: ReactPropTypes.number,
/** `paddingTop` works like `padding-top` in CSS.
* See http://www.w3schools.com/cssref/pr_padding-top.asp
* for more details.
*/
paddingTop: ReactPropTypes.number,
/** `paddingBottom` works like `padding-bottom` in CSS.
* See http://www.w3schools.com/cssref/pr_padding-bottom.asp
* for more details.
*/
paddingBottom: ReactPropTypes.number,
/** `paddingLeft` works like `padding-left` in CSS.
* See http://www.w3schools.com/cssref/pr_padding-left.asp
* for more details.
*/
paddingLeft: ReactPropTypes.number,
/** `paddingRight` works like `padding-right` in CSS.
* See http://www.w3schools.com/cssref/pr_padding-right.asp
* for more details.
*/
paddingRight: ReactPropTypes.number,
/** `borderWidth` works like `border-width` in CSS.
* See http://www.w3schools.com/cssref/pr_border-width.asp
* for more details.
*/
borderWidth: ReactPropTypes.number,
/** `borderTopWidth` works like `border-top-width` in CSS.
* See http://www.w3schools.com/cssref/pr_border-top_width.asp
* for more details.
*/
borderTopWidth: ReactPropTypes.number,
/** `borderRightWidth` works like `border-right-width` in CSS.
* See http://www.w3schools.com/cssref/pr_border-right_width.asp
* for more details.
*/
borderRightWidth: ReactPropTypes.number,
/** `borderBottomWidth` works like `border-bottom-width` in CSS.
* See http://www.w3schools.com/cssref/pr_border-bottom_width.asp
* for more details.
*/
borderBottomWidth: ReactPropTypes.number,
/** `borderLeftWidth` works like `border-left-width` in CSS.
* See http://www.w3schools.com/cssref/pr_border-bottom_width.asp
* for more details.
*/
borderLeftWidth: ReactPropTypes.number,
/** `position` in React Native is similar to regular CSS, but
* everything is set to `relative` by default, so `absolute`
* positioning is always just relative to the parent.
*
* If you want to position a child using specific numbers of logical
* pixels relative to its parent, set the child to have `absolute`
* position.
*
* If you want to position a child relative to something
* that is not its parent, just don't use styles for that. Use the
* component tree.
*
* See https://github.com/facebook/css-layout
* for more details on how `position` differs between React Native
* and CSS.
*/
position: ReactPropTypes.oneOf([
'absolute',
'relative'
]),
// https://developer.mozilla.org/en-US/docs/Web/CSS/flex-direction
/** `flexDirection` controls which directions children of a container go.
* `row` goes left to right, `column` goes top to bottom, and you may
* be able to guess what the other two do. It works like `flex-direction`
* in CSS, except the default is `column`. See
* https://css-tricks.com/almanac/properties/f/flex-direction/
* for more detail.
*/
flexDirection: ReactPropTypes.oneOf([
'row',
'row-reverse',
@@ -69,14 +273,24 @@ var LayoutPropTypes = {
'column-reverse'
]),
// https://developer.mozilla.org/en-US/docs/Web/CSS/flex-wrap
/** `flexWrap` controls whether children can wrap around after they
* hit the end of a flex container.
* It works like `flex-wrap` in CSS. See
* https://css-tricks.com/almanac/properties/f/flex-wrap/
* for more detail.
*/
flexWrap: ReactPropTypes.oneOf([
'wrap',
'nowrap'
]),
// How to align children in the main direction
// https://developer.mozilla.org/en-US/docs/Web/CSS/justify-content
/** `justifyContent` aligns children in the main direction.
* For example, if children are flowing vertically, `justifyContent`
* controls how they align vertically.
* It works like `justify-content` in CSS. See
* https://css-tricks.com/almanac/properties/j/justify-content/
* for more detail.
*/
justifyContent: ReactPropTypes.oneOf([
'flex-start',
'flex-end',
@@ -85,8 +299,14 @@ var LayoutPropTypes = {
'space-around'
]),
// How to align children in the cross direction
// https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
/** `alignItems` aligns children in the cross direction.
* For example, if children are flowing vertically, `alignItems`
* controls how they align horizontally.
* It works like `align-items` in CSS, except the default value
* is `stretch` instead of `flex-start`. See
* https://css-tricks.com/almanac/properties/a/align-items/
* for more detail.
*/
alignItems: ReactPropTypes.oneOf([
'flex-start',
'flex-end',
@@ -94,8 +314,12 @@ var LayoutPropTypes = {
'stretch'
]),
// How to align the element in the cross direction
// https://developer.mozilla.org/en-US/docs/Web/CSS/align-items
/** `alignSelf` controls how a child aligns in the cross direction,
* overriding the `alignItems` of the parent. It works like `align-self`
* in CSS. See
* https://css-tricks.com/almanac/properties/a/align-self/
* for more detail.
*/
alignSelf: ReactPropTypes.oneOf([
'auto',
'flex-start',
@@ -104,10 +328,37 @@ var LayoutPropTypes = {
'stretch'
]),
// https://developer.mozilla.org/en-US/docs/Web/CSS/flex
/** In React Native `flex` does not work the same way that it does in CSS.
* `flex` is a number rather than a string, and it works
* according to the `css-layout` library
* at https://github.com/facebook/css-layout .
*
* When `flex` is a positive number, it makes the component flexible
* and it will be sized proportional to its flex value. So a
* component with `flex` set to 2 will take twice the space as a
* component with `flex` set to 1.
*
* When `flex` is 0, the component is sized according to `width`
* and `height` and it is inflexible.
*
* When `flex` is -1, the component is normally sized according
* `width` and `height`. However, if there's not enough space,
* the component will shrink to its `minWidth` and `minHeight`.
*/
flex: ReactPropTypes.number,
// https://developer.mozilla.org/en-US/docs/Web/CSS/z-index
/** `zIndex` controls which components display on top of others.
* Normally, you don't use `zIndex`. Components render according to
* their order in the document tree, so later components draw over
* earlier ones. `zIndex` may be useful if you have animations or custom
* modal interfaces where you don't want this behavior.
*
* It works like the CSS `z-index` property - components with a larger
* `zIndex` will render on top. Think of the z-direction like it's
* pointing from the phone into your eyeball. See
* https://developer.mozilla.org/en-US/docs/Web/CSS/z-index for
* more detail.
*/
zIndex: ReactPropTypes.number,
};
+79 -24
View File
@@ -36,27 +36,42 @@ const viewConfig = {
};
/**
* A React component for displaying text which supports nesting,
* styling, and touch handling. In the following example, the nested title and
* body text will inherit the `fontFamily` from `styles.baseText`, but the title
* provides its own additional styles. The title and body will stack on top of
* each other on account of the literal newlines:
* A React component for displaying text.
*
* ```
* renderText: function() {
* return (
* <Text style={styles.baseText}>
* <Text style={styles.titleText} onPress={this.onPressTitle}>
* {this.state.titleText + '\n\n'}
* `Text` supports nesting, styling, and touch handling.
*
* In the following example, the nested title and body text will inherit the `fontFamily` from
*`styles.baseText`, but the title provides its own additional styles. The title and body will
* stack on top of each other on account of the literal newlines:
*
* ```ReactNativeWebPlayer
* import React, { Component } from 'react';
* import { AppRegistry, Text, StyleSheet } from 'react-native';
*
* class TextInANest extends Component {
* constructor(props) {
* super(props);
* this.state = {
* titleText: "Bird's Nest",
* bodyText: 'This is not really a bird nest.'
* };
* }
*
* render() {
* return (
* <Text style={styles.baseText}>
* <Text style={styles.titleText} onPress={this.onPressTitle}>
* {this.state.titleText}<br /><br />
* </Text>
* <Text numberOfLines={5}>
* {this.state.bodyText}
* </Text>
* </Text>
* <Text numberOfLines={5}>
* {this.state.bodyText}
* </Text>
* </Text>
* );
* },
* ...
* var styles = StyleSheet.create({
* );
* }
* }
*
* const styles = StyleSheet.create({
* baseText: {
* fontFamily: 'Cochin',
* },
@@ -64,21 +79,39 @@ const viewConfig = {
* fontSize: 20,
* fontWeight: 'bold',
* },
* };
* });
*
* // App registration and rendering
* AppRegistry.registerComponent('TextInANest', () => TextInANest);
* ```
*/
const Text = React.createClass({
propTypes: {
/**
* Line Break mode. Works only with numberOfLines.
* clip is working only for iOS
* Line Break mode. This can be one of the following values:
*
* - `head` - The line is displayed so that the end fits in the container and the missing text
* at the beginning of the line is indicated by an ellipsis glyph. e.g., "...wxyz"
* - `middle` - The line is displayed so that the beginning and end fit in the container and the
* missing text in the middle is indicated by an ellipsis glyph. "ab...yz"
* - `tail` - The line is displayed so that the beginning fits in the container and the
* missing text at the end of the line is indicated by an ellipsis glyph. e.g., "abcd..."
* - `clip` - Lines are not drawn past the edge of the text container.
*
* The default is `tail`.
*
* `numberOfLines` must be set in conjunction with this prop.
*
* > `clip` is working only for iOS
*/
lineBreakMode: React.PropTypes.oneOf(['head', 'middle', 'tail', 'clip']),
/**
* Used to truncate the text with an ellipsis after computing the text
* layout, including line wrapping, such that the total number of lines
* does not exceed this number.
*
* This prop is commonly used with `lineBreakMode`.
*/
numberOfLines: React.PropTypes.number,
/**
@@ -89,15 +122,26 @@ const Text = React.createClass({
onLayout: React.PropTypes.func,
/**
* This function is called on press.
*
* e.g., `onPress={() => console.log('1st')}``
*/
onPress: React.PropTypes.func,
/**
* This function is called on long press.
*
* e.g., `onLongPress={this.increaseSize}>``
*/
onLongPress: React.PropTypes.func,
/**
* When true, no visual change is made when text is pressed down. By
* Lets the user select text, to use the native copy and paste functionality.
*
* @platform android
*/
selectable: React.PropTypes.bool,
/**
* When `true`, no visual change is made when text is pressed down. By
* default, a gray oval highlights the text on press down.
*
* @platform ios
*/
suppressHighlighting: React.PropTypes.bool,
@@ -107,10 +151,21 @@ const Text = React.createClass({
*/
testID: React.PropTypes.string,
/**
* Specifies should fonts scale to respect Text Size accessibility setting on iOS.
* Specifies whether fonts should scale to respect Text Size accessibility setting on iOS. The
* default is `true`.
*
* @platform ios
*/
allowFontScaling: React.PropTypes.bool,
/**
* When set to `true`, indicates that the view is an accessibility element. The default value
* for a `Text` element is `true`.
*
* See the
* [Accessibility guide](/react-native/docs/accessibility.html#accessible-ios-android)
* for more information.
*/
accessible: React.PropTypes.bool,
},
getDefaultProps(): Object {
return {
+106 -40
View File
@@ -8,64 +8,129 @@
*
* @providesModule AlertIOS
* @flow
* @jsdoc
*/
'use strict';
var RCTAlertManager = require('NativeModules').AlertManager;
/**
* An Alert button type
*/
export type AlertType = $Enum<{
/**
* Default alert with no inputs
*/
'default': string;
/**
* Plain text input alert
*/
'plain-text': string;
/**
* Secure text input alert
*/
'secure-text': string;
/**
* Login and password alert
*/
'login-password': string;
}>;
/**
* An Alert button style
*/
export type AlertButtonStyle = $Enum<{
/**
* Default button style
*/
'default': string;
/**
* Cancel button style
*/
'cancel': string;
/**
* Destructive button style
*/
'destructive': string;
}>;
/**
* Array or buttons
* @typedef {Array} ButtonsArray
* @property {string=} text Button label
* @property {Function=} onPress Callback function when button pressed
* @property {AlertButtonStyle=} style Button style
*/
type ButtonsArray = Array<{
/**
* Button label
*/
text?: string;
/**
* Callback function when button pressed
*/
onPress?: ?Function;
/**
* Button style
*/
style?: AlertButtonStyle;
}>;
/**
* The AlertsIOS utility provides two functions: `alert` and `prompt`. All
* functionality available through `AlertIOS.alert` is also available in the
* cross-platform `Alert.alert`, which we recommend you use if you don't need
* iOS-specific functionality.
* @description
* `AlertIOS` provides functionality to create an iOS alert dialog with a
* message or create a prompt for user input.
*
* `AlertIOS.prompt` allows you to prompt the user for input inside of an
* alert popup.
* Creating an iOS alert:
*
* ```
* AlertIOS.alert(
* 'Sync Complete',
* 'All your data are belong to us.'
* );
* ```
*
* Creating an iOS prompt:
*
* ```
* AlertIOS.prompt(
* 'Enter a value',
* null,
* text => console.log("You entered "+text)
* );
* ```
*
* We recommend using the [`Alert.alert`](/docs/alert.html) method for
* cross-platform support if you don't need to create iOS-only prompts.
*
*/
class AlertIOS {
/**
* Creates a popup to alert the user. See
* [Alert](docs/alert.html).
*
* - title: string -- The dialog's title.
* - message: string -- An optional message that appears above the text input.
* - callbackOrButtons -- This optional argument should be either a
* single-argument function or an array of buttons. If passed a function,
* it will be called when the user taps 'OK'.
* Create and display a popup alert.
* @static
* @method alert
* @param title The dialog's title.
* @param message An optional message that appears below
* the dialog's title.
* @param callbackOrButtons This optional argument should
* be either a single-argument function or an array of buttons. If passed
* a function, it will be called when the user taps 'OK'.
*
* If passed an array of button configurations, each button should include
* a `text` key, as well as optional `onPress` and `style` keys.
* `style` should be one of 'default', 'cancel' or 'destructive'.
* - type -- *deprecated, do not use*
* a `text` key, as well as optional `onPress` and `style` keys. `style`
* should be one of 'default', 'cancel' or 'destructive'.
* @param type Deprecated, do not use.
*
* Example:
* @example <caption>Example with custom buttons</caption>
*
* ```
* AlertIOS.alert(
* 'Sync Complete',
* 'All your data are belong to us.'
* 'Update available',
* 'Keep your app up to date to enjoy the latest features',
* [
* {text: 'Cancel', onPress: () => console.log('Cancel Pressed'), style: 'cancel'},
* {text: 'Install', onPress: () => console.log('Install Pressed')},
* ],
* );
* ```
*/
static alert(
title: ?string,
@@ -82,23 +147,26 @@ class AlertIOS {
}
/**
* Prompt the user to enter some text.
*
* - title: string -- The dialog's title.
* - message: string -- An optional message that appears above the text input.
* - callbackOrButtons -- This optional argument should be either a
* single-argument function or an array of buttons. If passed a function,
* it will be called with the prompt's value when the user taps 'OK'.
* Create and display a prompt to enter some text.
* @static
* @method prompt
* @param title The dialog's title.
* @param message An optional message that appears above the text
* input.
* @param callbackOrButtons This optional argument should
* be either a single-argument function or an array of buttons. If passed
* a function, it will be called with the prompt's value when the user
* taps 'OK'.
*
* If passed an array of button configurations, each button should include
* a `text` key, as well as optional `onPress` and `style` keys (see example).
* `style` should be one of 'default', 'cancel' or 'destructive'.
* - type: string -- This configures the text input. One of 'plain-text',
* a `text` key, as well as optional `onPress` and `style` keys (see
* example). `style` should be one of 'default', 'cancel' or 'destructive'.
* @param type This configures the text input. One of 'plain-text',
* 'secure-text' or 'login-password'.
* - defaultValue: string -- the default value for the text field.
* @param defaultValue The dialog's title.
*
* @example <caption>Example with custom buttons</caption>
*
* Example with custom buttons:
* ```
* AlertIOS.prompt(
* 'Enter password',
* 'Enter your password to claim your $1.5B in lottery winnings',
@@ -108,18 +176,16 @@ class AlertIOS {
* ],
* 'secure-text'
* );
* ```
*
* Example with the default button and a custom callback:
* ```
* @example <caption>Example with the default button and a custom callback</caption>
*
* AlertIOS.prompt(
* 'Update username',
* null,
* text => console.log("Your username is "+text),
* null,
* 'default'
* )
* ```
* );
*/
static prompt(
title: ?string,
+7 -1
View File
@@ -4,7 +4,7 @@ package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
Pod::Spec.new do |s|
s.name = "React"
s.version = package['version']
s.version = "0.29.1"
s.summary = package['description']
s.description = <<-DESC
React Native apps are built using the React JS
@@ -54,6 +54,12 @@ Pod::Spec.new do |s|
ss.preserve_paths = "Libraries/AdSupport/*.js"
end
s.subspec 'RCTAnimation' do |ss|
ss.dependency 'React/Core'
ss.source_files = "Libraries/NativeAnimation/{Nodes/*,*}.{h,m}"
ss.preserve_paths = "Libraries/NativeAnimation/*.js"
end
s.subspec 'RCTCameraRoll' do |ss|
ss.dependency 'React/Core'
ss.dependency 'React/RCTImage'
+1 -1
View File
@@ -162,7 +162,7 @@ static NSString *serverRootWithHost(NSString *host)
[self updateDefaults:@(enableDev) forKey:kRCTEnableDevKey];
}
- (void)setEnableEnableLiveReload:(BOOL)enableLiveReload
- (void)setEnableLiveReload:(BOOL)enableLiveReload
{
[self updateDefaults:@(enableLiveReload) forKey:kRCTEnableLiveReloadKey];
}
+1 -2
View File
@@ -345,8 +345,7 @@ static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
NSString *cachesPath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) firstObject];
RCTAssert(cachesPath != nil, @"cachesPath should not be nil");
if (cachesPath) {
std::string path = std::string([cachesPath UTF8String]);
strongSelf->_jscWrapper->configureJSContextForIOS(strongSelf.context.ctx, path);
strongSelf->_jscWrapper->configureJSContextForIOS(strongSelf.context.ctx, [cachesPath UTF8String]);
}
}];
+1 -2
View File
@@ -10,7 +10,6 @@
#import <JavaScriptCore/JavaScriptCore.h>
#import "RCTDefines.h"
#import <string>
typedef JSStringRef (*JSValueToStringCopyFuncType)(JSContextRef, JSValueRef, JSValueRef *);
typedef JSStringRef (*JSStringCreateWithCFStringFuncType)(CFStringRef);
@@ -29,7 +28,7 @@ typedef JSStringRef (*JSValueCreateJSONStringFuncType)(JSContextRef, JSValueRef,
typedef bool (*JSValueIsUndefinedFuncType)(JSContextRef, JSValueRef);
typedef bool (*JSValueIsNullFuncType)(JSContextRef, JSValueRef);
typedef JSValueRef (*JSEvaluateScriptFuncType)(JSContextRef, JSStringRef, JSObjectRef, JSStringRef, int, JSValueRef *);
typedef void (*configureJSContextForIOSFuncType)(JSContextRef ctx, const std::string &cacheDir);
typedef void (*configureJSContextForIOSFuncType)(JSContextRef ctx, const char *cacheDir);
typedef struct RCTJSCWrapper {
JSValueToStringCopyFuncType JSValueToStringCopy;
+6
View File
@@ -95,6 +95,7 @@
83CBBA981A6020BB00E9B192 /* RCTTouchHandler.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBA971A6020BB00E9B192 /* RCTTouchHandler.m */; };
83CBBACC1A6023D300E9B192 /* RCTConvert.m in Sources */ = {isa = PBXBuildFile; fileRef = 83CBBACB1A6023D300E9B192 /* RCTConvert.m */; };
85C199EE1CD2407900DAD810 /* RCTJSCWrapper.mm in Sources */ = {isa = PBXBuildFile; fileRef = 85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */; };
B95154321D1B34B200FE7B80 /* RCTActivityIndicatorView.m in Sources */ = {isa = PBXBuildFile; fileRef = B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */; };
E9B20B7B1B500126007A2DA7 /* RCTAccessibilityManager.m in Sources */ = {isa = PBXBuildFile; fileRef = E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */; };
/* End PBXBuildFile section */
@@ -306,6 +307,8 @@
85C199EC1CD2407900DAD810 /* RCTJSCWrapper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTJSCWrapper.h; sourceTree = "<group>"; };
85C199ED1CD2407900DAD810 /* RCTJSCWrapper.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; path = RCTJSCWrapper.mm; sourceTree = "<group>"; };
ACDD3FDA1BC7430D00E7DE33 /* RCTBorderStyle.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTBorderStyle.h; sourceTree = "<group>"; };
B95154301D1B34B200FE7B80 /* RCTActivityIndicatorView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTActivityIndicatorView.h; sourceTree = "<group>"; };
B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTActivityIndicatorView.m; sourceTree = "<group>"; };
E3BBC8EB1ADE6F47001BBD81 /* RCTTextDecorationLineType.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RCTTextDecorationLineType.h; sourceTree = "<group>"; };
E9B20B791B500126007A2DA7 /* RCTAccessibilityManager.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RCTAccessibilityManager.h; sourceTree = "<group>"; };
E9B20B7A1B500126007A2DA7 /* RCTAccessibilityManager.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RCTAccessibilityManager.m; sourceTree = "<group>"; };
@@ -382,6 +385,8 @@
13B07FF31A6947C200A75B9A /* Views */ = {
isa = PBXGroup;
children = (
B95154301D1B34B200FE7B80 /* RCTActivityIndicatorView.h */,
B95154311D1B34B200FE7B80 /* RCTActivityIndicatorView.m */,
13B080181A69489C00A75B9A /* RCTActivityIndicatorViewManager.h */,
13B080191A69489C00A75B9A /* RCTActivityIndicatorViewManager.m */,
13442BF21AA90E0B0037E5B0 /* RCTAnimationType.h */,
@@ -756,6 +761,7 @@
58114A171AAE854800E7D092 /* RCTPickerManager.m in Sources */,
191E3EBE1C29D9AF00C180A6 /* RCTRefreshControlManager.m in Sources */,
68EFE4EE1CF6EB3900A1DE13 /* RCTBundleURLProvider.m in Sources */,
B95154321D1B34B200FE7B80 /* RCTActivityIndicatorView.m in Sources */,
13B0801A1A69489C00A75B9A /* RCTNavigator.m in Sources */,
137327E71AA5CF210034F82E /* RCTTabBar.m in Sources */,
13F17A851B8493E5007D4C75 /* RCTRedBox.m in Sources */,
+13
View File
@@ -0,0 +1,13 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import <UIKit/UIKit.h>
@interface RCTActivityIndicatorView : UIActivityIndicatorView
@end
+24
View File
@@ -0,0 +1,24 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
#import "RCTActivityIndicatorView.h"
@implementation RCTActivityIndicatorView {
}
- (void)setHidden:(BOOL)hidden
{
if ([self hidesWhenStopped] && ![self isAnimating]) {
[super setHidden: YES];
} else {
[super setHidden: hidden];
}
}
@end
@@ -8,7 +8,7 @@
*/
#import "RCTActivityIndicatorViewManager.h"
#import "RCTActivityIndicatorView.h"
#import "RCTConvert.h"
@implementation RCTConvert (UIActivityIndicatorView)
@@ -29,7 +29,7 @@ RCT_EXPORT_MODULE()
- (UIView *)view
{
return [UIActivityIndicatorView new];
return [RCTActivityIndicatorView new];
}
RCT_EXPORT_VIEW_PROPERTY(color, UIColor)
+1 -1
View File
@@ -1,4 +1,4 @@
VERSION_NAME=1000.0.0-master
VERSION_NAME=0.29.1
GROUP=com.facebook.react
POM_NAME=ReactNative
@@ -9,6 +9,8 @@
package com.facebook.react.devsupport;
import javax.annotation.Nullable;
import java.io.File;
import com.facebook.react.bridge.ReadableArray;
@@ -91,9 +93,10 @@ public class StackTraceHelper {
* Convert a JavaScript stack trace (see {@code parseErrorStack} JS module) to an array of
* {@link StackFrame}s.
*/
public static StackFrame[] convertJsStackTrace(ReadableArray stack) {
StackFrame[] result = new StackFrame[stack.size()];
for (int i = 0; i < stack.size(); i++) {
public static StackFrame[] convertJsStackTrace(@Nullable ReadableArray stack) {
int size = stack != null ? stack.size() : 0;
StackFrame[] result = new StackFrame[size];
for (int i = 0; i < size; i++) {
ReadableMap frame = stack.getMap(i);
String methodName = frame.getString("methodName");
String fileName = frame.getString("file");
+27 -30
View File
@@ -68,25 +68,6 @@ static JSValueRef nativeInjectHMRUpdate(
const JSValueRef arguments[],
JSValueRef *exception);
static std::string executeJSCallWithJSC(
JSGlobalContextRef ctx,
const std::string& methodName,
const std::vector<folly::dynamic>& arguments) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(
TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.executeJSCall",
"method", methodName);
#endif
// Evaluate script with JSC
folly::dynamic jsonArgs(arguments.begin(), arguments.end());
auto js = folly::to<std::string>(
"__fbBatchedBridge.", methodName, ".apply(null, ",
folly::toJson(jsonArgs), ")");
auto result = evaluateScript(ctx, String(js.c_str()), nullptr);
return Value(ctx, result).toJSONString();
}
std::unique_ptr<JSExecutor> JSCExecutorFactory::createJSExecutor(Bridge *bridge) {
return std::unique_ptr<JSExecutor>(new JSCExecutor(bridge, cacheDir_, m_jscConfig));
}
@@ -202,6 +183,8 @@ void JSCExecutor::terminateOnJSVMThread() {
m_batchedBridge.reset();
m_flushedQueueObj.reset();
m_callFunctionObj.reset();
m_invokeCallbackObj.reset();
s_globalContextRefToJSCExecutor.erase(m_context);
JSGlobalContextRelease(m_context);
@@ -266,6 +249,8 @@ bool JSCExecutor::ensureBatchedBridgeObject() {
}
m_batchedBridge = folly::make_unique<Object>(batchedBridgeValue.asObject());
m_flushedQueueObj = folly::make_unique<Object>(m_batchedBridge->getProperty("flushedQueue").asObject());
m_callFunctionObj = folly::make_unique<Object>(m_batchedBridge->getProperty("callFunctionReturnFlushedQueue").asObject());
m_invokeCallbackObj = folly::make_unique<Object>(m_batchedBridge->getProperty("invokeCallbackAndReturnFlushedQueue").asObject());
return true;
}
@@ -290,6 +275,10 @@ void JSCExecutor::flush() {
}
void JSCExecutor::callFunction(const std::string& moduleId, const std::string& methodId, const folly::dynamic& arguments) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.callFunction");
#endif
if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't call JS module %s, method %s: bridge configuration isn't available. This "
@@ -298,27 +287,35 @@ void JSCExecutor::callFunction(const std::string& moduleId, const std::string& m
methodId.c_str());
}
std::vector<folly::dynamic> call {
moduleId,
methodId,
std::move(arguments),
String argsString = String(folly::toJson(std::move(arguments)).c_str());
String moduleIdStr(moduleId.c_str());
String methodIdStr(methodId.c_str());
JSValueRef args[] = {
JSValueMakeString(m_context, moduleIdStr),
JSValueMakeString(m_context, methodIdStr),
Value::fromJSON(m_context, argsString)
};
std::string calls = executeJSCallWithJSC(m_context, "callFunctionReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(*this, calls, true);
auto result = m_callFunctionObj->callAsFunction(3, args);
m_bridge->callNativeModules(*this, result.toJSONString(), true);
}
void JSCExecutor::invokeCallback(const double callbackId, const folly::dynamic& arguments) {
#ifdef WITH_FBSYSTRACE
FbSystraceSection s(TRACE_TAG_REACT_CXX_BRIDGE, "JSCExecutor.invokeCallback");
#endif
if (!ensureBatchedBridgeObject()) {
throwJSExecutionException(
"Couldn't invoke JS callback %d: bridge configuration isn't available. This shouldn't be possible. Congratulations.", (int) callbackId);
}
std::vector<folly::dynamic> call {
(double) callbackId,
std::move(arguments)
String argsString = String(folly::toJson(std::move(arguments)).c_str());
JSValueRef args[] = {
JSValueMakeNumber(m_context, callbackId),
Value::fromJSON(m_context, argsString)
};
std::string calls = executeJSCallWithJSC(m_context, "invokeCallbackAndReturnFlushedQueue", std::move(call));
m_bridge->callNativeModules(*this, calls, true);
auto result = m_invokeCallbackObj->callAsFunction(2, args);
m_bridge->callNativeModules(*this, result.toJSONString(), true);
}
void JSCExecutor::setGlobalVariable(const std::string& propName, const std::string& jsonValue) {
@@ -91,6 +91,8 @@ private:
folly::dynamic m_jscConfig;
std::unique_ptr<Object> m_batchedBridge;
std::unique_ptr<Object> m_flushedQueueObj;
std::unique_ptr<Object> m_callFunctionObj;
std::unique_ptr<Object> m_invokeCallbackObj;
/**
* WebWorker constructor. Must be invoked from thread this Executor will run on.
+1 -1
View File
@@ -4,7 +4,7 @@ title: Accessibility
layout: docs
category: Guides
permalink: docs/accessibility.html
next: direct-manipulation
next: timers
---
## Native App Accessibility (iOS and Android)
+15 -3
View File
@@ -20,13 +20,25 @@ Make sure you have the following installed:
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:
### Point Gradle to your Android SDK:
**Step 1:** Set environment variables through your local shell.
Note: Files may vary based on shell flavor. See below for examples from common shells.
- bash: `.bash_profile` or `.bashrc`
- zsh: `.zprofile` or `.zshrc`
- ksh: `.profile` or `$ENV`
Example:
```
sdk.dir=absolute_path_to_android_sdk
ndk.dir=absolute_path_to_android_ndk
export ANDROID_SDK=/Users/your_unix_name/android-sdk-macosx
export ANDROID_NDK=/Users/your_unix_name/android-ndk/android-ndk-r10e
```
**Step 2:** Create a `local.properties` file in the `android` directory of your react-native app with the following contents:
Example:
```
+4 -4
View File
@@ -24,13 +24,13 @@ component with a simple spring bounce on mount looks like this:
```javascript
class Playground extends React.Component {
constructor(props: any) {
constructor(props) {
super(props);
this.state = {
bounceValue: new Animated.Value(0),
};
}
render(): ReactElement {
render() {
return (
<Animated.Image // Base: Image, Text, View
source={{uri: 'http://i.imgur.com/XMKOH81.jpg'}}
@@ -286,7 +286,7 @@ class App extends React.Component {
componentWillMount() {
// Animate creation
LayoutAnimation.spring();
},
}
_onPress() {
// Animate the update
@@ -306,7 +306,7 @@ class App extends React.Component {
</View>
);
}
};
}
```
[Run this example](https://rnplay.org/apps/uaQrGQ)
+2 -1
View File
@@ -2,8 +2,9 @@
id: colors
title: Colors
layout: docs
category: Polyfills
category: Guides
permalink: docs/colors.html
next: images
---
The following formats are supported:
+49 -31
View File
@@ -7,6 +7,33 @@ permalink: docs/debugging.html
next: testing
---
## Accessing the In-App Developer Menu
You can access the developer menu by shaking your device or by selecting "Shake Gesture" inside the Hardware menu in the iOS Simulator. You can also use the **`Command`**`⌘` + **`D`** keyboard shortcut when your app is running in the iPhone Simulator, or **`Command`**`⌘` + **`M`** when running in an Android emulator.
![](img/DeveloperMenu.png)
> The Developer Menu is disabled in release (production) builds.
## Reloading JavaScript
Instead of recompiling your app every time you make a change, you can reload your app's JavaScript code instantly. To do so, select "Reload" from the Developer Menu. You can also press **`Command`**`⌘` + **`R`** in the iOS Simulator, or press **`R`** twice on Android emulators.
> If the **`Command`**`⌘` + **`R`** keyboard shortcut does not seem to reload the iOS Simulator, go to the Hardware menu, select Keyboard, and make sure that "Connect Hardware Keyboard" is checked.
### Automatic reloading
You can speed up your development times by having your app reload automatically any time your code changes. Automatic reloading can be enabled by selecting "Enable Live Reload" from the Developer Menu.
You may even go a step further and keep your app running as new versions of your files are injected into the JavaScript bundle automatically by enabling [Hot Reloading](https://facebook.github.io/react-native/blog/2016/03/24/introducing-hot-reloading.html) from the Developer Menu. This will allow you to persist the app's state through reloads.
> There are some instances where hot reloading cannot be implemented perfectly. If you run into any issues, use a full reload to reset your app.
You will need to rebuild your app for changes to take effect in certain situations:
* You have added new resources to your native app's bundle, such as an image in `Images.xcassets` on iOS or the `res/drawable` folder on Android.
* You have modified native code (Objective-C/Swift on iOS or Java/C++ on Android).
## In-app Errors and Warnings
Errors and warnings are displayed inside your app in development builds.
@@ -25,55 +52,46 @@ YellowBoxes can be disabled during development by using `console.disableYellowBo
> RedBoxes and YellowBoxes are automatically disabled in release (production) builds.
## Accessing the In-App Developer Menu
## Accessing console logs
You can access the developer menu by shaking your device. You can also use the `Command⌘ + D` keyboard shortcut when your app is running in the iPhone Simulator, or `Command⌘ + M` when running in an Android emulator.
You can display the console logs for an iOS or Android app by using the following commands in a terminal while the app is running:
> The Developer Menu is disabled in release (production) builds.
```
$ react-native log-ios
$ react-native log-android
```
## Reloading JavaScript
Selecting `Reload` from the Developer Menu will reload the JavaScript that powers your application. You can also press `Command⌘ + R` in the iOS Simulator, or press `R` twice on Android emulators.
You will need to rebuild your app for changes to take effect in certain situations:
* You have added new resources to your native app's bundle, such as an image in `Images.xcassets` on iOS or in `res/drawable` folder on Android.
* You have modified native code (Objective-C/Swift on iOS or Java/C++ on Android).
### Automatic reloading
You may enable Live Reload to automatically trigger a reload whenever your JavaScript code changes.
Live Reload is available on iOS via the Developer Menu. On Android, select "Dev Settings" from the Developer Menu and enable "Auto reload on JS change".
## Accessing logs
To view detailed logs on iOS, open your app in Xcode, then Build and Run your app on a device or the iPhone Simulator. The console should appear automatically after the app launches.
Run `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal to display the logs for an Android app running on a device or an emulator.
You may also access these through `Debug → Open System Log...` in the iOS Simulator or by running `adb logcat *:S ReactNative:V ReactNativeJS:V` in a terminal while an Android app is running on a device or emulator.
## 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).
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 `Command⌘ + 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.
Select `Tools → Developer Tools` from the Chrome Menu to open the [Developer Tools](https://developer.chrome.com/devtools). You may also access the DevTools using keyboard shortcuts (**`Command`**`⌘` + **`Option`**`⌥` + **`I`** on Mac, **`Ctrl`** + **`Shift`** + **`I`** on Windows). You may also want to 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.
> It is [currently not possible](https://github.com/facebook/react-devtools/issues/229) to use the "React" tab in the Chrome Developer Tools to inspect app widgets. You can use Nuclide's "React Native Inspector" as a workaround.
### Debugging on a device with Chrome Developer Tools
On iOS devices, 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, then select `Debug JS Remotely` from the Developer Menu.
On iOS devices, 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, then select "Debug JS Remotely" from the Developer Menu.
On Android 5.0+ devices connected via USB, you can use the [`adb` command line tool](http://developer.android.com/tools/help/adb.html) to setup port forwarding from the device to your computer:
`adb reverse tcp:8081 tcp:8081`
Alternatively, select `Dev Settings` from the Developer Menu, then update the `Debug server host for device` setting to match the IP address of your computer.
Alternatively, select "Dev Settings" from the Developer Menu, then update the "Debug server host for device" setting to match the IP address of your computer.
> If you run into any issues, it may be possible that one of your Chrome extensions is interacting in unexpected ways with the debugger. Try disabling all of your extensions and re-enabling them one-by-one until you find the problematic extension.
### Debugging using a custom JavaScript debugger
To use a custom JavaScript debugger in place of Chrome Developer Tools, set the `REACT_DEBUGGER` environment variable to a command that will start your custom debugger. You can then select `Debug JS Remotely` from the Developer Menu to start debugging.
To use a custom JavaScript debugger in place of Chrome Developer Tools, set the `REACT_DEBUGGER` environment variable to a command that will start your custom debugger. You can then select "Debug JS Remotely" from the Developer Menu to start debugging.
> The debugger will receive a list of all project roots, separated by a space. For example, 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 be used to start your debugger. Custom debugger commands executed this way should be short-lived processes, and they shouldn't produce more than 200 kilobytes of output.
The debugger will receive a list of all project roots, separated by a space. For example, 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 be used to start your debugger.
## FPS (Frames per Second) Monitor
> Custom debugger commands executed this way should be short-lived processes, and they shouldn't produce more than 200 kilobytes of output.
You can enable a FPS graph overlay in the Developer Menu in order to help you debug performance problems.
## Performance Monitor
You can enable a performance overlay to help you debug performance problems by selecting "Perf Monitor" in the Developer Menu.
+23 -17
View File
@@ -32,7 +32,7 @@ uses `setNativeProps` internally to update the opacity of its child
component:
```javascript
setOpacityTo: function(value) {
setOpacityTo(value) {
// Redacted: animation related code
this.refs[CHILD_REF].setNativeProps({
opacity: value
@@ -57,9 +57,10 @@ 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, }
},
constructor(props) {
super(props);
this.state = { myButtonOpacity: 1, };
}
render() {
return (
@@ -93,25 +94,25 @@ Composite components are not backed by a native view, so you cannot call
`setNativeProps` on them. Consider this example:
```javascript
var MyButton = React.createClass({
class MyButton extends React.Component {
render() {
return (
<View>
<Text>{this.props.label}</Text>
</View>
)
},
});
}
}
var App = React.createClass({
class App extends React.Component {
render() {
return (
<TouchableOpacity>
<MyButton label="Press me!" />
</TouchableOpacity>
)
},
});
}
}
```
[Run this example](https://rnplay.org/apps/JXkgmQ)
@@ -132,10 +133,10 @@ that calls `setNativeProps` on the appropriate child with the given
arguments.
```javascript
var MyButton = React.createClass({
class MyButton extends React.Component {
setNativeProps(nativeProps) {
this._root.setNativeProps(nativeProps);
},
}
render() {
return (
@@ -143,8 +144,8 @@ var MyButton = React.createClass({
<Text>{this.props.label}</Text>
</View>
)
},
});
}
}
```
[Run this example](https://rnplay.org/apps/YJxnEQ)
@@ -172,10 +173,15 @@ necessary. For example, the following code demonstrates clearing the
input when you tap a button:
```javascript
var App = React.createClass({
class App extends React.Component {
constructor(props) {
super(props);
this.clearText = this.clearText.bind(this);
}
clearText() {
this._textInput.setNativeProps({text: ''});
},
}
render() {
return (
@@ -188,7 +194,7 @@ var App = React.createClass({
</View>
);
}
});
}
```
[Run this example](https://rnplay.org/plays/pOI9bA)
+1 -1
View File
@@ -4,7 +4,7 @@ title: Gesture Responder System
layout: docs
category: Guides
permalink: docs/gesture-responder-system.html
next: animations
next: native-modules-ios
---
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.
@@ -2,11 +2,19 @@
id: quick-start-getting-started
title: Getting Started
layout: docs
category: Quick Start
category: The Basics
permalink: docs/getting-started.html
next: tutorial-core-components
next: tutorial
---
Welcome to React Native! This page will help you install React Native on
your system, so that you can build apps with it right away. If you already
have React Native installed, you can skip ahead to the
[Tutorial](/react-native/docs/tutorial.html).
The instructions are a bit different depending on your development operating system, and whether you want to start developing for iOS or Android. If you
want to develop for both iOS and Android, that's fine - you just have to pick
one to start with, since the setup is a bit different.
<div class="toggler">
<style>
@@ -35,7 +43,7 @@ block { display: none; }
.display-platform-android.display-os-windows .android.windows {
display: block;
}</style>
<span>Target:</span>
<span>Mobile OS:</span>
<a href="javascript:void(0);" class="button-ios" onclick="display('platform', 'ios')">iOS</a>
<a href="javascript:void(0);" class="button-android" onclick="display('platform', 'android')">Android</a>
<span>Development OS:</span>
@@ -50,7 +58,7 @@ block { display: none; }
## Unsupported
<div>Unfortunately, Apple only lets you develop for iOS on a Mac machine. Please check out the <a href="" onclick="display('platform', 'android')">Android</a> instructions instead.</div>
<div>Unfortunately, Apple only lets you develop for iOS on a Mac. If you want to build an iOS app but you don't have a Mac yet, you can try starting with the <a href="" onclick="display('platform', 'android')">Android</a> instructions instead.</div>
<center><img src="img/react-native-sorry-not-supported.png" width="150"></img></center>
@@ -58,74 +66,57 @@ block { display: none; }
<block class="mac ios" />
## Installing React Native
## Dependencies for Mac + iOS
There's a few things you need to install first. You will need Node.js, the React Native command line tools, Watchman, and Xcode.
You will need Xcode, node.js, the React Native command line tools, and Watchman.
<block class="mac android" />
## Installing React Native
## Dependencies for Mac + Android
There's a few things you need to install first. You will need Node.js, the React Native command line tools, Watchman, and Android Studio.
You will need Android Studio, node.js, the React Native command line tools, and Watchman.
<block class="mac ios android" />
#### Node.js
We recommend installing Node.js via [Homebrew](http://brew.sh/), a popular package manager for OS X:
We recommend installing node and watchman via [Homebrew](http://brew.sh/).
```
brew install node
brew install watchman
```
#### React Native command line tools
Use Node's package manager to install the React Native command line tools. These will allow you to easily create your first React Native project.
Node comes with npm, which lets you install the React Native command line interface.
```
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`.
#### 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
```
If you get a permission error, try with sudo: `sudo npm install -g react-native-cli`.
<block class="mac ios" />
#### Xcode
You can install Xcode via the [Mac App Store](https://itunes.apple.com/us/app/xcode/id497799835?mt=12), or download it directly from the [Apple Developer portal](https://developer.apple.com/xcode/downloads/).
The easiest way to install Xcode is via the [Mac App Store](https://itunes.apple.com/us/app/xcode/id497799835?mt=12).
<block class="mac android" />
#### Android Studio
Download and install [Android Studio](https://developer.android.com/studio/install.html).
#### Gradle Daemon
While optional, enabling [Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) will greatly improve incremental build times for changes in Java code.
If you plan to make changes in Java code, we recommend [Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) which speeds up the build.
<!-- ######### LINUX and WINDOWS for ANDROID ##################### -->
<block class="linux windows android" />
<block class="linux android" />
## Installing React Native
## Dependencies for Linux + Android
There's a few things you need to install first. You will need Node.js, the React Native command line tools, Watchman, and Android Studio.
<block class="windows android" />
## Dependencies for Windows + Android
<block class="linux windows android" />
#### Node.js
You will need node.js, the React Native command line tools, Watchman, and Android Studio.
<block class="linux android" />
@@ -133,51 +124,33 @@ Follow the [installation instructions for your Linux distribution](https://nodej
<block class='windows android' />
We recommend installing Node.js via [Chocolatey](https://chocolatey.org), a popular package manager for Windows. Open a Command Prompt as Administrator, then run the following command:
We recommend installing node.js and Python2 via [Chocolatey](https://chocolatey.org), a popular package manager for Windows. Open a Command Prompt as Administrator, then run:
```
choco install nodejs.install
```
##### Python
The React Native command line tools require Python2. Install it using Chocolatey:
```
choco install python2
```
<block class="windows linux android" />
#### React Native command line tools
Use Node's package manager to install the React Native command line tools. These will allow you to easily create your first React Native project.
Node comes with npm, which lets you install the React Native command line interface.
```
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`.
<block class="windows linux android" />
#### Android Studio
Download and install [Android Studio](https://developer.android.com/studio/install.html).
<block class="linux android" />
#### Watchman
[Watchman](https://facebook.github.io/watchman) is a tool by Facebook for watching changes in the filesystem. It is recommended you install
it for better performance. You can follow the [Watchman installation guide](https://facebook.github.io/watchman/docs/install.html#installing-from-source) to compile and install from source.
[Watchman](https://facebook.github.io/watchman) is a tool by Facebook for watching changes in the filesystem. Installing it should
improve performance, but you can also try not installing it, if the installation process is too annoying. You can follow the [Watchman installation guide](https://facebook.github.io/watchman/docs/install.html#installing-from-source) to compile and install from source.
<block class="windows linux android" />
#### Gradle Daemon
While optional, enabling [Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) will greatly improve incremental build times for changes in Java code.
If you plan to make changes in Java code, we recommend [Gradle Daemon](https://docs.gradle.org/2.9/userguide/gradle_daemon.html) which speeds up the build.
<block class="mac ios android" />
@@ -193,13 +166,7 @@ cd AwesomeProject
react-native run-ios
```
If everything is set up correctly, you should see your new app running in the iOS Simulator shortly.
> 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.
You should see your new app running in the iOS Simulator shortly. `react-native run-ios` is just one way to run your app - you can also run it directly from within Xcode or Nuclide.
<block class="mac android" />
@@ -211,12 +178,7 @@ cd AwesomeProject
react-native run-android
```
If everything is set up correctly, you should see your new app running in your Android emulator shortly.
> 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).
If everything is set up correctly, you should see your new app running in your Android emulator shortly. `react-native run-android` is just one way to run your app - you can also run it directly from within Android Studio or Nuclide.
<block class="mac ios android" />
@@ -274,33 +236,20 @@ Now that you have successfully run the app, let's modify it.
### That's it!
Congratulations! You've successfully run and modified your first React Native app.
Congratulations! You've successfully run and modified a React Native app.
<center><img src="img/react-native-congratulations.png" width="150"></img></center>
<block class="mac ios android" />
<block class="mac windows linux ios android" />
## Common Followups
## Now What?
<block class="mac ios" />
- If you want to add this new React Native code to an existing application, check out the [Integration guide](docs/integration-with-existing-apps.html).
- 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 can't get this to work, see the [Troubleshooting](docs/troubleshooting.html#content) page.
<block class="mac android" />
- If you want to run on a physical device, see the [Running on Android Device page](docs/running-on-device-android.html#content).
<block class="mac ios android" />
- If you run into any issues getting started, see the [Troubleshooting](docs/troubleshooting.html#content) and [Debugging](docs/debugging.html#content) pages.
<block class="windows linux android" />
## 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](docs/troubleshooting.html#content) and [Debugging](docs/debugging.html#content) pages.
- If you're curious to learn more about React Native, continue on
to the [Tutorial](docs/tutorial.html).
<script>
// Convert <div>...<span><block /></span>...</div>
@@ -326,7 +275,6 @@ function display(type, value) {
var container = document.getElementsByTagName('block')[0].parentNode;
container.className = 'display-' + type + '-' + value + ' ' +
container.className.replace(RegExp('display-' + type + '-[a-z]+ ?'), '');
event && event.preventDefault();
}
// If we are coming to the page with a hash in it (i.e. from a search, for example), try to get
+49
View File
@@ -0,0 +1,49 @@
---
id: handling-text-input
title: Handling Text Input
layout: docs
category: The Basics
permalink: docs/handling-text-input.html
next: using-a-scrollview
---
[`TextInput`](/react-native/docs/textinput.html#content) is a basic component that allows the user to enter text. It has an `onChangeText` prop that takes
a function to be called every time the text changed, and an `onSubmitEditing` prop that takes a function to be called when the text is submitted.
For example, let's say that as the user types, you're translating their words into a different language. In this new language, every single word is written the same way: 🍕. So the sentence "Hello there Bob" would be translated
as "🍕🍕🍕".
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Text, TextInput, View } from 'react-native';
class PizzaTranslator extends Component {
constructor(props) {
super(props);
this.state = {text: ''};
}
render() {
return (
<View style={{padding: 10}}>
<TextInput
style={{height: 40}}
placeholder="Type here to translate!"
onChangeText={(text) => this.setState({text})}
/>
<Text style={{padding: 10, fontSize: 42}}>
{this.state.text.split(' ').map((word) => word && '🍕').join(' ')}
</Text>
</View>
);
}
}
AppRegistry.registerComponent('PizzaTranslator', () => PizzaTranslator);
```
In this example, we store `text` in the state, because it changes over time.
There are a lot more things you might want to do with a text input. For example, you could validate the text inside while the user types. For more detailed examples, see the [React docs on controlled components](https://facebook.github.io/react/docs/forms.html), or the [reference docs for TextInput](/react-native/docs/textinput.html).
Text input is probably the simplest example of a component whose state naturally changes over time. Next, let's look at another type of component like this is one that controls layout, and [learn about the ScrollView](/react-native/docs/using-a-scrollview.html).
+66
View File
@@ -0,0 +1,66 @@
---
id: handling-touches
title: Handling Touches
layout: docs
category: Guides
permalink: docs/handling-touches.html
next: animations
---
Users interact with mobile apps mainly through touch. They can use a combination of gestures, such as tapping on a button, scrolling a list, or zooming on a map.
React Native provides components to handle common gestures, such as taps and swipes, as well as a comprehensive [gesture responder system](/docs/gesturerespondersystem.html) to allow for more advanced gesture recognition.
## Tappable Components
You can use "Touchable" components when you want to capture a tapping gesture. They take a function through the `onPress` props which will be called when the touch begins and ends within the bounds of the component.
Example:
```javascript
class MyButton extends Component {
_onPressButton() {
console.log("You tapped the button!");
}
render() {
return (
<TouchableHighlight onPress={this._onPressButton}>
<Text>Button</Text>
</TouchableHighlight>
);
}
}
```
Tappable components should provide feedback that show the user what is handling their touch, and what will happen when they lift their finger. The user should also be able to cancel a tap by dragging their finger away.
Which component you use will depend on what kind of feedback you want to provide:
- Generally, you can use [**TouchableHighlight**](/docs/touchablehighlight.html) anywhere you would use a button or link on web. The view's background will be darkened when the user presses down on the button.
- You may consider using [**TouchableNativeFeedback**](/docs/touchablenativefeedback.html) on Android to display ink surface reaction ripples that respond to the user's touch.
- [**TouchableOpacity**](/docs/touchableopacity.html) can be used to provide feedback by reducing the opacity of the button, allowing the background to be seen through while the user is pressing down.
- If you need to handle a tap gesture but you don't want any feedback to be displayed, use [**TouchableWithoutFeedback**](/docs/touchablewithoutfeedback.html).
### Long presses
In some cases, you may want to detect when a user presses and holds a view for a set amount of time. These long presses can be handled by passing a function to the `onLongPress` props of any of the touchable components listed above.
## Scrolling lists and swiping views
A common pattern to many mobile apps is the scrollable list of items. Users interact with these using panning or swiping gestures. The [ScrollView](/docs/basics-component-scrollview.html) component displays a list of items that can be scrolled using these gestures.
ScrollViews can scroll vertically or horizontally, and can be configured to allow paging through views using swiping gestures by using the `pagingEnabled` props. Swiping horizontally between views can also be implemented on Android using the [ViewPagerAndroid](/docs/viewpagerandroid.html) component.
A [ListView](/docs/basics-component-listview.html) is a special kind of ScrollView that is best suited for displaying long vertical lists of items. It can also display section headers and footers, similar to `UITableView`s on iOS.
### Pinch-to-zoom
A ScrollView with a single item can be used to allow the user to zoom content. Set up the `maximumZoomScale` and `minimumZoomScale` props and your user will be able to use pinch and expand gestures to zoom in and out.
## Handling additional gestures
If you want to allow a user to drag a view around the screen, or you want to implement your own custom pan/drag gesture, take a look at the [PanResponder](/docs/panresponder.html) API or the [gesture responder system docs](/docs/gesturerespondersystem.html).
+65
View File
@@ -0,0 +1,65 @@
---
id: height-and-width
title: Height and Width
layout: docs
category: The Basics
permalink: docs/height-and-width.html
next: flexbox
---
A component's height and width determine its size on the screen.
#### Fixed Dimensions
The simplest way to set the dimensions of a component is by adding a fixed `width` and `height` to style. All dimensions in React Native are unitless, and represent density-independent pixels.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class FixedDimensionsBasics extends Component {
render() {
return (
<View>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 100, height: 100, backgroundColor: 'skyblue'}} />
<View style={{width: 150, height: 150, backgroundColor: 'steelblue'}} />
</View>
);
}
};
AppRegistry.registerComponent('AwesomeProject', () => FixedDimensionsBasics);
```
Setting dimensions this way is common for components that should always render at exactly the same size, regardless of screen dimensions.
#### Flex Dimensions
Use `flex` in a component's style to have the component expand and shrink dynamically based on available space. Normally you will use `flex: 1`, which tells a component to fill all available space, shared evenly amongst each other component with the same parent. The larger the `flex` given, the higher the ratio of space a component will take compared to its siblings.
> A component can only expand to fill available space if its parent has dimensions greater than 0. If a parent does not have either a fixed `width` and `height` or `flex`, the parent will have dimensions of 0 and the `flex` children will not be visible.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class FlexDimensionsBasics extends Component {
render() {
return (
// Try removing the `flex: 1` on the parent View.
// The parent will not have dimensions, so the children can't expand.
// What if you add `height: 300` instead of `flex: 1`?
<View style={{flex: 1}}>
<View style={{flex: 1, backgroundColor: 'powderblue'}} />
<View style={{flex: 2, backgroundColor: 'skyblue'}} />
<View style={{flex: 3, backgroundColor: 'steelblue'}} />
</View>
);
}
};
AppRegistry.registerComponent('AwesomeProject', () => FlexDimensionsBasics);
```
After you can control a component's size, the next step is to [learn how to lay it out on the screen](/react-native/docs/flexbox.html).
+1 -1
View File
@@ -4,7 +4,7 @@ title: Images
layout: docs
category: Guides
permalink: docs/images.html
next: gesture-responder-system
next: handling-touches
---
## Static Image Resources
@@ -1,10 +1,10 @@
---
id: tutorial-integration-with-existing-apps
id: integration-with-existing-apps
title: Integration With Existing Apps
layout: docs
category: Tutorials
permalink: docs/tutorial-integration-with-existing-apps.html
next: sample-application-movies
category: Guides
permalink: docs/integration-with-existing-apps.html
next: colors
---
<div class="integration-toggler">
+1 -1
View File
@@ -4,7 +4,7 @@ title: JavaScript Environment
layout: docs
category: Guides
permalink: docs/javascript-environment.html
next: navigator-comparison
next: navigation
---
## JavaScript Runtime
-90
View File
@@ -1,90 +0,0 @@
---
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 `<top frame>`.
### 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:
- `<ViewPagerAndroid>` and `<ScrollView pagingEnabled={true}>` on iOS do a similar thing. We might want to unify them to `<ViewPager>`.
- `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:
```
<View collapsable={false}>
...
</View>
```
### 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.
### Moving folder after iOS build
Moving a React Native project after it has been compiled in iOS can sometimes cause errors with pre-compiled headers e.g. `mv MyAwesomeProject/ newDir/MyAwesomeProject`. This results in a message resembling: `error: PCH was compiled with module cache path ...`. If you were compiling using Xcode you can [hold option when you clean the build](http://stackoverflow.com/a/15463219/3110982). If you're using `react-native run-ios` you can manually clean the header cache by deleting the contents of your ModuleCache folder. e.g. `rm -rf ios/build/ModuleCache/*`
### 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.
### iOS App Transport Security and loading HTTP resources
As of iOS 9, new Xcode projects enable App Transport Security by default, which rejects all HTTP requests that are not sent over HTTPS. This can result in HTTP traffic being blocked (including the developer React Native server) with the following console errors:
```
App Transport Security has blocked a cleartext HTTP (http://) resource load since it is insecure. Temporary exceptions can be configured via your app's Info.plist file.
```
```
NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
```
See our guide for [running on an iOS device](RunningOnDeviceIOS.md) and working around the ATS issues, or [several](http://useyourloaf.com/blog/app-transport-security/) [community](https://www.hackingwithswift.com/example-code/system/how-to-handle-the-https-requirements-in-ios-9-with-app-transport-security) [posts](https://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/) on handling common cases like [whitelisting specific domains](http://stackoverflow.com/a/30732693) for non-HTTPS traffic.
+106
View File
@@ -0,0 +1,106 @@
---
id: flexbox
title: Layout with Flexbox
layout: docs
category: The Basics
permalink: docs/flexbox.html
next: handling-text-input
---
A component can specify the layout of its children using the flexbox algorithm. Flexbox is designed to provide a consistent layout on different screen sizes.
You will normally use a combination of `flexDirection`, `alignItems`, and `justifyContent` to achieve the right layout.
> Flexbox works the same way in React Native as it does in CSS on the web, with a few exceptions. The defaults are different, with `flexDirection` defaulting to `column` instead of `row`, and `alignItems` defaulting to `stretch` instead of `flex-start`, and the `flex` parameter only supports a single number.
#### Flex Direction
Adding `flexDirection` to a component's `style` determines the **primary axis** of its layout. Should the children be organized horizontally (`row`) or vertically (`column`)? The default is `column`.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class FlexDirectionBasics extends Component {
render() {
return (
// Try setting `flexDirection` to `column`.
<View style={{flex: 1, flexDirection: 'row'}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
AppRegistry.registerComponent('AwesomeProject', () => FlexDirectionBasics);
```
#### Justify Content
Adding `justifyContent` to a component's style determines the **distribution** of children along the **primary axis**. Should children be distributed at the start, the center, the end, or spaced evenly? Available options are `flex-start`, `center`, `flex-end`, `space-around`, and `space-between`.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class JustifyContentBasics extends Component {
render() {
return (
// Try setting `justifyContent` to `center`.
// Try setting `flexDirection` to `row`.
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'space-between',
}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
AppRegistry.registerComponent('AwesomeProject', () => JustifyContentBasics);
```
#### Align Items
Adding `alignItems` to a component's style determines the **alignment** of children along the **secondary axis** (if the primary axis is `row`, then the secondary is `column`, and vice versa). Should children be aligned at the start, the center, the end, or stretched to fill? Available options are `flex-start`, `center`, `flex-end`, and `stretch`.
> For `stretch` to have an effect, children must not have a fixed dimension along the secondary axis. In the following example, setting `alignItems: stretch` does nothing until the `width: 50` is removed from the children.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, View } from 'react-native';
class AlignItemsBasics {
render() {
return (
// Try setting `alignItems` to 'flex-start'
// Try setting `justifyContent` to `flex-end`.
// Try setting `flexDirection` to `row`.
<View style={{
flex: 1,
flexDirection: 'column',
justifyContent: 'center',
alignItems: 'center',
}}>
<View style={{width: 50, height: 50, backgroundColor: 'powderblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'skyblue'}} />
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
</View>
);
}
};
AppRegistry.registerComponent('AwesomeProject', () => AlignItemsBasics);
```
#### Going Deeper
We've covered the basics, but there are many other styles you may need for layouts. The full list of props that control layout is documented [here](./docs/layout-props.html).
We're getting close to being able to build a real application. One thing we are still missing is a way to take user input, so let's move on to [learn how to handle text input with the TextInput component](/react-native/docs/handling-text-input.html).
+48
View File
@@ -0,0 +1,48 @@
---
id: more-resources
title: More Resources
layout: docs
category: The Basics
permalink: docs/more-resources.html
next: integration-with-existing-apps
---
If you just read through this website, you should be able to build a pretty cool React Native app. But React Native isn't just a product made by one company - it's a community of thousands of developers. So if you're interested in React Native, here's some related stuff you might want to check out.
## Popular Libraries
If you're using React Native, you probably already know about [React](https://facebook.github.io/react/). So I feel a bit silly mentioning this. But if you haven't, check out React - it's the best way to build a modern website.
One common question is how to handle the "state" of your React Native application. The most popular library for this is [Redux](http://redux.js.org/). Don't be afraid of how often Redux uses the word "reducer" - it's a pretty simple library, and there's also a nice [series of videos](https://egghead.io/courses/getting-started-with-redux) explaining it.
If you're looking for a library that does a specific thing, check out [Awesome React Native](https://github.com/jondot/awesome-react-native), a curated list of components that also has demos, articles, and other stuff.
## Example Apps
There are a lot of example apps at the [React Native Playground](https://rnplay.org/apps/picks). You can see the code running on a real device, which is a neat feature.
The folks who built the app for Facebook's F8 conference in 2016 also [open-sourced the code](https://github.com/fbsamples/f8app) and wrote up a [detailed series of tutorials](http://makeitopen.com/tutorials/building-the-f8-app/planning/). This is useful if you want a more in-depth example that's more realistic than most sample apps out there.
## Development Tools
[Nuclide](https://nuclide.io/) is the IDE that Facebook uses internally for React Native development. The killer feature of Nuclide is its debugging ability. It also has great inline Flow support.
[Ignite](https://github.com/infinitered/ignite) is a starter kit that uses Redux and a few different common UI libraries. It has a CLI to generate apps, components, and containers. If you like all of the individual tech choices, Ignite could be perfect for you.
[CodePush](https://microsoft.github.io/code-push/) is a service from Microsoft that makes it easy to deploy live updates to your React Native app. If you don't like going through the app store process to deploy little tweaks, and you also don't like setting up your own backend, give CodePush a try.
[Exponent](http://docs.getexponent.com/versions/v6.0.0/index.html) is a development environment plus application that focuses on letting you build React Native apps in the Exponent development environment, without ever touching Xcode or Android Studio. If you wish React Native was even more JavaScripty and webby, check out Exponent.
[Deco](https://www.decosoftware.com/) is an all-in-one development environment specifically designed for React Native. It can automatically set up a new project, search for open source components, and insert them. You can also tweak your app graphically in real time. Check it out if you use macOS.
## Where React Native People Hang Out
The [React Native Community](https://www.facebook.com/groups/react.native.community) Facebook group has thousands of developers, and it's pretty active. Come there to show off your project, or ask how other people solved similar problems.
[Reactiflux](https://discord.gg/0ZcbPKXt5bZjGY5n) is a Discord chat where a lot of React-related discussion happens, including React Native. Discord is just like Slack except it works better for open source projects with a zillion contributors. Check out the #react-native channel.
The [React Twitter account](https://twitter.com/reactjs) covers both React and React Native. Following that account is a pretty good way to find out what's happening in the world of React.
There are a lot of [React Native Meetups](http://www.meetup.com/topics/react-native/) that happen around the world. Often there is React Native content in React meetups as well.
Sometimes we have React conferences. We posted the [videos from React.js Conf 2016](https://www.youtube.com/playlist?list=PLb0IAmt7-GS0M8Q95RIc2lOM6nc77q1IY), and we'll probably have more conferences in the future, too. Stay tuned.
+2 -1
View File
@@ -148,7 +148,8 @@ The event name `topChange` maps to the `onChange` callback prop in JavaScript (m
// MyCustomView.js
class MyCustomView extends React.Component {
constructor() {
constructor(props) {
super(props);
this._onChange = this._onChange.bind(this);
}
_onChange(event: Event) {
+1 -1
View File
@@ -69,7 +69,7 @@ The CalendarManager module is instantiated on the Objective-C side using a [Cale
- 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
- object (`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.
+344
View File
@@ -0,0 +1,344 @@
---
id: navigation
title: Navigation
layout: docs
category: Guides
permalink: docs/navigation.html
next: performance
---
This guide covers the various navigation components available in React Native. If you are just getting started with navigation, you will probably want to use `Navigator`. If you are only targeting iOS and would like to stick to the native look and feel, check out `NavigatorIOS`. If you are looking for greater control over your navigation stack, you can't go wrong with `NavigationExperimental`.
## Navigator
`Navigator` provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize. This is the same component you used to build your first navigation stack in the [navigators tutorial](docs/navigators.html).
![](img/NavigationStack-Navigator.gif)
`Navigator` can easily be adapted to render different components based on the current route in its `renderScene` function. It will transition new scenes onto the screen by sliding in from the right by default, but you can control this behavior by using the `configureScene` function. You can also configure a navigation bar through the `navigationBar` prop.
Check out the [Navigator API reference](docs/navigator.html) for specific examples that cover each of these scenarios.
## NavigatorIOS
If you are targeting iOS only, you may also want to consider using [NavigatorIOS](docs/navigatorios.html). It looks and feels just like [`UINavigationController`](https://developer.apple.com/library/ios/documentation/UIKit/Reference/UINavigationController_Class/), because it is actually built on top of it.
![](img/NavigationStack-NavigatorIOS.gif)
```javascript
<NavigatorIOS
initialRoute={{
component: MyScene,
title: 'My Initial Scene',
passProps: { myProp: 'foo' },
}}
/>
```
Just like `Navigator`, `NavigatorIOS` uses routes to represent scenes, with some important differences. The actual component that will be rendered can be specified using the `component` key in the route, and any props that should be passed to this component can be specified in `passProps`. A "navigator" object is automatically passed as a prop to the component, allowing you to call `push` and `pop` as needed.
As `NavigatorIOS` leverages native UIKit navigation, it will automatically render a navigation bar with a back button and title.
```javascript
import React, { Component, PropTypes } from 'react';
import { NavigatorIOS, Text, TouchableHighlight, View } from 'react-native';
export default class NavigatorIOSApp extends Component {
render() {
return (
<NavigatorIOS
initialRoute={{
component: MyScene,
title: 'My Initial Scene',
}}
style={{flex: 1}}
/>
)
}
}
class MyScene extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
navigator: PropTypes.object.isRequired,
}
constructor(props, context) {
super(props, context);
this._onForward = this._onForward.bind(this);
}
_onForward() {
this.props.navigator.push({
title: 'Scene ' + nextIndex,
});
}
render() {
return (
<View>
<Text>Current Scene: { this.props.title }</Text>
<TouchableHighlight onPress={this._onForward}>
<Text>Tap me to load the next scene</Text>
</TouchableHighlight>
</View>
)
}
}
```
Check out the [`NavigatorIOS` reference docs](docs/navigatorios.html) to learn more about this component.
> You may also want to check out [react-native-navigation](https://github.com/wix/react-native-navigation), a component that aims to provide native navigation on both iOS and Android.
## NavigationExperimental
`Navigator` and `NavigatorIOS` are both stateful components. If your app has multiple of these, it can become tricky to coordinate navigation transitions between them. NavigationExperimental provides a different approach to navigation, allowing any view to act as a navigation view and using reducers to manipulate state at a top-level object. It is bleeding edge as the name implies, but you might want to check it out if you are craving greater control over your app's navigation.
```javascript
<NavigationCardStack
onNavigateBack={onPopRouteFunc}
navigationState={myNavigationState}
renderScene={renderSceneFun}
/>
```
You can import `NavigationExperimental` like any other component in React Native. Once you have that, you can deconstruct any additional components from `NavigationExperimental` that you may find useful. Since I am feeling like building navigation stacks today, I'll go ahead and pick out `NavigationCardStack` and `NavigationStateUtils`.
```javascript
import React, { Component } from 'react';
import { NavigationExperimental } from 'react-native';
const {
CardStack: NavigationCardStack,
StateUtils: NavigationStateUtils,
} = NavigationExperimental;
```
As I said earlier, `NavigationExperimental` takes a different approach than `Navigator` and `NavigatorIOS`. Using it to build a navigation stack requires a few more steps than the stateful components, but the payoff is worth it.
### Step 1. Define Initial State and Top Level Component
Create a new component for your application. This will be the top-level object, so we will define the initial state here. The navigation state will be defined in the `navigationState` key, where we define our initial route:
```javascript
class BleedingEdgeApplication extends Component {
constructor(props, context) {
super(props, context);
this.state = {
// This defines the initial navigation state.
navigationState: {
index: 0, // Starts with first route focused.
routes: [{key: 'My Initial Scene'}], // Starts with only one route.
},
};
// We'll define this function later - hang on
this._onNavigationChange = this._onNavigationChange.bind(this);
}
_onNavigationChange(type) {
// It's literally the next step. We'll get to it!
}
render() {
return (
<Text>This is a placeholder. We will come back to this and render our navigation here later.</Text>
);
}
}
```
Alright, now we have a simple stateful component that doesn't do much at all. We can change that. Our initial state contains one route, and the current index. That looks suspiciously just like our initial route definition in Navigator. Do you remember which actions its navigator object provided?
Push and pop, of course. That seems pretty straightforward to implement. I promised you earlier we would be using reducers to manage state at the top-level object. Sit tight.
### Step 2. Reducing the Navigation State
NavigationExperimental comes built-in with a some useful reducers, and they are all available as part of NavigationStateUtils. The two we will be using right now are called -- yep -- push and pop. They take a navigationState object, and return a new navigationState object.
We can use them to write our `_onNavigationChange` function which, given a "push" or "pop" action, will reduce the state accordingly.
```javascript
_onNavigationChange(type) {
// Extract the navigationState from the current state:
let {navigationState} = this.state;
switch (type) {
case 'push':
// Push a new route, which in our case is an object with a key value.
// I am fond of cryptic keys (but seriously, keys should be unique)
const route = {key: 'Route-' + Date.now()};
// Use the push reducer provided by NavigationStateUtils
navigationState = NavigationStateUtils.push(navigationState, route);
break;
case 'pop':
// Pop the current route using the pop reducer.
navigationState = NavigationStateUtils.pop(navigationState);
break;
}
// NavigationStateUtils gives you back the same `navigationState` if nothing
// has changed. We will only update state if it has changed.
if (this.state.navigationState !== navigationState) {
// Always use setState() when setting a new state!
this.setState({navigationState});
// If you are new to ES6, the above is equivalent to:
// this.setState({navigationState: navigationState});
}
}
```
Cool. I'm getting the hang of this. This is the heart of NavigationExperimental. We are only handling two actions here, but a more complex application could also take into account a "back" action (e.g. Android back button), as well as handle the transition between several tabs in a tabbed application.
I am still missing the initial scene that will be rendered (as well as the actual navigator that will wrap it, but let's not get ahead of ourselves).
### Step 3. Define Scenes
First I want to define a Row component out of convenience. It displays some text and can call some function when pressed.
```javascript
class TappableRow extends Component {
render() {
return (
<TouchableHighlight
style={styles.row}
underlayColor="#D0D0D0"
onPress={this.props.onPress}>
<Text style={styles.buttonText}>
{this.props.text}
</Text>
</TouchableHighlight>
);
}
}
```
Now I will define my actual scene. It uses a scroll view to display a vertical list of items. The first row displays the current route's key, and two more rows will call our theoretical navigator's push and pop functions.
```javascript
class MyVeryComplexScene extends Component {
render() {
return (
<ScrollView style={styles.scrollView}>
<Text style={styles.row}>
Route: {this.props.route.key}
</Text>
<TappableRow
text="Tap me to load the next scene"
onPress={this.props.onPushRoute}
/>
<TappableRow
text="Tap me to go back"
onPress={this.props.onPopRoute}
/>
</ScrollView>
);
}
}
```
### Step 4. Create a Navigation Stack
Now that I have defined the state and a function to manage it, I think I can go ahead and create a proper navigator component now. While I'm at it, I'll render my scene after configuring it with the current route's props.
```javascript
class MyVerySimpleNavigator extends Component {
// This sets up the methods (e.g. Pop, Push) for navigation.
constructor(props, context) {
super(props, context);
this._onPushRoute = this.props.onNavigationChange.bind(null, 'push');
this._onPopRoute = this.props.onNavigationChange.bind(null, 'pop');
this._renderScene = this._renderScene.bind(this);
}
// Now we finally get to use the `NavigationCardStack` to render the scenes.
render() {
return (
<NavigationCardStack
onNavigateBack={this._onPopRoute}
navigationState={this.props.navigationState}
renderScene={this._renderScene}
style={styles.navigator}
/>
);
}
// Render a scene for route.
// The detailed spec of `sceneProps` is defined at `NavigationTypeDefinition`
// as type `NavigationSceneRendererProps`.
// Here you could choose to render a different component for each route, but
// we'll keep it simple.
_renderScene(sceneProps) {
return (
<MyVeryComplexScene
route={sceneProps.scene.route}
onPushRoute={this._onPushRoute}
onPopRoute={this._onPopRoute}
onExit={this.props.onExit}
/>
);
}
}
```
That's it -- so close to the finish line I can smell it. Let's plug our new navigator into our top-level component:
```javascript
class BleedingEdgeApplication extends Component {
// constructor and other methods omitted for clarity
render() {
return (
<MyVerySimpleNavigator
navigationState={this.state.navigationState}
onNavigationChange={this._onNavigationChange}
onExit={this._exit}
/>
);
}
}
```
We're done! Bask in the glory of NavigationExperimental.
#### Hey -- I think you are missing something.
(Oh yes, sorry about that -- here's our missing imports and styles.)
```javascript
import { NavigationExperimental, PixelRatio, ScrollView, StyleSheet, Text, TouchableHighlight } from 'react-native';
const styles = StyleSheet.create({
navigator: {
flex: 1,
},
scrollView: {
marginTop: 64
},
row: {
padding: 15,
backgroundColor: 'white',
borderBottomWidth: 1 / PixelRatio.get(),
borderBottomColor: '#CDCDCD',
},
rowText: {
fontSize: 17,
},
buttonText: {
fontSize: 17,
fontWeight: '500',
},
});
```
### Homework
You are now an expert navigator. Take a look at [NavigationExperimental in UIExplorer](https://github.com/facebook/react-native/tree/master/Examples/UIExplorer/NavigationExperimental) to learn how to implement other types of navigation hierarchies, such as a tabbed application with multiple navigation stacks.
-49
View File
@@ -1,49 +0,0 @@
---
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`.
-155
View File
@@ -1,155 +0,0 @@
---
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) and [OkHttp](http://square.github.io/okhttp/). 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.
+130
View File
@@ -0,0 +1,130 @@
---
id: network
title: Networking
layout: docs
category: The Basics
permalink: docs/network.html
next: using-navigators
---
Many mobile apps need to load resources from a remote URL. You may want to make a POST request to a REST API, or you may simply need to fetch a chunk of static content from another server.
## Using Fetch
React Native provides the [Fetch API](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API) for your networking needs. Fetch will seem familiar if you have used `XMLHttpRequest` or other networking APIs before. You may refer to MDN's guide on [Using Fetch](https://developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch) for additional information.
#### Making requests
In order to fetch content from an arbitrary URL, just pass the URL to fetch:
```js
fetch('https://mywebsite.com/mydata.json')
```
Fetch also takes an optional second argument that allows you to customize the HTTP request. You may want to specify additional headers, or make a POST request:
```js
fetch('https://mywebsite.com/endpoint/', {
method: 'POST',
headers: {
'Accept': 'application/json',
'Content-Type': 'application/json',
},
body: JSON.stringify({
firstParam: 'yourValue',
secondParam: 'yourOtherValue',
})
})
```
Take a look at the [Fetch Request docs](https://developer.mozilla.org/en-US/docs/Web/API/Request) for a full list of properties.
#### Handling the response
The above examples show how you can make a request. In many cases, you will want to do something with the response.
Networking is an inherently asynchronous operation. Fetch methods will return a [Promise](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) that make it straightforward to write code that works in an asynchronous manner:
```js
getMoviesFromApiAsync() {
return fetch('http://facebook.github.io/react-native/movies.json')
.then((response) => response.json())
.then((responseJson) => {
return responseJson.movies;
})
.catch((error) => {
console.error(error);
});
}
```
You can also use ES7's `async`/`await` syntax in React Native app:
```js
async getMoviesFromApi() {
try {
let response = await fetch('http://facebook.github.io/react-native/movies.json');
let responseJson = await response.json();
return responseJson.movies;
} catch(error) {
console.error(error);
}
}
```
Don't forget to catch any errors that may be thrown by `fetch`, otherwise they will be dropped silently.
### Using Other Networking Libraries
The [XMLHttpRequest API](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest) is built in to React Native. This means that you can use third party libraries such as [frisbee](https://github.com/niftylettuce/frisbee) or [axios](https://github.com/mzabriskie/axios) that depend on it, or you can use the XMLHttpRequest API directly if you prefer.
```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/');
request.send();
```
> The security model for XMLHttpRequest is different than on web as there is no concept of [CORS](http://en.wikipedia.org/wiki/Cross-origin_resource_sharing) in native apps.
## WebSocket Support
React Native also supports [WebSockets](https://developer.mozilla.org/en-US/docs/Web/API/WebSocket), a protocol which provides 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'); // send a message
};
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);
};
```
Your app can now display all sorts of data and you may soon need to organize this content into several screens. To manage the transition between these screens, you will need to learn about [navigators](/react-native/docs/using-navigators.html).
-8
View File
@@ -1,8 +0,0 @@
---
id: newsletter
title: Newsletter
layout: docs
category: Community Resources
permalink: http://reactnative.cc/
next: style
---
+4
View File
@@ -81,6 +81,10 @@ but their receipt is not necessary for the scroll to occur).
### Common sources of performance problems
#### Console.log statements
When running a bundled app, these statements can cause a big bottleneck in the JavaScript thread. This includes calls from debugging libraries such as [redux-logger](https://github.com/evgenyrodionov/redux-logger), so make sure to remove them before bundling.
#### Development mode (dev=true)
JavaScript thread performance suffers greatly when running in dev mode.
+6 -7
View File
@@ -4,23 +4,21 @@ title: Platform Specific Code
layout: docs
category: Guides
permalink: docs/platform-specific-code.html
next: native-modules-ios
next: gesture-responder-system
---
When building a cross-platform app, you'll want to re-use as much code as possible. Scenarios may arise where it makes sense for the code to be different, for example you may want to implement separate visual components for iOS and Android.
React Native provides two ways to easily organize your code and separate it by platform:
* Using the `Platform` module.
* Using platform-specific file extensions.
* Using the [`Platform` module](#platform-module).
* Using [platform-specific file extensions](#platform-specific-extensions).
```javascript
import BigButton from './components/BigButton';
```
Certain components may have properties that work on one platform only. All of these props are annotated with `@platform` and have a small badge next to them on the website.
React Native will import the correct component for the running platform.
## Platform module
React Native provides a module that detects the platform in which the app is running. You can use the detection logic to implement platform-specific code. Use this option when only small parts of a component are platform-specific.
```javascript
@@ -79,6 +77,7 @@ if(Platform.Version === 21){
```
## Platform-specific extensions
When your platform-specific code is more complex, you should consider splitting the code out into separate files. React Native will detect when a file has a `.ios.` or `.android.` extension and load the relevant platform file when required from other components.
For example, say you have the following files in your project:
+72
View File
@@ -0,0 +1,72 @@
---
id: props
title: Props
layout: docs
category: The Basics
permalink: docs/props.html
next: state
---
Most components can be customized when they are created, with different parameters. These creation parameters are called `props`.
For example, one basic React Native component is the `Image`. When you
create an image, you can use a prop named `source` to control what image it shows.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Image } from 'react-native';
class Bananas extends Component {
render() {
let pic = {
uri: 'https://upload.wikimedia.org/wikipedia/commons/d/de/Bananavarieties.jpg'
};
return (
<Image source={pic} style={{width: 193, height: 110}}/>
);
}
}
AppRegistry.registerComponent('Bananas', () => Bananas);
```
Notice that `{pic}` is surrounded by braces, to embed the variable `pic` into JSX. You can put any JavaScript expression inside braces in JSX.
Your own components can also use `props`. This lets you make a single component
that is used in many different places in your app, with slightly different
properties in each place. Just refer to `this.props` in your `render` function. Here's an example:
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
class Greeting extends Component {
render() {
return (
<Text>Hello {this.props.name}!</Text>
);
}
}
class LotsOfGreetings extends Component {
render() {
return (
<View style={{alignItems: 'center'}}>
<Greeting name='Rexxar' />
<Greeting name='Jaina' />
<Greeting name='Valeera' />
</View>
);
}
}
AppRegistry.registerComponent('LotsOfGreetings', () => LotsOfGreetings);
```
Using `name` as a prop lets us customize the `Greeting` component, so we can reuse that component for each of our greetings. This example also uses the `Greeting` component in JSX, just like the built-in components. The power to do this is what makes React so cool - if you find yourself wishing that you had a different set of UI primitives to work with, you just invent new ones.
The other new thing going on here is the [`View`](/react-native/docs/view.html) component. A [`View`](/react-native/docs/view.html) is useful
as a container for other components, to help control style and layout.
With `props` and the basic [`Text`](/react-native/docs/text.html), [`Image`](/react-native/docs/image.html), and [`View`](/react-native/docs/view.html) components, you can
build a wide variety of static screens. To learn how to make your app change over time, you need to [learn about State](/react-native/docs/state.html).
+17 -1
View File
@@ -20,7 +20,7 @@ Check that your device has been **successfully connected** by running `adb devic
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.
Now you can use `react-native run-android` to install and launch your app on the device. If you get a "bridge configuration isn't available" error, see the `Using adb reverse` section below.
## Setting up an Android Device
@@ -93,6 +93,22 @@ Have your device connected via USB with debugging enabled (see paragraph above o
1. Run `adb reverse tcp:8081 tcp:8081`
2. You can use `Reload JS` and other development options with no extra configuration
### Running packager on a non-standard port
Launch the packager manually with `react-native start --port [PORT]`
For Android: Use the developer menu by clicking the menu button or shake. Select 'Debug server host & port for device' to set a different port.
<center>
<img src="img/AndroidDeveloperMenu.png" width="162" />
<img src="img/AndroidDevSettings.png" width="150" />
<img src="img/AndroidDevServerDialog.png" width="150" />
</center>
For IOS: Edit the AppDelegate.m and change the line below to match the port number you're running:
```jsCodeLocation = [NSURL URLWithString:@"http://localhost:8081/index.ios.bundle?platform=ios&dev=true"];```
### 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**.
+23 -22
View File
@@ -4,41 +4,42 @@ title: Running On Device
layout: docs
category: Guides (iOS)
permalink: docs/running-on-device-ios.html
next: communication-ios
next: running-on-simulator-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.
Running an iOS app on a device requires an [Apple Developer account](https://developer.apple.com/) and provisioning your iPhone. This guide covers only React Native specific topics.
## Accessing development server from device
## Accessing the 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.
You can iterate quickly on device using the development server. First, ensure that you are on the same Wi-Fi network as your computer.
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. Temporarily disable App Transport Security (ATS) by [adding the `NSAllowsArbitraryLoads` entry to your `Info.plist` file][gpl]. Since ATS does not allow insecure HTTP requests to IP addresses, you must completely disable it to run on a device. This is only a requirement for development on a device, and unless you can't workaround an issue you should leave ATS enabled for production builds. For more information, see [this post on configuring ATS][bats].
4. In Xcode select your phone as build target and press "Build and run"
[gpl]: https://gist.github.com/andrewsardone/91797ff9923b9ac6ea64
[bats]: http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/
In Xcode, select your phone as build target and press "Build and run"
> Hint
>
> Shake the device to open development menu (reload, debug, etc.)
> Shake the device to open the [developer menu](/docs/debugging.html#accessing-the-in-app-developer-menu).
## Using offline bundle
## Building your app for production
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.
You have built a great app using React Native, and you are now itching to release it in the App Store. The process is the same as any other native iOS app, with some additional considerations to take into account.
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 the developer menu
## Disabling in-app developer menu
Building an app for distribution in the App Store requires using the `Release` scheme in Xcode. Apps built for `Release` will automatically disable the in-app developer menu. This will prevent your users from inadvertently accessing the menu in production.
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.
### Using the offline bundle
## Troubleshooting
Set up your app to load your JavaScript, images, and other static assets from its resource bundle rather than the development server. This way you can test the app independently of the development server, and will allow you to distribute the app to beta testers and submit the app to the App Store.
If `curl` command fails make sure the packager is running. Also try adding `--ipv4` flag to the end of it.
1. Open `ios/YourApp/AppDelegate.m`
2. Uncomment the line, `jsCodeLocation = [[NSBundle mainBundle] ...`
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.
### App Transport Security
App Transport Security is a security feature, added in iOS 9, that rejects all HTTP requests that are not sent over HTTPS. This can result in HTTP traffic being blocked, including the developer React Native server.
ATS is disabled by default in projects generated using the React Native CLI in order to make development easier. You should re-enable ATS prior to building your app for production by removing the `NSAllowsArbitraryLoads` entry from your `Info.plist` file in the `ios/` folder.
To learn more about how to configure ATS on your own Xcode projects, see [this post on ATS][cats].
[cats]: http://ste.vn/2015/06/10/configuring-app-transport-security-ios-9-osx-10-11/
+18
View File
@@ -0,0 +1,18 @@
---
id: running-on-simulator-ios
title: Running On Simulator
layout: docs
category: Guides (iOS)
permalink: docs/running-on-simulator-ios.html
next: communication-ios
---
## Starting the simulator
Once you have your React Native project initialized, you can run `react-native run-ios` inside the newly created project directory. If everything is set up correctly, you should see your new app running in the iOS Simulator shortly.
## Specifying a device
You can specify the device the simulator should run with the `--simulator` flag, followed by the device name as a string. The default is `"iPhone 6"`. If you wish to run your app on an iPhone 4s, just run `react-native run-ios --simulator "iPhone 4s"`.
The device names correspond to the list of devices available in Xcode. You can check your available devices by running `xcrun simctl list devices` from the console.
-8
View File
@@ -1,8 +0,0 @@
---
id: sample-application-f8
title: F8 2016 App
layout: docs
category: Sample Applications
permalink: http://makeitopen.com/
next: videos
---
-504
View File
@@ -1,504 +0,0 @@
---
id: sample-application-movies
title: Movie Fetcher
layout: docs
category: Sample Applications
permalink: docs/sample-application-movies.html
next: sample-application-f8
---
## Overview
In this tutorial we'll be building a simple version of a Movies app that fetches 25 movies that are in theaters and displays them in a `ListView`.
## Setup
> This sample application requires the basic setup explained at
> [React Native Getting Started](docs/quick-start/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. Its 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 SampleAppMovies`
This command fetches the React Native source code and dependencies and then creates a new Xcode project in `SampleAppMovies/iOS/SampleAppMovies.xcodeproj` and a gradle project in `SampleAppMovies/android/app`.
### Starting the app on iOS
Open this new project (`SampleAppMovies/ios/SampleAppMovies.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 `SampleAppMovies` 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 `SampleAppMovies`. 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.
## Actual App
Now that we have initialized our React Native project, we can begin creating our Movie application.
### 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 (
<View style={styles.container}>
<Text>{movie.title}</Text>
<Text>{movie.year}</Text>
<Image source={{uri: movie.posters.thumbnail}} />
</View>
);
}
```
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
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
```
Press `⌘+R` / `Reload JS` and the image should now render.
<div class="tutorial-mock">
<img src="img/TutorialMock.png" />
<img src="img/TutorialMock2.png" />
</div>
### 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 (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
```
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.
<div class="tutorial-mock">
<img src="img/TutorialStyledMock.png" />
<img src="img/TutorialStyledMock2.png" />
</div>
### 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`s 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 (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
renderMovie(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
```
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.
<div class="tutorial-mock">
<img src="img/TutorialSingleFetched.png" />
<img src="img/TutorialSingleFetched2.png" />
</div>
## 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 (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
```
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:
<div class="tutorial-mock">
<img src="img/TutorialFinal.png" />
<img src="img/TutorialFinal2.png" />
</div>
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 SampleAppMovies 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 (
<ListView
dataSource={this.state.dataSource}
renderRow={this.renderMovie}
style={styles.listView}
/>
);
}
renderLoadingView() {
return (
<View style={styles.container}>
<Text>
Loading movies...
</Text>
</View>
);
}
renderMovie(movie) {
return (
<View style={styles.container}>
<Image
source={{uri: movie.posters.thumbnail}}
style={styles.thumbnail}
/>
<View style={styles.rightContainer}>
<Text style={styles.title}>{movie.title}</Text>
<Text style={styles.year}>{movie.year}</Text>
</View>
</View>
);
}
}
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('SampleAppMovies', () => SampleAppMovies);
```
+59
View File
@@ -0,0 +1,59 @@
---
id: state
title: State
layout: docs
category: The Basics
permalink: docs/state.html
next: style
---
There are two types of data that control a component: `props` and `state`. `props` are set by the parent and they are fixed throughout the lifetime of a component. For data that is going to change, we have to use `state`.
In general, you should initialize `state` in the constructor, and then call `setState` when you want to change it.
For example, let's say we want to make text that blinks all the time. The text itself gets set once when the blinking component gets created, so the text itself is a `prop`. The "whether the text is currently on or off" changes over time, so that should be kept in `state`.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
class Blink extends Component {
constructor(props) {
super(props);
this.state = {showText: true};
// Toggle the state every second
setInterval(() => {
this.setState({ showText: !this.state.showText });
}, 1000);
}
render() {
let display = this.state.showText ? this.props.text : ' ';
return (
<Text>{display}</Text>
);
}
}
class BlinkApp extends Component {
render() {
return (
<View>
<Blink text='I love to blink' />
<Blink text='Yes blinking is so great' />
<Blink text='Why did they ever take this out of HTML' />
<Blink text='Look at me look at me look at me' />
</View>
);
}
}
AppRegistry.registerComponent('BlinkApp', () => BlinkApp);
```
In a real application, you probably won't be setting state with a timer. You might set state when you have new data arrive from the server, or from user input. You can also use a state container like [Redux](http://redux.js.org/index.html) to control your data flow. In that case you would use Redux to modify your state rather than calling `setState` directly.
State works the same way as it does in React, so for more details on handling state, you can look at the [React.Component API](https://facebook.github.io/react/docs/component-api.html).
At this point, you might be annoyed that most of our examples so far use boring default black text. To make things more beautiful, you will have to [learn about Style](/react-native/docs/style.html).
+32 -82
View File
@@ -2,101 +2,51 @@
id: style
title: Style
layout: docs
category: Guides
category: The Basics
permalink: docs/style.html
next: images
next: height-and-width
---
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.
With React Native, you don't use a special language or syntax for defining styles. You just style your application using JavaScript. All of the core components accept a prop named `style`. The style names and values usually match how CSS works on the web, except names are written like `backgroundColor` instead of like `background-color`.
<script async class="speakerdeck-embed" data-id="2e15908049bb013230960224c1b4b8bd" data-ratio="2" src="//speakerdeck.com/assets/embed.js"></script>
The `style` prop can be a plain old JavaScript object. That's the simplest and what we usually use for example code. You can also pass an array of styles - the last style in the array has precedence, so you can use this to inherit styles.
## Declare Styles
As a component grows in complexity, it is often cleaner to use `StyleSheet.create` to define several styles in one place. Here's an example:
The way to declare styles in React Native is the following:
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, StyleSheet, Text, View } from 'react-native';
```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
<Text style={styles.base} />
<View style={styles.background} />
```
They also accept an array of styles.
```javascript
<View style={[styles.base, styles.background]} />
```
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
<View style={[styles.base, this.state.active && styles.active]} />
```
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
<View
style={[styles.base, {
width: this.state.width,
height: this.state.width * this.state.aspectRatio
}]}
/>
```
## 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() {
class LotsOfStyles extends Component {
render() {
return (
<View style={this.props.style}>
{elements.map((element) =>
<View style={[styles.element, this.props.elementStyle]} />
)}
<View>
<Text style={styles.red}>just red</Text>
<Text style={styles.bigblue}>just bigblue</Text>
<Text style={[styles.bigblue, styles.red]}>bigblue, then red</Text>
<Text style={[styles.red, styles.bigblue]}>red, then bigblue</Text>
</View>
);
}
}
const styles = StyleSheet.create({
bigblue: {
color: 'blue',
fontWeight: 'bold',
fontSize: 30,
},
red: {
color: 'red',
},
});
// ... in another file ...
<List style={styles.list} elementStyle={styles.listElement} />
AppRegistry.registerComponent('LotsOfStyles', () => LotsOfStyles);
```
## Supported Properties
You can checkout latest support of CSS Properties in following Links.
One common pattern is to make your component accept a `style` prop which in
turn is used to style subcomponents. You can use this to make styles "cascade" they way they do in CSS.
- [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)
There are a lot more ways to customize text style. Check out the [Text component reference](/react-native/docs/text.html) for a complete list.
Now you can make your text beautiful. The next step in becoming a style master is to [learn how to control component size](/react-native/docs/height-and-width.html).
+36 -14
View File
@@ -4,13 +4,24 @@
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
<Text style={{fontWeight: 'bold'}}>
I am bold
<Text style={{color: 'red'}}>
and red
</Text>
</Text>
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Text } from 'react-native';
class BoldAndBeautiful extends Component {
render() {
return (
<Text style={{fontWeight: 'bold'}}>
I am bold
<Text style={{color: 'red'}}>
and red
</Text>
</Text>
);
}
}
AppRegistry.registerComponent('BoldAndBeautiful', () => BoldAndBeautiful);
```
Behind the scenes, React Native converts this to a flat `NSAttributedString` or `SpannableString` that contains the following information:
@@ -25,15 +36,26 @@ Behind the scenes, React Native converts this to a flat `NSAttributedString` or
On iOS, you can nest views within your Text component. Here's an example:
```javascript
<Text>
There is a blue square
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
in between my text.
</Text>
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Text, View } from 'react-native';
class BlueIsCool extends Component {
render() {
return (
<Text>
There is a blue square
<View style={{width: 50, height: 50, backgroundColor: 'steelblue'}} />
in between my text.
</Text>
);
}
}
AppRegistry.registerComponent('BlueIsCool', () => BlueIsCool);
```
In order to use this feature, you must give the view a `width` and a `height`.
> In order to use this feature, you must give the view a `width` and a `height`.
## Containers
+2 -2
View File
@@ -2,9 +2,9 @@
id: timers
title: Timers
layout: docs
category: Polyfills
category: Guides
permalink: docs/timers.html
next: colors
next: direct-manipulation
---
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).
+34 -59
View File
@@ -6,69 +6,51 @@ 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.
These are some common issues you may run into while setting up React Native. If you encounter something that is not listed here, try [searching for the issue in GitHub](https://github.com/facebook/react-native/issues/).
![Keyboard Menu](https://cloud.githubusercontent.com/assets/1388454/6863127/03837824-d409-11e4-9251-e05bd31d978f.png)
### Port already in use
The React Native packager runs on port 8081. If another process is already using that port (such as McAfee Antivirus on Windows), you can either terminate that process, or change the port that the packager uses.
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.
#### Terminating a process on port 8081
You can use Cmd+M on Android to bring up the dev menu.
Run the following command on a Mac to find the id for the process that is listening on port 8081:
## 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
Then run the following to terminate the process:
`$ kill -9 <cma process id>`
`$ kill -9 <PID>`
#### Using a port other than 8081
##### 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"];
```
You can configure the packager to use a port other than 8081 by using the `port` parameter:
`$ react-native start --port=8088`
## 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.
You will also need to update your applications to load the JavaScript bundle from the new port.
To change the port used by an iOS application, edit the `AppDelegate.m` file in the `ios` folder. Scroll down to the line where the bundle location is defined, and replace 8081 with the new port.
```
brew uninstall watchman
brew install --HEAD watchman
jsCodeLocation = [NSURL URLWithString:@"http://localhost:8088/index.ios.bundle"];
```
## NPM locking error
### NPM locking error
If you encounter an error such as "npm WARN locking Error: EACCES" while using the React Native CLI, try running the following:
If in the `react-native init <project>` 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.
### Missing libraries for React
## Xcode Build Failures
If you added React Native manually to your project, make sure you have included all the relevant dependencies that you are using, like `RCTText.xcodeproj`, `RCTImage.xcodeproj`. 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).
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 `<Text />`, `<Image />` and `fetch()` APIs, you would need to add these in your `Podfile`:
```
pod 'React', :path => '../node_modules/react-native', :subspecs => [
'RCTText',
@@ -77,46 +59,39 @@ pod 'React', :path => '../node_modules/react-native', :subspecs => [
'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
#### 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
### No transports available
##### 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.
React Native implements a polyfill for WebSockets. These [polyfills](https://github.com/facebook/react-native/blob/master/Libraries/JavaScriptAppEngine/Initialization/InitializeJavaScriptAppEngine.js) 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, such as [Firebase](https://github.com/facebook/react-native/issues/3645), be sure to load/require it after react-native:
##### 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).
## Shell Command Unresponsive Exception
If you encounter:
If you encounter a ShellCommandUnresponsiveException exception such as:
```
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 `<project-name>/android/build.gradle` (https://github.com/facebook/react-native/issues/2720)
Try [downgrading your Gradle version to 1.2.3](https://github.com/facebook/react-native/issues/2720) in `android/build.gradle`.
## react-native init hangs
If you run into issues where running `react-native init` hangs in your system, try running it again in verbose mode and refering to [#2797](https://github.com/facebook/react-native/issues/2797) for common causes:
```
react-native init --verbose
```
-142
View File
@@ -1,142 +0,0 @@
---
id: tutorial-core-components
title: Core Components
layout: docs
category: Tutorials
permalink: docs/tutorial-core-components.html
next: tutorial-integration-with-existing-apps
---
Components are the building blocks for a React Native application. A React Native user interface (UI) is specified by declaring components, possibly nested, and then those components are mapped to the native UI on the targeted platform.
React Native has a number of core components that are commonly used in applications, either on their own or combined to build new components.
## Text
The most basic component in React Native is the [`Text`](/react-native/docs/text.html#content) component. The `Text` component simply renders text.
This example displays the `string` `"Hello World!"` on the device.
```JavaScript
import React from 'react';
import { AppRegistry, Text } from 'react-native';
const App = () => {
return (
<Text>Hello World!</Text>
);
}
// App registration and rendering
AppRegistry.registerComponent('MyApp', () => App);
```
## Image
The other basic React Native component is the [`Image`](/react-native/docs/image.html#content) component. Like `Text`, the `Image` component simply renders an image.
> An `Image` is analogous to using `img` when building websites.
The simplest way to render an image is to provide a source file to that image via the `source` attribute.
This example displays a checkbox `Image` on the device.
```JavaScript
import React from 'react';
import { AppRegistry, Image } from 'react-native';
const App = () => {
return (
<Image source={require('./img/check.png')} />
);
}
// App registration and rendering
AppRegistry.registerComponent('MyApp', () => App);
```
## View
A [`View`](/react-native/docs/view.html#content) is the most basic building block for a React Native application. The `View` is an abstraction on top of the target platform's native equivalent, such as iOS's `UIView`.
> A `View` is analogous to using a `div` for building websites.
While basic components such as `Text` and `Image`, can be displayed without a `View`, this is not generally recommended since the `View` gives you the control for styling and layout of those components.
This example creates a `View` that aligns the `string` `Hello` in the top center of the device, something which could not be done with a `Text` component alone (i.e., a `Text` component without a `View` would place the `string` in a fixed location in the upper corner):
```JavaScript
import React from 'react';
import { AppRegistry, Text, View } from 'react-native';
const App = () => {
return (
<View style={{alignItems: 'center'}}>
<Text>Hello!</Text>
</View>
);
}
// App registration and rendering
AppRegistry.registerComponent('MyApp', () => App);
```
## TextInput
Direct text-based user input is a foundation for many apps. Writing a post or comment on a page is a canonical example of this. [`TextInput`](/react-native/docs/textinput.html#content) is a basic component that allows the user to enter text.
This example creates a simple `TextInput` box with the `string` `Hello` as the placeholder when the `TextInput` is empty.
```JavaScript
import React from 'react';
import { AppRegistry, TextInput, View } from 'react-native';
const App = () => {
return (
<View>
<TextInput placeholder="Hello" />
</View>
);
}
// App registration and rendering
AppRegistry.registerComponent('MyApp', () => App);
```
## ListView
On mobile devices, lists are a core element in many applications. The [`ListView`](/react-native/docs/listview.html#content) component is a special type of [`View`](/react-native/docs/tutorials/core-components.html#view) that displays a vertically scrolling list of changing data.
The `ListView` component requires two properties, `dataSource` and `renderRow`. `dataSource` is the actual source of information that will be part of the list. `renderRow` takes the data and returns a renderable component to display.
This example creates a simple `ListView` of hardcoded data. It first initializes the `datasource` that will be used to populate the `ListView`. Then it renders that `ListView` with that data.
> A `rowHasChanged` function is required to use `ListView`. Here we just say a row has changed if the row we are on is not the same as the previous row.
```JavaScript
import React from 'react';
import { AppRegistry, Text, View, ListView} from 'react-native';
var SimpleList = React.createClass({
// Initialize the hardcoded data
getInitialState: function() {
var ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
return {
dataSource: ds.cloneWithRows(['John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie'])
};
},
render: function() {
return (
<View>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
</View>
);
}
});
// App registration and rendering
AppRegistry.registerComponent('MyApp', () => SimpleList);
```
+53
View File
@@ -0,0 +1,53 @@
---
id: tutorial
title: Tutorial
layout: docs
category: The Basics
permalink: docs/tutorial.html
next: props
---
React Native is like React, but it uses native components instead of web components as building blocks. So to understand the basic structure of a React Native app, you need to understand some of the basic React concepts, like JSX, components, `state`, and `props`. If you already know React, you still need to learn some React-Native-specific stuff, like the native components. This
tutorial is aimed at all audiences, whether you have React experience or not.
Let's do this thing.
## Hello World
In accordance with the ancient traditions of our people, we must first build an app that does nothing except say "Hello world". Here it is:
```ReactNativeWebPlayer
import React, { Component } from 'react';
import { AppRegistry, Text } from 'react-native';
class HelloWorldApp extends Component {
render() {
return (
<Text>Hello world!</Text>
);
}
}
AppRegistry.registerComponent('HelloWorldApp', () => HelloWorldApp);
```
If you are feeling curious, you can play around with sample code directly in the web simulators. You can also paste it into your `index.ios.js` or `index.android.js` file to create a real app on your local machine.
## What's going on here?
Some of the things in here might not look like JavaScript to you. Don't panic. This is the future.
First of all, ES2015 (also known as ES6) is a set of improvements to JavaScript that is now part of the official standard, but not yet supported by all browsers, so often it isn't used yet in web development. React Native ships with ES2015 support, so you can use this stuff without worrying about compatibility. `import`, `from`, `class`, `extends`, and the `() =>` syntax in the example above are all ES2015 features. If you aren't familiar with ES2015, you can probably pick it up just by reading through sample code like this tutorial has. If you want, [this page](https://babeljs.io/docs/learn-es2015/) has a good overview of ES2015 features.
The other unusual thing in this code example is `<Text>Hello world!</Text>`. This is JSX - a syntax for embedding XML within JavaScript. Many frameworks use a special templating language which lets you embed code inside markup language. In React, this is reversed. JSX lets you write your markup language inside code. It looks like HTML on the web, except instead of web things like `<div>` or `<span>`, you use React components. In this case, `<Text>`
is a built-in component that just displays some text.
## Component and AppRegistry
So this code is defining `HelloWorldApp`, a new `Component`, and it's registering it with the `AppRegistry`. When you're building a React Native app, you'll be making new components a lot. Anything you see on the screen is some sort of component. A component can be pretty simple - the only thing that's required is a `render` function which returns some JSX to render.
The `AppRegistry` just tells React Native which component is the root one for the whole application. You won't be thinking about `AppRegistry` a lot - there will probably just be one call to `AppRegistry.registerComponent` in your whole app. It's included in these examples so you can paste the whole thing into your `index.ios.js` or `index.android.js` file and get it running.
## This App Doesn't Do Very Much
Good point. To make components do more interesting things, you need to [learn about Props](/react-native/docs/props.html).
+51
View File
@@ -0,0 +1,51 @@
---
id: using-a-listview
title: Using a ListView
layout: docs
category: The Basics
permalink: docs/using-a-listview.html
next: network
---
The `ListView` component displays a vertically scrolling list of changing, but similarly structured, data.
`ListView` works well for long lists of data, where the number of items might change over time. Unlike the more generic [`ScrollView`](/react-native/docs/using-a-scrollview.html), the `ListView` only renders elements that are currently showing on the screen, not all the elements at once.
The `ListView` component requires two props: `dataSource` and `renderRow`. `dataSource` is the source of information for the list. `renderRow` takes one item from the source and returns a formatted component to render.
This example creates a simple `ListView` of hardcoded data. It first initializes the `dataSource` that will be used to populate the `ListView`. Each item in the `dataSource` is then rendered as a `Text` component. Finally it renders the `ListView` and all `Text` components.
> A `rowHasChanged` function is required to use `ListView`. Here we just say a row has changed if the row we are on is not the same as the previous row.
```JavaScript
import React, { Component } from 'react';
import { AppRegistry, ListView, Text, View } from 'react-native';
class ListViewBasics extends Component {
// Initialize the hardcoded data
constructor(props) {
super(props);
const ds = new ListView.DataSource({rowHasChanged: (r1, r2) => r1 !== r2});
this.state = {
dataSource: ds.cloneWithRows([
'John', 'Joel', 'James', 'Jimmy', 'Jackson', 'Jillian', 'Julie', 'Devin'
])
};
}
render() {
return (
<View style={{paddingTop: 22}}>
<ListView
dataSource={this.state.dataSource}
renderRow={(rowData) => <Text>{rowData}</Text>}
/>
</View>
);
}
}
// App registration and rendering
AppRegistry.registerComponent('AwesomeProject', () => ListViewBasics);
```
One of the most common uses for a `ListView` is displaying data that you fetch from a server. To do that, you will need to [learn about networking in React Native](/react-native/docs/network.html).
+64
View File
@@ -0,0 +1,64 @@
---
id: using-a-scrollview
title: Using a ScrollView
layout: docs
category: The Basics
permalink: docs/using-a-scrollview.html
next: using-a-listview
---
The [`ScrollView`](/react-native/docs/scrollview.html) is a generic scrolling container that can host multiple components and views. The scrollable items need not be homogenous, and you can scroll both vertically and horizontally (by setting the `horizontal` property).
This example creates a vertical `ScrollView` with both images and text mixed together.
```ReactNativeWebPlayer
import React, { Component } from 'react';
import{ AppRegistry, ScrollView, Image, Text, View } from 'react-native'
class IScrolledDownAndWhatHappenedNextShockedMe extends Component {
render() {
return(
<ScrollView>
<Text style={{fontSize:96}}>Scroll me plz</Text>
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Text style={{fontSize:96}}>If you like</Text>
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Text style={{fontSize:96}}>Scrolling down</Text>
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Text style={{fontSize:96}}>What's the best</Text>
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Text style={{fontSize:96}}>Framework around?</Text>
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Image source={require('./img/favicon.png')} />
<Text style={{fontSize:80}}>React Native</Text>
</ScrollView>
);
}
}
AppRegistry.registerComponent(
'IScrolledDownAndWhatHappenedNextShockedMe',
() => IScrolledDownAndWhatHappenedNextShockedMe);
```
`ScrollView` works best to present a small amount of things of a limited size. All the elements and views of a `ScrollView` are rendered, even if they are not currently shown on the screen. If you have a long list of more items that can fit on the screen, you should use a `ListView` instead. So let's [learn about the ListView](/react-native/docs/using-a-listview.html) next.
+167
View File
@@ -0,0 +1,167 @@
---
id: using-navigators
title: Using Navigators
layout: docs
category: The Basics
permalink: docs/using-navigators.html
next: more-resources
---
Mobile apps rarely consist of just one screen. As soon as you add a second screen to your app, you will have to take into consideration how the user will navigate from one screen to the other.
You can use navigators to transition between multiple screens. These transitions can be typical side-to-side animations down a master/detail stack, or vertical modal popups.
## Navigator
React Native has several built-in navigation components, but for your first app you will probably want to use `Navigator`. It provides a JavaScript implementation of a navigation stack, so it works on both iOS and Android and is easy to customize.
![](img/NavigationStack-Navigator.gif)
### Working with Scenes
At this point you should feel comfortable rendering all sorts of components in your app, be it a simple `View` with `Text` inside, or a `ScrollView` with a list of `Image`s. Together, these components make up a scene (another word for screen) in your app.
A scene is nothing other than a React component that is typically rendered full screen. This is in contrast to a `Text`, an `Image`, or even a custom `SpinningBeachball` component that is meant to be rendered as part of a screen. You may have already used one without realizing it - the ["HelloWorldApp"](docs/tutorial.html), the ["FlexDirectionBasics"](docs/flexbox.html), and the ["ListViewBasics"](docs/using-a-listview.html) components covered earlier in the tutorial are all examples of scenes.
For simplicity's sake, let's define a simple scene that displays a bit of text. We will come back to this scene later as we add navigation to our app. Create a new file called "MyScene.js" with the following contents:
```javascript
import React, { Component } from 'react';
import { View, Text } from 'react-native';
export default class MyScene extends Component {
getDefaultProps() {
return {
title: 'MyScene'
};
}
render() {
return (
<View>
<Text>Hi! My name is {this.props.title}.</Text>
</View>
)
}
}
```
Notice the `export default` in front of the component declaration. This will _export_ the component, and in turn allow other components to _import_ it later on, like so:
```javascript
import React, { Component } from 'react';
import { View, Text } from 'react-native';
import MyScene from './MyScene';
class YoDawgApp extends Component {
render() {
return (
<MyScene />
)
}
}
AppRegistry.registerComponent('YoDawgApp', () => YoDawgApp);
```
We now have a simple app that renders your scene and nothing else. In this case, `MyScene` is a simple example of a [reusable React component](https://facebook.github.io/react/docs/reusable-components.html).
### Using Navigator
Enough about scenes, let's start navigating. We will start by rendering a `Navigator`, and then let the `Navigator` render the scene for you by passing in your own render function to its `renderScene` prop.
```javascript
render() {
return (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) => {
<MyScene title={route.title} />
}}
/>
);
}
```
Something you will encounter a lot when dealing with navigation is the concept of routes. A route is an object that contains information about a scene. It is used to provide all the context that the navigator's `renderScene` function needs to render a scene. It can have any number of keys to help distinguish your scene, and I happened to pick a single `title` key for the above example.
#### Pushing scenes onto the stack
In order to transition to a new scene, you will need to learn about `push` and `pop`. These two methods are provided by the `navigator` object that is passed to your `renderScene` function above. They can be used, as you may have realized, to push and pop routes into your navigation stack.
```javascript
navigator.push({
title: 'Next Scene',
index: 1,
});
navigator.pop();
```
A more complete example that demonstrates the pushing and popping of routes could therefore look something like this:
```javascript
import React, { Component, PropTypes } from 'react';
import { Navigator, Text, TouchableHighlight, View } from 'react-native';
export default class SimpleNavigationApp extends Component {
render() {
return (
<Navigator
initialRoute={{ title: 'My Initial Scene', index: 0 }}
renderScene={(route, navigator) =>
<MyScene
title={route.title}
// Function to call when a new scene should be displayed
onForward={ () => {
const nextIndex = route.index + 1;
navigator.push({
title: 'Scene ' + nextIndex,
index: nextIndex,
});
}}
// Function to call to go back to the previous scene
onBack={() => {
if (route.index > 0) {
navigator.pop();
}
}}
/>
}
/>
)
}
}
class MyScene extends Component {
static propTypes = {
title: PropTypes.string.isRequired,
onForward: PropTypes.func.isRequired,
onBack: PropTypes.func.isRequired,
}
render() {
return (
<View>
<Text>Current Scene: { this.props.title }</Text>
<TouchableHighlight onPress={this.props.onForward}>
<Text>Tap me to load the next scene</Text>
</TouchableHighlight>
<TouchableHighlight onPress={this.props.onBack}>
<Text>Tap me to go back</Text>
</TouchableHighlight>
</View>
)
}
}
```
In this example, the `MyScene` component is passed the title of the current route via the `title` prop. It displays two tappable components that call the `onForward` and `onBack` functions passed through its props, which in turn will call `navigator.push()` and `navigator.pop()` as needed.
Check out the [Navigator API reference](docs/navigator.html) for more `Navigator` code samples, or read through the [Navigation guide](docs/navigation.html) for other examples of what you can do with navigators.
## High Five!
If you've gotten here by reading linearly through the tutorial, then you are a pretty impressive human being. Congratulations. Next, you might want to check out [all the cool stuff the community does with React Native](/react-native/docs/more-resources.html).
-67
View File
@@ -1,67 +0,0 @@
---
id: videos
title: Videos
layout: docs
category: Community Resources
permalink: docs/videos.html
next: newsletter
---
### React.js Conf 2016
<iframe width="650" height="315" src="//www.youtube.com/embed/2Zthnq-hIXA" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/Xnqy_zkBAew" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/RBg2_uQE4KM" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/0MlT74erp60" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/B8J8xn3pLpk" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/f1Sj48rJE3I" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/uBYPqb83C7k" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/09ddrCaLo10" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/d3VVfA9hWjc" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/impQkQOCbMw" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/wuLKELLuwVk" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/Zoerbz5Mu5U" frameborder="0" allowfullscreen></iframe>
### React.js Conf 2015
<iframe width="650" height="315" src="//www.youtube.com/embed/KVZ-P-ZI6W4" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/7rDsRXj9-cU" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/X6YbAKiLCLU" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/oWPoW0gIzvs" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/hDviGU-57lU" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/8N4f4h6SThc" frameborder="0" allowfullscreen></iframe>
<iframe width="650" height="315" src="//www.youtube.com/embed/-XxSCi8TKuk" frameborder="0" allowfullscreen></iframe>
### [The Changelog #149](https://thechangelog.com/149/)
With Christopher "vjeux" Chedeau and Spencer Ahrens
<audio src="http://fdlyr.co/d/changelog/cdn.5by5.tv/audio/broadcasts/changelog/2015/changelog-149.mp3" controls="controls" preload="none"></audio>
### [JSJabber #146](http://devchat.tv/js-jabber/146-jsj-react-with-christopher-chedeau-and-jordan-walke)
With Christopher "vjeux" Chedeau and Jordan Walke
<audio controls="">
<source ng-src="http://www.podtrac.com/pts/redirect.mp3/media.devchat.tv/js-jabber/JSJ146React.mp3?player=true" type="audio/mpeg" src="http://www.podtrac.com/pts/redirect.mp3/media.devchat.tv/js-jabber/JSJ146React.mp3?player=true">
<p>
This player is only available in HTML5 enabled browsers. Please update your browser or
<a download="146-jsj-react-with-christopher-chedeau-and-jordan-walke.mp3" href="http://www.podtrac.com/pts/redirect.mp3/media.devchat.tv/js-jabber/JSJ146React.mp3?download=true?download=true">download the episode</a>
</p>
</audio>
+4
View File
@@ -19,7 +19,9 @@ const link = require('./rnpm/link/src/link');
const path = require('path');
const Promise = require('promise');
const runAndroid = require('./runAndroid/runAndroid');
const logAndroid = require('./logAndroid/logAndroid');
const runIOS = require('./runIOS/runIOS');
const logIOS = require('./logIOS/logIOS');
const server = require('./server/server');
const TerminalAdapter = require('yeoman-environment/lib/adapter.js');
const yeoman = require('yeoman-environment');
@@ -49,7 +51,9 @@ const documentedCommands = {
'new-library': [library, 'generates a native library bridge'],
'android': [generateWrapper, 'generates an Android project for your app'],
'run-android': [runAndroid, 'builds your app and starts it on a connected Android emulator or device'],
'log-android': [logAndroid, 'print Android logs'],
'run-ios': [runIOS, 'builds your app and starts it on iOS simulator'],
'log-ios': [logIOS, 'print iOS logs'],
'upgrade': [upgrade, 'upgrade your app\'s template files to the latest version; run this after ' +
'updating the react-native version in your package.json and running npm install'],
'link': [linkWrapper, 'link a library'],
@@ -18,6 +18,7 @@
{
NSURL *jsCodeLocation;
[[RCTBundleURLProvider sharedSettings] setDefaults];
jsCodeLocation = [[RCTBundleURLProvider sharedSettings] jsBundleURLForBundleRoot:@"index.ios" fallbackResource:nil];
RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation
+51
View File
@@ -0,0 +1,51 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
'use strict';
const chalk = require('chalk');
const child_process = require('child_process');
const Promise = require('promise');
/**
* Starts adb logcat
*/
function logAndroid() {
return new Promise((resolve, reject) => {
_logAndroid(resolve, reject);
});
}
function _logAndroid(resolve, reject) {
try {
const adbPath = process.env.ANDROID_HOME
? process.env.ANDROID_HOME + '/platform-tools/adb'
: 'adb';
const adbArgs = ['logcat', '*:S', 'ReactNative:V', 'ReactNativeJS:V'];
console.log(chalk.bold(
`Starting the logger (${adbPath} ${adbArgs.join(' ')})...`
));
const log = child_process.spawnSync(adbPath, adbArgs, {stdio: 'inherit'});
if (log.error !== null) {
throw log.error;
}
} catch (e) {
console.log(chalk.red(
'adb invocation failed. Do you have adb in your PATH?'
));
reject();
return;
}
}
module.exports = logAndroid;
+77
View File
@@ -0,0 +1,77 @@
'use strict';
const chalk = require('chalk');
const child_process = require('child_process');
const os = require('os');
const path = require('path');
const Promise = require('promise');
/**
* Starts iOS device syslog tail
*/
function logIOS() {
return new Promise((resolve, reject) => {
_logIOS(resolve, reject);
});
}
function _logIOS(resolve, reject) {
let rawDevices;
try {
rawDevices = child_process.execFileSync(
'xcrun', ['simctl', 'list', 'devices', '--json'], {encoding: 'utf8'}
);
} catch (e) {
console.log(chalk.red(
'xcrun invocation failed. Please check that Xcode is installed.'
));
reject(e);
return;
}
const { devices } = JSON.parse(rawDevices);
const device = _findAvailableDevice(devices);
if (device === undefined) {
console.log(chalk.red(
'No active iOS device found'
));
reject();
}
tailDeviceLogs(device.udid, reject);
}
function _findAvailableDevice(devices) {
for (const key of Object.keys(devices)) {
for (const device of devices[key]) {
if (device.availability === '(available)' && device.state === 'Booted') {
return device;
}
}
}
}
function tailDeviceLogs(udid, reject) {
const logDir = path.join(
os.homedir(),
'Library',
'Logs',
'CoreSimulator',
udid,
'asl',
);
const log =
child_process.spawnSync('syslog', ['-w', '-F', 'std', '-d', logDir], {stdio: 'inherit'});
if (log.error !== null) {
console.log(chalk.red(
'syslog invocation failed.'
));
reject(log.error);
}
}
module.exports = logIOS;
@@ -33,9 +33,9 @@ exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
const packageFolder = userConfig.packageFolder ||
packageName.replace(/\./g, path.sep);
const mainActivityPath = path.join(
const mainFilePath = path.join(
sourceDir,
userConfig.mainActivityPath || `src/main/java/${packageFolder}/MainActivity.java`
userConfig.mainFilePath || `src/main/java/${packageFolder}/MainApplication.java`
);
const stringsPath = path.join(
@@ -68,7 +68,7 @@ exports.projectConfig = function projectConfigAndroid(folder, userConfig) {
buildGradlePath,
settingsGradlePath,
assetsPath,
mainActivityPath,
mainFilePath,
};
};
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "react-native",
"version": "1000.0.0",
"version": "0.29.1",
"description": "A framework for building native apps using React",
"license": "BSD-3-Clause",
"repository": {
@@ -125,7 +125,7 @@
"react-native": "local-cli/wrong-react-native.js"
},
"peerDependencies": {
"react": "~15.2.0-rc.1"
"react": "~15.2.0"
},
"dependencies": {
"absolute-path": "^0.0.0",
@@ -201,7 +201,7 @@
"flow-bin": "^0.27.0",
"jest": "12.1.1",
"portfinder": "0.4.0",
"react": "~15.2.0-rc.1",
"react": "~15.2.0",
"shelljs": "0.6.0"
}
}
}
+5 -3
View File
@@ -31,7 +31,9 @@ gradle.projectsEvaluated {
productFlavors.each { productFlavorName ->
buildTypes.each { buildTypeName ->
// Create variant and target names
def targetName = "${productFlavorName.capitalize()}${buildTypeName.capitalize()}"
def flavorNameCapitalized = "${productFlavorName.capitalize()}"
def buildNameCapitalized = "${buildTypeName.capitalize()}"
def targetName = "${flavorNameCapitalized}${buildNameCapitalized}"
def targetPath = productFlavorName ?
"${productFlavorName}/${buildTypeName}" :
"${buildTypeName}"
@@ -92,8 +94,8 @@ gradle.projectsEvaluated {
currentBundleTask.dependsOn("merge${targetName}Resources")
currentBundleTask.dependsOn("merge${targetName}Assets")
runBefore("processArmeabi-v7a${targetName}Resources", currentBundleTask)
runBefore("processX86${targetName}Resources", currentBundleTask)
runBefore("process${flavorNameCapitalized}Armeabi-v7a${buildNameCapitalized}Resources", currentBundleTask)
runBefore("process${flavorNameCapitalized}X86${buildNameCapitalized}Resources", currentBundleTask)
runBefore("processUniversal${targetName}Resources", currentBundleTask)
runBefore("process${targetName}Resources", currentBundleTask)
}
+11 -1
View File
@@ -8,6 +8,7 @@
var React = require('React');
var Prism = require('Prism');
var WebPlayer = require('WebPlayer');
var Header = require('Header');
/**
@@ -827,7 +828,16 @@ Parser.prototype.tok = function() {
);
}
case 'code': {
return <Prism>{this.token.text}</Prism>;
var lang = this.token.lang
, text = this.token.text;
if (lang && lang.indexOf('ReactNativeWebPlayer') === 0) {
return (
<WebPlayer params={lang.split('?')[1]}>{text}</WebPlayer>
);
}
return <Prism>{text}</Prism>;
}
case 'table': {
var table = []
+68
View File
@@ -0,0 +1,68 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule WebPlayer
*/
var React = require('React');
var Prism = require('Prism');
/**
* Use the WebPlayer by including a ```ReactNativeWebPlayer``` block in markdown.
*
* Optionally, include url parameters directly after the block's language. For
* the complete list of url parameters, see: https://github.com/dabbott/react-native-web-player
*
* E.g.
* ```ReactNativeWebPlayer?platform=android
* import React from 'react';
* import { AppRegistry, Text } from 'react-native';
*
* const App = () => <Text>Hello World!</Text>;
*
* AppRegistry.registerComponent('MyApp', () => App);
* ```
*/
var WebPlayer = React.createClass({
parseParams: function(paramString) {
var params = {};
if (paramString) {
var pairs = paramString.split('&');
for (var i = 0; i < pairs.length; i++) {
var pair = pairs[i].split('=');
params[pair[0]] = pair[1];
}
}
return params;
},
render: function() {
var hash = `#code=${encodeURIComponent(this.props.children)}`;
if (this.props.params) {
hash += `&${this.props.params}`;
}
return (
<div className={'web-player'}>
<Prism>{this.props.children}</Prism>
<iframe
style={{marginTop: 4}}
width='880'
height={this.parseParams(this.props.params).platform === 'android' ? '425' : '420'}
data-src={`//npmcdn.com/react-native-web-player@1.0.0/index.html${hash}`}
frameBorder='0'
/>
</div>
);
},
});
module.exports = WebPlayer;
+15
View File
@@ -0,0 +1,15 @@
{
"tags": {
"allowUnknownTags": true,
"dictionaries": ["jsdoc","closure"]
},
"source": {
"includePattern": ".+\\.js(doc)?$",
"excludePattern": "(^|\\/|\\\\)_"
},
"plugins": ["./jsdocs/jsdoc-plugin-values"],
"templates": {
"cleverLinks": true,
"monospaceLinks": false
}
}
+11
View File
@@ -0,0 +1,11 @@
exports.defineTags = function(dictionary) {
dictionary.defineTag('value', {
mustHaveValue: true,
canHaveType: true,
canHaveName: true,
onTagged: function(doclet, tag) {
if (!doclet.values) { doclet.values = []; }
doclet.values.push(tag.value);
}
});
};
+324 -31
View File
@@ -9,6 +9,8 @@
* @providesModule AutodocsLayout
*/
'use strict';
var DocsSidebar = require('DocsSidebar');
var H = require('Header');
var Header = require('Header');
@@ -93,6 +95,45 @@ function renderType(type) {
return type.name;
}
function renderTypeNameLink(typeName, docPath, namedTypes) {
const ignoreTypes = [
'string',
'number',
'boolean',
'object',
'function',
'array',
];
const typeNameLower = typeName.toLowerCase();
if (ignoreTypes.indexOf(typeNameLower) !== -1 || !namedTypes[typeNameLower]) {
return typeName;
}
return <a href={docPath + '#' + typeNameLower}>{typeName}</a>;
}
function renderTypeWithLinks(type, docTitle, namedTypes) {
if (!type || !type.names) {
return null;
}
const docPath = docTitle ? 'docs/' + docTitle.toLowerCase() + '.html' : 'docs/';
return (
<div>
{
type.names.map((typeName, index, array) => {
let separator = index < array.length - 1 && ' | ';
return (
<span key={index}>
{renderTypeNameLink(typeName, docPath, namedTypes)}
{separator}
</span>
);
})
}
</div>
);
}
function sortByPlatform(props, nameA, nameB) {
var a = props[nameA];
var b = props[nameB];
@@ -134,6 +175,17 @@ function removeCommentsFromDocblock(docblock) {
.join('\n');
}
function getNamedTypes(typedefs) {
let namedTypes = {};
typedefs && typedefs.forEach(typedef => {
if (typedef.name) {
const type = typedef.name.toLowerCase();
namedTypes[type] = 1;
}
});
return namedTypes;
}
var ComponentDoc = React.createClass({
renderProp: function(name, prop) {
return (
@@ -254,20 +306,22 @@ var ComponentDoc = React.createClass({
}
},
renderMethod: function(method) {
renderMethod: function(method, namedTypes) {
return (
<Method
key={method.name}
name={method.name}
description={method.description}
params={method.params}
modifiers={method.modifiers}
modifiers={method.scope ? [method.scope] : method.modifiers}
examples={method.examples}
returns={method.returns}
namedTypes={namedTypes}
/>
);
},
renderMethods: function(methods) {
renderMethods: function(methods, namedTypes) {
if (!methods || !methods.length) {
return null;
}
@@ -277,7 +331,38 @@ var ComponentDoc = React.createClass({
<div className="props">
{methods.filter((method) => {
return method.name[0] !== '_';
}).map(this.renderMethod)}
}).map(method => this.renderMethod(method, namedTypes))}
</div>
</span>
);
},
renderTypeDef: function(typedef, namedTypes) {
return (
<TypeDef
key={typedef.name}
name={typedef.name}
description={typedef.description}
type={typedef.type}
properties={typedef.properties}
values={typedef.values}
apiName={this.props.apiName}
namedTypes={namedTypes}
/>
);
},
renderTypeDefs: function(typedefs, namedTypes) {
if (!typedefs || !typedefs.length) {
return null;
}
return (
<span>
<H level={3}>Type Definitions</H>
<div className="props">
{typedefs.map((typedef) => {
return this.renderTypeDef(typedef, namedTypes);
})}
</div>
</span>
);
@@ -286,6 +371,7 @@ var ComponentDoc = React.createClass({
render: function() {
var content = this.props.content;
this.extractPlatformFromProps(content.props);
const namedTypes = getNamedTypes(content.typedef);
return (
<div>
<Marked>
@@ -293,7 +379,8 @@ var ComponentDoc = React.createClass({
</Marked>
<H level={3}>Props</H>
{this.renderProps(content.props, content.composes)}
{this.renderMethods(content.methods)}
{this.renderMethods(content.methods, namedTypes)}
{this.renderTypeDefs(content.typedef, namedTypes)}
</div>
);
}
@@ -301,19 +388,22 @@ var ComponentDoc = React.createClass({
var APIDoc = React.createClass({
renderMethod: function(method) {
renderMethod: function(method, namedTypes) {
return (
<Method
key={method.name}
name={method.name}
description={method.docblock && removeCommentsFromDocblock(method.docblock)}
description={method.description || method.docblock && removeCommentsFromDocblock(method.docblock)}
params={method.params}
modifiers={method.modifiers}
modifiers={method.scope ? [method.scope] : method.modifiers}
examples={method.examples}
apiName={this.props.apiName}
namedTypes={namedTypes}
/>
);
},
renderMethods: function(methods) {
renderMethods: function(methods, namedTypes) {
if (!methods.length) {
return null;
}
@@ -323,7 +413,7 @@ var APIDoc = React.createClass({
<div className="props">
{methods.filter((method) => {
return method.name[0] !== '_';
}).map(this.renderMethod)}
}).map(method => this.renderMethod(method, namedTypes))}
</div>
</span>
);
@@ -363,7 +453,7 @@ var APIDoc = React.createClass({
);
},
renderClasses: function(classes) {
renderClasses: function(classes, namedTypes) {
if (!classes || !classes.length) {
return null;
}
@@ -382,7 +472,7 @@ var APIDoc = React.createClass({
{cls.docblock && <Marked>
{removeCommentsFromDocblock(cls.docblock)}
</Marked>}
{this.renderMethods(cls.methods)}
{this.renderMethods(cls.methods, namedTypes)}
{this.renderProperties(cls.properties)}
</ul>
</span>
@@ -393,6 +483,55 @@ var APIDoc = React.createClass({
);
},
renderTypeDef: function(typedef, namedTypes) {
return (
<TypeDef
key={typedef.name}
name={typedef.name}
description={typedef.description}
type={typedef.type}
properties={typedef.properties}
values={typedef.values}
apiName={this.props.apiName}
namedTypes={namedTypes}
/>
);
},
renderTypeDefs: function(typedefs, namedTypes) {
if (!typedefs || !typedefs.length) {
return null;
}
return (
<span>
<H level={3}>Type Definitions</H>
<div className="props">
{typedefs.map((typedef) => {
return this.renderTypeDef(typedef, namedTypes);
})}
</div>
</span>
);
},
renderMainDescription: function(content) {
if (content.docblock) {
return (
<Marked>
{removeCommentsFromDocblock(content.docblock)}
</Marked>
);
}
if (content.class && content.class.length && content.class[0].description) {
return (
<Marked>
{content.class[0].description}
</Marked>
);
}
return null;
},
render: function() {
var content = this.props.content;
if (!content.methods) {
@@ -400,14 +539,14 @@ var APIDoc = React.createClass({
'No component methods found for ' + content.componentName
);
}
const namedTypes = getNamedTypes(content.typedef);
return (
<div>
<Marked>
{removeCommentsFromDocblock(content.docblock)}
</Marked>
{this.renderMethods(content.methods)}
{this.renderMainDescription(content)}
{this.renderMethods(content.methods, namedTypes)}
{this.renderProperties(content.properties)}
{this.renderClasses(content.classes)}
{this.renderClasses(content.classes, namedTypes)}
{this.renderTypeDefs(content.typedef, namedTypes)}
</div>
);
}
@@ -440,21 +579,81 @@ var Method = React.createClass({
return this.renderTypehintRec(typehint);
},
renderMethodExamples: function(examples) {
if (!examples || !examples.length) {
return null;
}
return examples.map((example) => {
const re = /<caption>(.*?)<\/caption>/ig;
const result = re.exec(example);
const caption = result ? result[1] + ':' : 'Example:';
const code = example.replace(/<caption>.*?<\/caption>/ig, '')
.replace(/^\n\n/, '');
return (
<div>
<br/>
{caption}
<Prism>
{code}
</Prism>
</div>
);
});
},
renderMethodParameters: function(params) {
if (!params || !params.length) {
return null;
}
if (!params[0].type || !params[0].type.names) {
return null;
}
const foundDescription = params.find(p => p.description);
if (!foundDescription) {
return null;
}
return (
<div>
<strong>Parameters:</strong>
<table className="params">
<thead>
<tr>
<th>Name and Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{params.map((param) => {
return (
<tr>
<td>
{param.optional ? '[' + param.name + ']' : param.name}
<br/><br/>
{renderTypeWithLinks(param.type, this.props.apiName, this.props.namedTypes)}
</td>
<td className="description"><Marked>{param.description}</Marked></td>
</tr>
);
})}
</tbody>
</table>
</div>
);
},
render: function() {
return (
<div className="prop">
<Header level={4} className="propTitle" toSlug={this.props.name}>
{this.props.modifiers.length && <span className="propType">
<Header level={4} className="methodTitle" toSlug={this.props.name}>
{this.props.modifiers && this.props.modifiers.length && <span className="methodType">
{this.props.modifiers.join(' ') + ' '}
</span> || ''}
{this.props.name}
<span className="propType">
({this.props.params
<span className="methodType">
({this.props.params && this.props.params.length && this.props.params
.map((param) => {
var res = param.name;
if (param.type) {
res += ': ' + this.renderTypehint(param.type);
}
res += param.optional ? '?' : '';
return res;
})
.join(', ')})
@@ -464,6 +663,100 @@ var Method = React.createClass({
{this.props.description && <Marked>
{this.props.description}
</Marked>}
{this.renderMethodParameters(this.props.params)}
{this.renderMethodExamples(this.props.examples)}
</div>
);
},
});
var TypeDef = React.createClass({
renderProperties: function(properties) {
if (!properties || !properties.length) {
return null;
}
if (!properties[0].type || !properties[0].type.names) {
return null;
}
return (
<div>
<br/>
<strong>Properties:</strong>
<table className="params">
<thead>
<tr>
<th>Name and Type</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{properties.map((property) => {
return (
<tr>
<td>
{property.optional ? '[' + property.name + ']' : property.name}
<br/><br/>
{renderTypeWithLinks(property.type, this.props.apiName, this.props.namedTypes)}
</td>
<td className="description"><Marked>{property.description}</Marked></td>
</tr>
);
})}
</tbody>
</table>
</div>
);
},
renderValues: function(values) {
if (!values || !values.length) {
return null;
}
if (!values[0].type || !values[0].type.names) {
return null;
}
return (
<div>
<br/>
<strong>Constants:</strong>
<table className="params">
<thead>
<tr>
<th>Value</th>
<th>Description</th>
</tr>
</thead>
<tbody>
{values.map((value) => {
return (
<tr>
<td>
{value.name}
</td>
<td className="description"><Marked>{value.description}</Marked></td>
</tr>
);
})}
</tbody>
</table>
</div>
);
},
render: function() {
return (
<div className="prop">
<Header level={4} className="propTitle" toSlug={this.props.name}>
{this.props.name}
</Header>
{this.props.description && <Marked>
{this.props.description}
</Marked>}
<strong>Type:</strong>
<br/>
{this.props.type.names.join(' | ')}
{this.renderProperties(this.props.properties)}
{this.renderValues(this.props.values)}
</div>
);
},
@@ -482,7 +775,7 @@ var EmbeddedSimulator = React.createClass({
: <img alt="Run example in simulator" width="170" height="356" src="img/uiexplorer_main_ios.png" />;
return (
<div className="column-left">
<div className="embedded-simulator">
<p><a className="modal-button-open"><strong>Run this example</strong></a></p>
<div className="modal-button-open modal-button-open-img">
{imagePreview}
@@ -562,9 +855,12 @@ var Autodocs = React.createClass({
path={example.path}
metadata={metadata}
/>
<Prism>
{example.content.replace(/^[\s\S]*?\*\//, '').trim()}
</Prism>
<div className="example-container">
<Prism>
{example.content.replace(/^[\s\S]*?\*\//, '').trim()}
</Prism>
<EmbeddedSimulator shouldRender={metadata.runnable} metadata={metadata} />
</div>
</div>
);
},
@@ -608,9 +904,6 @@ var Autodocs = React.createClass({
{metadata.next && <a className="docs-next" href={'docs/' + metadata.next + '.html#content'}>Next &rarr;</a>}
</div>
</div>
<EmbeddedSimulator shouldRender={metadata.runnable} metadata={metadata} />
</section>
</Site>
);
+2 -2
View File
@@ -51,10 +51,10 @@ var DocsLayout = React.createClass({
<div className="survey">
<div className="survey-image" />
<p>
We are planning improvements to the React Native documentation. Your responses to this short survey will go a long way in helping us provide valuable content. Thank you!
Recently, we have been working hard to make the documentation better based on your feedback. Your responses to this yes/no style survey will help us gauge whether we moved in the right direction with the improvements. Thank you!
</p>
<center>
<a className="button" href="https://www.facebook.com/survey?oid=681969738611332">Take Survey</a>
<a className="button" href="https://www.facebook.com/survey?oid=516954245168428">Take Survey</a>
</center>
</div>
</div>
+10 -2
View File
@@ -13,9 +13,17 @@
"mkdirp": "^0.5.1",
"optimist": "0.6.0",
"react": "~0.13.0",
"react-docgen": "^2.8.0",
"react-docgen": "^2.9.0",
"react-page-middleware": "git://github.com/facebook/react-page-middleware.git",
"request": "^2.69.0",
"semver-compare": "^1.0.0"
"semver-compare": "^1.0.0",
"babel-core": "^6.6.4",
"babel-plugin-external-helpers": "^6.5.0",
"babel-polyfill": "^6.6.1",
"babel-preset-react-native": "~1.6.0",
"babel-register": "^6.6.0",
"babel-types": "^6.6.4",
"jsdoc-api": "^1.1.0",
"deep-assign": "^2.0.0"
}
}
+127 -14
View File
@@ -1,8 +1,8 @@
"use strict";
var docgen = require('react-docgen');
'use strict';
const docgen = require('react-docgen');
function stylePropTypeHandler(documentation, path) {
var propTypesPath = docgen.utils.getMemberValuePath(path, 'propTypes');
let propTypesPath = docgen.utils.getMemberValuePath(path, 'propTypes');
if (!propTypesPath) {
return;
}
@@ -18,25 +18,25 @@ function stylePropTypeHandler(documentation, path) {
docgen.utils.getPropertyName(propertyPath) !== 'style') {
return;
}
var valuePath = docgen.utils.resolveToValue(propertyPath.get('value'));
let valuePath = docgen.utils.resolveToValue(propertyPath.get('value'));
// If it's a call to StyleSheetPropType, do stuff
if (valuePath.node.type !== 'CallExpression' ||
valuePath.node.callee.name !== 'StyleSheetPropType') {
return;
}
// Get type of style sheet
var styleSheetModule = docgen.utils.resolveToModule(
let styleSheetModule = docgen.utils.resolveToModule(
valuePath.get('arguments', 0)
);
if (styleSheetModule) {
var propDescriptor = documentation.getPropDescriptor('style');
let propDescriptor = documentation.getPropDescriptor('style');
propDescriptor.type = {name: 'stylesheet', value: styleSheetModule};
}
});
}
function deprecatedPropTypeHandler(documentation, path) {
var propTypesPath = docgen.utils.getMemberValuePath(path, 'propTypes');
let propTypesPath = docgen.utils.getMemberValuePath(path, 'propTypes');
if (!propTypesPath) {
return;
}
@@ -48,13 +48,13 @@ function deprecatedPropTypeHandler(documentation, path) {
// Checks for deprecatedPropType function and add deprecation info.
propTypesPath.get('properties').each(function(propertyPath) {
var valuePath = docgen.utils.resolveToValue(propertyPath.get('value'));
let valuePath = docgen.utils.resolveToValue(propertyPath.get('value'));
// If it's a call to deprecatedPropType, do stuff
if (valuePath.node.type !== 'CallExpression' ||
valuePath.node.callee.name !== 'deprecatedPropType') {
return;
}
var propDescriptor = documentation.getPropDescriptor(
let propDescriptor = documentation.getPropDescriptor(
docgen.utils.getPropertyName(propertyPath)
);
// The 2nd argument of deprecatedPropType is the deprecation message.
@@ -72,13 +72,104 @@ function deprecatedPropTypeHandler(documentation, path) {
});
}
function typedefHandler(documentation, path) {
const declarationPath = path.get('declaration');
const typePath = declarationPath.get('right');
// Name, type, description of the typedef
const name = declarationPath.value.id.name;
const type = { names: [typePath.node.id.name] };
const description = docgen.utils.docblock.getDocblock(path);
// Get the properties for the typedef
let paramsDescriptions = [];
let paramsTypes;
if (typePath.node.typeParameters) {
const paramsPath = typePath.get('typeParameters').get('params', 0);
if (paramsPath) {
const properties = paramsPath.get('properties');
// Get the descriptions inside each property (are inline leading comments)
paramsDescriptions =
properties.map(property => docgen.utils.docblock.getDocblock(property));
// Get the property type info
paramsTypes = docgen.utils.getFlowType(paramsPath);
}
}
// Get the property type, description and value info
let values = [];
if (paramsTypes && paramsTypes.signature && paramsTypes.signature.properties &&
paramsTypes.signature.properties.length !== 0) {
values = paramsTypes.signature.properties.map((property, index) => {
return {
type: { names: [property.value.name] },
description: paramsDescriptions[index],
name: property.key,
};
});
}
let typedef = {
name: name,
description: description,
type: type,
values: values,
};
documentation.set('typedef', typedef);
}
function getTypeName(type) {
let typeName;
switch (type.name) {
case 'signature':
typeName = type.type;
break;
case 'union':
typeName = type.elements.map(getTypeName);
break;
default:
typeName = type.alias ? type.alias : type.name;
break;
}
return typeName;
}
function jsDocFormatType(entities) {
let modEntities = entities;
if (entities) {
if (typeof entities === 'object' && entities.length) {
entities.map((entity, entityIndex) => {
if (entity.type) {
const typeNames = [].concat(getTypeName(entity.type));
modEntities[entityIndex].type = { names: typeNames };
}
});
} else {
modEntities.type = [].concat(getTypeName(entities));
}
}
return modEntities;
}
function jsDocFormatHandler(documentation, path) {
const methods = documentation.get('methods');
if (!methods || methods.length === 0) {
return;
}
let modMethods = methods;
methods.map((method, methodIndex) => {
modMethods[methodIndex].params = jsDocFormatType(method.params);
modMethods[methodIndex].returns = jsDocFormatType(method.returns);
});
documentation.set('methods', modMethods);
}
function findExportedOrFirst(node, recast) {
return docgen.resolver.findExportedComponentDefinition(node, recast) ||
docgen.resolver.findAllComponentDefinitions(node, recast)[0];
}
function findExportedObject(ast, recast) {
var objPath;
let objPath;
recast.visit(ast, {
visitAssignmentExpression: function(path) {
if (!objPath && docgen.utils.isExportsOrModuleAssignment(path)) {
@@ -93,9 +184,9 @@ function findExportedObject(ast, recast) {
// handler.
// This converts any expression, e.g. `foo` to an object expression of
// the form `{propTypes: foo}`
var b = recast.types.builders;
var nt = recast.types.namedTypes;
var obj = objPath.node;
let b = recast.types.builders;
let nt = recast.types.namedTypes;
let obj = objPath.node;
// Hack: This is converting calls like
//
@@ -107,7 +198,7 @@ function findExportedObject(ast, recast) {
if (nt.CallExpression.check(obj) &&
recast.print(obj.callee).code === 'Object.assign') {
obj = objPath.node.arguments[1];
var firstArg = objPath.node.arguments[0];
let firstArg = objPath.node.arguments[0];
if (recast.print(firstArg.callee).code === 'Object.create') {
firstArg = firstArg.arguments[0];
}
@@ -123,7 +214,29 @@ function findExportedObject(ast, recast) {
return objPath;
}
function findExportedType(ast, recast) {
let types = recast.types.namedTypes;
let definitions;
recast.visit(ast, {
visitExportNamedDeclaration: function(path) {
if (path.node.declaration) {
if (types.TypeAlias.check(path.node.declaration)) {
if (!definitions) {
definitions = [];
}
definitions.push(path);
}
}
return false;
}
});
return definitions;
}
exports.stylePropTypeHandler = stylePropTypeHandler;
exports.deprecatedPropTypeHandler = deprecatedPropTypeHandler;
exports.typedefHandler = typedefHandler;
exports.jsDocFormatHandler = jsDocFormatHandler;
exports.findExportedOrFirst = findExportedOrFirst;
exports.findExportedObject = findExportedObject;
exports.findExportedType = findExportedType;
+237 -34
View File
@@ -15,6 +15,9 @@ const fs = require('fs');
const jsDocs = require('../jsdocs/jsdocs.js');
const path = require('path');
const slugify = require('../core/slugify');
const babel = require('babel-core');
const jsdocApi = require('jsdoc-api');
const deepAssign = require('deep-assign');
const ANDROID_SUFFIX = 'android';
const CROSS_SUFFIX = 'cross';
@@ -36,7 +39,9 @@ function removeExtName(filepath) {
function getNameFromPath(filepath) {
filepath = removeExtName(filepath);
if (filepath === 'LayoutPropTypes') {
return 'Flexbox';
return 'Layout Props';
} else if (filepath == 'ShadowPropTypesIOS') {
return 'Shadow Props';
} else if (filepath === 'TransformPropTypes') {
return 'Transforms';
} else if (filepath === 'TabBarItemIOS') {
@@ -58,8 +63,8 @@ function getPlatformFromPath(filepath) {
}
function getExamplePaths(componentName, componentPlatform) {
var componentExample = '../Examples/UIExplorer/' + componentName + 'Example.';
var pathsToCheck = [
const componentExample = '../Examples/UIExplorer/' + componentName + 'Example.';
let pathsToCheck = [
componentExample + 'js',
componentExample + componentPlatform + '.js',
];
@@ -69,7 +74,7 @@ function getExamplePaths(componentName, componentPlatform) {
componentExample + ANDROID_SUFFIX + '.js'
);
}
var paths = [];
let paths = [];
pathsToCheck.map((p) => {
if (fs.existsSync(p)) {
paths.push(p);
@@ -79,12 +84,12 @@ function getExamplePaths(componentName, componentPlatform) {
}
function getExamples(componentName, componentPlatform) {
var paths = getExamplePaths(componentName, componentPlatform);
const paths = getExamplePaths(componentName, componentPlatform);
if (paths) {
var examples = [];
let examples = [];
paths.map((p) => {
var platform = p.match(/Example\.(.*)\.js$/);
var title = '';
const platform = p.match(/Example\.(.*)\.js$/);
let title = '';
if ((componentPlatform === CROSS_SUFFIX) && (platform !== null)) {
title = platform[1].toUpperCase();
}
@@ -128,7 +133,7 @@ function filterMethods(method) {
// Determines whether a component should have a link to a runnable example
function isRunnable(componentName, componentPlatform) {
var paths = getExamplePaths(componentName, componentPlatform);
const paths = getExamplePaths(componentName, componentPlatform);
if (paths && paths.length > 0) {
return true;
} else {
@@ -156,9 +161,8 @@ function getNextComponent(idx) {
} else {
return getNextComponent(idx + 1);
}
} else {
return 'network';
}
return null;
}
function componentsToMarkdown(type, json, filepath, idx, styles) {
@@ -182,8 +186,8 @@ function componentsToMarkdown(type, json, filepath, idx, styles) {
json.methods = json.methods.filter(filterMethods);
}
// Put Flexbox into the Polyfills category
const category = (type === 'style' ? 'Polyfills' : type + 's');
// Put styles (e.g. Flexbox) into the API category
const category = (type === 'style' ? 'apis' : type + 's');
const next = getNextComponent(idx);
const res = [
@@ -206,37 +210,239 @@ function componentsToMarkdown(type, json, filepath, idx, styles) {
let componentCount;
function getTypedef(filepath, fileContent, json) {
let typedefDocgen;
try {
typedefDocgen = docgen.parse(
fileContent,
docgenHelpers.findExportedType,
[docgenHelpers.typedefHandler]
).map((type) => type.typedef);
} catch (e) {
// Ignore errors due to missing exported type definitions
if (e.message.indexOf(docgen.ERROR_MISSING_DEFINITION) !== -1) {
console.error('Cannot parse file', filepath, e);
}
}
if (!json) {
return typedefDocgen;
}
let typedef = typedefDocgen;
if (json.typedef && json.typedef.length !== 0) {
json.typedef.forEach(def => {
const typedefMatch = typedefDocgen.find(t => t.name === def.name);
if (typedefMatch) {
typedef.name = Object.assign(typedefMatch, def);
} else {
typedef.push(def);
}
});
}
return typedef;
}
function renderComponent(filepath) {
const fileContent = fs.readFileSync(filepath);
const json = docgen.parse(
fs.readFileSync(filepath),
fileContent,
docgenHelpers.findExportedOrFirst,
docgen.defaultHandlers.concat([
docgenHelpers.stylePropTypeHandler,
docgenHelpers.deprecatedPropTypeHandler,
docgenHelpers.jsDocFormatHandler,
])
);
json.typedef = getTypedef(filepath, fileContent);
return componentsToMarkdown('component', json, filepath, componentCount++, styleDocs);
}
function renderAPI(type) {
return function(filepath) {
let json;
try {
json = jsDocs(fs.readFileSync(filepath).toString());
} catch (e) {
console.error('Cannot parse file', filepath, e);
json = {};
}
return componentsToMarkdown(type, json, filepath, componentCount++);
function isJsDocFormat(fileContent) {
const reComment = /\/\*\*[\s\S]+?\*\//g;
const comments = fileContent.match(reComment);
if (!comments) {
return false;
}
return !!comments[0].match(/\s*\*\s+@jsdoc/);
}
function parseAPIJsDocFormat(filepath, fileContent) {
const fileName = path.basename(filepath);
const babelRC = {
'filename': fileName,
'sourceFileName': fileName,
'plugins': [
'transform-flow-strip-types',
'babel-plugin-syntax-trailing-function-commas',
]
};
// Babel transform
const code = babel.transform(fileContent, babelRC).code;
// Parse via jsdocs
let jsonParsed = jsdocApi.explainSync({
source: code,
configure: './jsdocs/jsdoc-conf.json'
});
// Cleanup jsdocs return
jsonParsed = jsonParsed.filter(i => {
return !i.undocumented && !/package|file/.test(i.kind);
});
jsonParsed = jsonParsed.map((identifier) => {
delete identifier.comment;
return identifier;
});
jsonParsed.forEach((identifier, index) => {
identifier.order = index;
});
// Group by "kind"
let json = {};
jsonParsed.forEach((identifier, index) => {
let kind = identifier.kind;
if (kind === 'function') {
kind = 'methods';
}
if (!json[kind]) {
json[kind] = [];
}
delete identifier.kind;
json[kind].push(identifier);
});
json.typedef = getTypedef(filepath, fileContent, json);
return json;
}
function parseAPIInferred(filepath, fileContent) {
let json;
try {
json = jsDocs(fileContent);
} catch (e) {
console.error('Cannot parse file', filepath, e);
json = {};
}
return json;
}
function getTypeName(type) {
let typeName;
switch (type.name) {
case 'signature':
typeName = type.type;
break;
case 'union':
typeName = type.value ?
type.value.map(getTypeName) :
type.elements.map(getTypeName);
break;
case 'enum':
if (typeof type.value === 'string') {
typeName = type.value;
} else {
typeName = 'enum';
}
break;
case '$Enum':
if (type.elements[0].signature.properties) {
typeName = type.elements[0].signature.properties.map(p => p.key);
}
break;
case 'arrayOf':
typeName = getTypeName(type.value);
break;
case 'instanceOf':
typeName = type.value;
break;
case 'func':
typeName = 'function';
break;
default:
typeName = type.alias ? type.alias : type.name;
break;
}
return typeName;
}
function getTypehintRec(typehint) {
if (typehint.type === 'simple') {
return typehint.value;
}
if (typehint.type === 'generic') {
return getTypehintRec(typehint.value[0]) +
'<' + getTypehintRec(typehint.value[1]) + '>';
}
return JSON.stringify(typehint);
}
function getTypehint(typehint) {
if (typeof typehint === 'object' && typehint.name) {
return getTypeName(typehint);
}
try {
var typehint = JSON.parse(typehint);
} catch (e) {
return typehint.toString().split('|').map(type => type.trim());
}
return getTypehintRec(typehint);
}
function getJsDocFormatType(entities) {
let modEntities = entities;
if (entities) {
if (typeof entities === 'object' && entities.length) {
entities.map((entity, entityIndex) => {
if (entity.typehint) {
const typeNames = [].concat(getTypehint(entity.typehint));
modEntities[entityIndex].type = { names: typeNames };
delete modEntities[entityIndex].typehint;
}
if (entity.name) {
const regexOptionalType = /\?$/;
if (regexOptionalType.test(entity.name)) {
modEntities[entityIndex].optional = true;
modEntities[entityIndex].name =
entity.name.replace(regexOptionalType, '');
}
}
});
} else {
const typeNames = [].concat(getTypehint(entities));
return { type: { names : typeNames } };
}
}
return modEntities;
}
function renderAPI(filepath, type) {
const fileContent = fs.readFileSync(filepath).toString();
let json = parseAPIInferred(filepath, fileContent);
if (isJsDocFormat(fileContent)) {
let jsonJsDoc = parseAPIJsDocFormat(filepath, fileContent);
// Combine method info with jsdoc fomatted content
const methods = json.methods;
if (methods && methods.length) {
let modMethods = methods;
methods.map((method, methodIndex) => {
modMethods[methodIndex].params = getJsDocFormatType(method.params);
modMethods[methodIndex].returns =
getJsDocFormatType(method.returntypehint);
delete modMethods[methodIndex].returntypehint;
});
json.methods = modMethods;
// Use deep Object.assign so duplicate properties are overwritten.
deepAssign(jsonJsDoc.methods, json.methods);
}
json = jsonJsDoc;
}
return componentsToMarkdown(type, json, filepath, componentCount++);
}
function renderStyle(filepath) {
const json = docgen.parse(
fs.readFileSync(filepath),
docgenHelpers.findExportedObject,
[docgen.handlers.propTypeHandler]
[
docgen.handlers.propTypeHandler,
docgen.handlers.propDocBlockHandler,
]
);
// Remove deprecated transform props from docs
@@ -297,6 +503,7 @@ const apis = [
'../Libraries/Components/Clipboard/Clipboard.js',
'../Libraries/Components/DatePickerAndroid/DatePickerAndroid.android.js',
'../Libraries/Utilities/Dimensions.js',
'../Libraries/Geolocation/Geolocation.js',
'../Libraries/Components/Intent/IntentAndroid.android.js',
'../Libraries/Interaction/InteractionManager.js',
'../Libraries/LayoutAnimation/LayoutAnimation.js',
@@ -327,14 +534,9 @@ const stylesForEmbed = [
'../Libraries/Image/ImageStylePropTypes.js',
];
const polyfills = [
'../Libraries/Geolocation/Geolocation.js',
];
const all = components
.concat(apis)
.concat(stylesWithPermalink)
.concat(polyfills);
.concat(stylesWithPermalink);
const styleDocs = stylesForEmbed.reduce(function(docs, filepath) {
docs[path.basename(filepath).replace(path.extname(filepath), '')] =
@@ -355,8 +557,9 @@ module.exports = function() {
componentCount = 0;
return [].concat(
components.map(renderComponent),
apis.map(renderAPI('api')),
stylesWithPermalink.map(renderStyle),
polyfills.map(renderAPI('Polyfill'))
apis.map((filepath) => {
return renderAPI(filepath, 'api');
}),
stylesWithPermalink.map(renderStyle)
);
};
+121 -22
View File
@@ -125,6 +125,33 @@ html * {
rendering-intent: auto;
}
.example-container {
position: relative;
}
.embedded-simulator, .embedded-simulator * {
box-sizing: border-box;
}
.embedded-simulator p {
text-align: center;
color: #999;
}
.embedded-simulator {
width: 210px;
position: absolute;
right: -200px;
top: 0;
}
@media screen and (max-width: 680px) {
.embedded-simulator {
position: relative;
right: 0;
}
}
.prism {
white-space: pre-wrap;
font-family: 'source-code-pro', Menlo, 'Courier New', Consolas, monospace;
@@ -377,7 +404,7 @@ h1:hover .hash-link, h2:hover .hash-link, h3:hover .hash-link, h4:hover .hash-li
}
.hero {
background: #05A5D1;
background: #2D2D2D;
padding: 50px 0;
color: #FDF3E7;
font-weight: 300;
@@ -1027,21 +1054,6 @@ small code, li code, p code {
text-decoration: none !important;
}
.column-left, .column-left * {
box-sizing: border-box;
}
.column-left p {
text-align: center;
color: #999;
}
.column-left {
float: left;
padding: 20px;
width: 210px;
}
/* Modal */
.modal-backdrop {
background: rgba(0,0,0,.4);
@@ -1225,6 +1237,23 @@ div[data-twttr-id] iframe {
margin-left: 20px;
}
.methodTitle {
font-weight: bold;
font-size: 24px;
color: #2F9C0A;
}
.compactProps .methodTitle {
font-size: 14px;
margin-bottom: 0;
margin-top: 0;
}
.compactProps .methodTitle div {
font-weight: normal;
margin-left: 20px;
}
.prop {
padding: 5px 10px;
}
@@ -1243,6 +1272,16 @@ div[data-twttr-id] iframe {
font-size: 13px;
}
.methodType {
font-weight: normal;
font-size: 24px;
}
.compactProps .methodType {
font-weight: normal;
font-size: 13px;
}
.platform {
background-color: hsl(198, 100%, 87%);
border-radius: 5px;
@@ -1326,15 +1365,10 @@ div[data-twttr-id] iframe {
@media only screen
and (min-device-width: 1024px) {
.showcase {
width: 20%;
width: 25%;
}
}
.showcase:hover {
text-decoration: none;
opacity: 0.8;
}
.showcase h3 {
margin-bottom: 0px;
line-height: 20px;
@@ -1545,3 +1579,68 @@ input#algolia-doc-search:focus {
background-color: hsl(198, 100%, 96%);
color: #3B3738;
}
.params, .props
{
border-spacing: 0;
border: 0;
border-collapse: collapse;
}
.params .name, .props .name, .name code {
color: #4D4E53;
}
.params td, .params th, .props td, .props th
{
border: 1px solid #ddd;
margin: 0px;
text-align: left;
vertical-align: top;
padding: 4px 6px;
display: table-cell;
}
.params thead tr, .props thead tr
{
background-color: hsl(198, 75%, 88%);
font-weight: bold;
}
.params .params thead tr, .props .props thead tr
{
background-color: #fff;
font-weight: bold;
}
.params th, .props th { border-right: 1px solid #aaa; }
.params thead .last, .props thead .last { border-right: 1px solid #ddd; }
.params td.description > div > p:first-child,
.props td.description > div > p:first-child
{
margin-top: 0;
padding-top: 0;
}
.params td.description > p:last-child,
.props td.description > p:last-child
{
margin-bottom: 0;
padding-bottom: 0;
}
/** Web player **/
.web-player > iframe, .web-player > .prism {
display: none;
}
.web-player.desktop > iframe {
display: block;
}
.web-player.mobile > .prism {
display: block;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 192 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

+55 -347
View File
@@ -19,399 +19,107 @@ var index = React.createClass({
<div className="wrap">
<div className="text"><strong>React Native</strong></div>
<div className="minitext">
A framework for building native apps using React
Learn once, write anywhere: Build mobile apps with React
</div>
</div>
</div>
<section className="content wrap">
<div style={{margin: '40px auto', maxWidth: 800}}>
<p>
React Native enables you to build world-class application experiences on native platforms using a consistent developer experience based on JavaScript and
{' '}<a href="http://facebook.github.io/react/" >React</a>{'. '}
The focus of React Native is on developer efficiency across all the platforms you care about &mdash; learn once, write anywhere.
Facebook uses React Native in multiple production apps and will continue investing in React Native.
</p>
</div>
<div className="buttons-unit">
<a href="docs/getting-started.html#content" className="button">Get started with React Native</a>
</div>
</div>
<section className="content wrap">
<div style={{margin: '40px auto', maxWidth: 800}}>
<h2>Native Components</h2>
<h2>Build Native Mobile Apps using JavaScript and React</h2>
<p>
With React Native, you can use the standard platform components such as UITabBar on iOS and Drawer on Android. This gives your app a consistent look and feel with the rest of the platform ecosystem, and keeps the quality bar high. These components are easily incorporated into your app using their React component counterparts, such as TabBarIOS and DrawerLayoutAndroid.
React Native lets you build mobile apps using only JavaScript. It uses the same design as React, letting you compose a rich mobile UI from declarative components.
</p>
<Prism>
{`// iOS
import React, {
Component,
} from 'react';
import {
TabBarIOS,
NavigatorIOS,
} from 'react-native';
{`import React, { Component } from 'react';
import { Text, View } from 'react-native';
class App extends Component {
class WhyReactNativeIsSoGreat extends Component {
render() {
return (
<TabBarIOS>
<TabBarIOS.Item title="React Native" selected={true}>
<NavigatorIOS initialRoute={{ title: 'React Native' }} />
</TabBarIOS.Item>
</TabBarIOS>
<View>
<Text>
If you like React on the web, you'll like React Native.
</Text>
<Text>
You just use native components like 'View' and 'Text',
instead of web components like 'div' and 'span'.
</Text>
</View>
);
}
}`}
</Prism>
<Prism>
{`// Android
import React, {
Component,
} from 'react';
import {
DrawerLayoutAndroid,
ProgressBarAndroid,
Text,
} from 'react-native';
class App extends Component {
render() {
return (
<DrawerLayoutAndroid
renderNavigationView={() => <Text>React Native</Text>}>
<ProgressBarAndroid />
</DrawerLayoutAndroid>
);
}
}`}
</Prism>
<h2>Asynchronous Execution</h2>
<h2>A React Native App is a Real Mobile App</h2>
<p>
All operations between the JavaScript application code and the native platform are performed asynchronously, and the native modules can also make use of additional threads as well. This means we can decode images off of the main thread, save to disk in the background, measure text and compute layouts without blocking the UI, and more. As a result, React Native apps are naturally fluid and responsive. The communication is also fully serializable, which allows us to leverage Chrome Developer Tools to debug the JavaScript while running the complete app, either in the simulator or on a physical device.
With React Native, you don't build a “mobile web app”, an “HTML5 app”, or a “hybrid app”. You build a real mobile app that's indistinguishable from an app built using Objective-C or Java. React Native uses the same fundamental UI building blocks as regular iOS and Android apps. You just put those building blocks together using JavaScript and React.
</p>
<p>
See <a href="docs/debugging.html#content">Debugging</a>.
</p>
<img src="img/chrome_breakpoint.png" width="800" height="443" />
<h2>Touch Handling</h2>
<p>
React Native implements a powerful system to negotiate touches in complex view hierarchies and provides high level components such as TouchableHighlight that integrate properly with scroll views and other elements without any additional configuration.
</p>
<Prism>
{`// iOS & Android
{`import React, { Component } from 'react';
import { Image, ScrollView, Text } from 'react-native';
import React, {
Component,
} from 'react';
import {
ScrollView,
TouchableHighlight,
Text,
} from 'react-native';
class TouchDemo extends Component {
class AwkwardScrollingImageWithText extends Component {
render() {
return (
<ScrollView>
<TouchableHighlight onPress={() => console.log('pressed')}>
<Text>Proper Touch Handling</Text>
</TouchableHighlight>
<Image source={{uri: 'https://i.chzbgr.com/full/7345954048/h7E2C65F9/'}} />
<Text>
On iOS, a React Native ScrollView uses a native UIScrollView.
On Android, it uses a native ScrollView.
On iOS, a React Native Image uses a native UIImageView.
On Android, it uses a native ImageView.
React Native wraps the fundamental native components, giving you
the performance of a native app, plus the clean design of React.
</Text>
</ScrollView>
);
}
}`}
</Prism>
<h2>Flexbox and Styling</h2>
<h2>Don't Waste Time Recompiling</h2>
<p>
Laying out views should be easy, which is why we brought the flexbox layout model from the web to React Native. Flexbox makes it simple to build the most common UI layouts, such as stacked and nested boxes with margin and padding. React Native also supports common web styles, such as fontWeight, and the StyleSheet abstraction provides an optimized mechanism to declare all your styles and layout right along with the components that use them and apply them inline.
React Native lets you build your app faster. Instead of recompiling, you can reload your app instantly. With hot reloading, you can even run new code while retaining your application state. Give it a try - it's a magical experience.
</p>
<br />
<img src='https://media.giphy.com/media/13WZniThXy0hSE/giphy.gif' />
<h2>Use Native Code When You Need To</h2>
<p>
React Native combines smoothly with components written in Objective-C, Java, or Swift. It's simple to drop down to native code if you need to optimize a few aspects of your application. It's also easy to build part of your app in React Native, and part of your app using native code directly - that's how the Facebook app works.
</p>
<Prism>
{`// iOS & Android
{`import React, { Component } from 'react';
import { Text, View } from 'react-native';
import { TheGreatestComponentInTheWorld } from './your-native-code';
import React, {
Component,
} from 'react';
import {
Image,
StyleSheet,
Text,
View,
} from 'react-native';
class ReactNative extends Component {
class SomethingFast extends Component {
render() {
return (
<View style={styles.row}>
<Image
source={{uri: 'http://facebook.github.io/react/img/logo_og.png'}}
style={styles.image}
/>
<View style={styles.text}>
<Text style={styles.title}>
React Native
</Text>
<Text style={styles.subtitle}>
Build high quality mobile apps using React
</Text>
</View>
<View>
<TheGreatestComponentInTheWorld />
<Text>
TheGreatestComponentInTheWorld could use native Objective-C,
Java, or Swift - the product development process is the same.
</Text>
</View>
);
}
}
var styles = StyleSheet.create({
row: { flexDirection: 'row', margin: 40 },
image: { width: 40, height: 40, marginRight: 10 },
text: { flex: 1, justifyContent: 'center'},
title: { fontSize: 11, fontWeight: 'bold' },
subtitle: { fontSize: 10 },
});`}
</Prism>
<h2>Polyfills</h2>
<p>
React Native is focused on changing the way view code is written. For the rest, we look to the web for universal standards and polyfill those APIs where appropriate. You can use npm to install JavaScript libraries that work on top of the functionality baked into React Native, such as XMLHttpRequest, window.requestAnimationFrame, and navigator.geolocation. We are working on expanding the available APIs, and are excited for the Open Source community to contribute as well.
</p>
<Prism>
{`// iOS & Android
import React, {
Component,
} from 'react';
import {
Text,
} from 'react-native';
class GeoInfo extends Component {
constructor(props) {
super(props);
this.state = { position: 'unknown' };
},
componentDidMount() {
navigator.geolocation.getCurrentPosition(
(position) => this.setState({position}),
(error) => console.error(error)
);
}
render() {
return (
<Text>
Position: {JSON.stringify(this.state.position)}
</Text>
);
}
}`}
</Prism>
<h2>Extensibility</h2>
<p>
It is certainly possible to create a great app using React Native without writing a single line of native code, but React Native is also designed to be easily extended with custom native views and modules - that means you can reuse anything you{"'"}ve already built, and can import and use your favorite native libraries.
</p>
<h3>Creating iOS modules</h3>
<p>
To create a simple iOS module, create a new class that implements the RCTBridgeModule protocol, and wrap the function that you want to make available to JavaScript in RCT_EXPORT_METHOD. Additionally, the class itself must be explicitly exported with RCT_EXPORT_MODULE();.
</p>
<Prism>
{`// Objective-C
#import "RCTBridgeModule.h"
@interface MyCustomModule : NSObject <RCTBridgeModule>
@end
@implementation MyCustomModule
RCT_EXPORT_MODULE();
// Available as NativeModules.MyCustomModule.processString
RCT_EXPORT_METHOD(processString:(NSString *)input callback:(RCTResponseSenderBlock)callback)
{
callback(@[[input stringByReplacingOccurrencesOfString:@"Goodbye" withString:@"Hello"]]);
}
@end`}
</Prism>
<Prism>
{`// JavaScript
import React, {
Component,
} from 'react';
import {
NativeModules,
Text,
} from 'react-native';
class Message extends Component {
constructor(props) {
super(props);
this.state = { text: 'Goodbye World.' };
}
componentDidMount() {
NativeModules.MyCustomModule.processString(this.state.text, (text) => {
this.setState({text});
});
}
render() {
return (
<Text>{this.state.text}</Text>
);
}
}`}
</Prism>
<h3>Creating iOS views</h3>
<p>
Custom iOS views can be exposed by subclassing RCTViewManager, implementing a -(UIView *)view method, and exporting properties with the RCT_EXPORT_VIEW_PROPERTY macro. Then a simple JavaScript file connects the dots.
</p>
<Prism>
{`// Objective-C
#import "RCTViewManager.h"
@interface MyCustomViewManager : RCTViewManager
@end
@implementation MyCustomViewManager
RCT_EXPORT_MODULE()
- (UIView *)view
{
return [[MyCustomView alloc] init];
}
RCT_EXPORT_VIEW_PROPERTY(myCustomProperty, NSString);
@end`}
</Prism>
<Prism>
{`// JavaScript
import React, {
Component,
} from 'react';
import {
requireNativeComponent,
} from 'react-native';
var NativeMyCustomView = requireNativeComponent('MyCustomView', MyCustomView);
export default class MyCustomView extends Component {
static propTypes = {
myCustomProperty: React.PropTypes.oneOf(['a', 'b']),
};
render() {
return <NativeMyCustomView {...this.props} />;
}
}
`}
</Prism>
<h3>Creating Android modules</h3>
<p>
Likewise, Android also supports custom extensions, the methods are just slightly different.
</p>
<p>
To create a simple module in Android, create a new class that extends the ReactContextBaseJavaModule class, and annotate the function that you want to make available to JavaScript with @ReactMethod. Additionally, the class itself must be registered in the ReactPackage of your React Native application.
</p>
<Prism>
{`// Java
public class MyCustomModule extends ReactContextBaseJavaModule {
// Available as NativeModules.MyCustomModule.processString
@ReactMethod
public void processString(String input, Callback callback) {
callback.invoke(input.replace("Goodbye", "Hello"));
}
}
`}
</Prism>
<Prism>
{`// JavaScript
import React, {
Component,
} from 'react';
import {
NativeModules,
Text,
} from 'react-native';
class Message extends Component {
constructor(props) {
super(props);
this.state = { text: 'Goodbye World.' };
},
componentDidMount() {
NativeModules.MyCustomModule.processString(this.state.text, (text) => {
this.setState({text});
});
}
render() {
return (
<Text>{this.state.text}</Text>
);
}
}
`}
</Prism>
<h3>Creating Android views</h3>
<p>
Custom Android views can be exposed by extending SimpleViewManager, implementing a createViewInstance and getName methods, and exporting properties with the @ReactProp annotation. Then a simple JavaScript file connects the dots.
</p>
<Prism>
{`// Java
public class MyCustomViewManager extends SimpleViewManager<MyCustomView> {
@Override
public String getName() {
return "MyCustomView";
}
@Override
protected MyCustomView createViewInstance(ThemedReactContext reactContext) {
return new MyCustomView(reactContext);
}
@ReactProp(name = "myCustomProperty")
public void setMyCustomProperty(MyCustomView view, String value) {
view.setMyCustomProperty(value);
}
}
`}
</Prism>
<Prism>
{`// JavaScript
import React, {
Component,
} from 'react';
import {
requireNativeComponent,
} from 'react-native';
var NativeMyCustomView = requireNativeComponent('MyCustomView', MyCustomView);
export default class MyCustomView extends Component {
static propTypes = {
myCustomProperty: React.PropTypes.oneOf(['a', 'b']),
};
render() {
return <NativeMyCustomView {...this.props} />;
}
}
`}
</Prism>
</div>
<section className="home-bottom-section">
<div className="buttons-unit">
+20 -1
View File
@@ -7,10 +7,29 @@
document.addEventListener('DOMContentLoaded', init);
function init() {
if (isMobile()) {
var mobile = isMobile();
if (mobile) {
document.querySelector('.nav-site-wrapper a[data-target]').addEventListener('click', toggleTarget);
}
var webPlayerList = document.querySelectorAll('.web-player');
// Either show interactive or static code block, depending on desktop or mobile
for (var i = 0; i < webPlayerList.length; ++i) {
webPlayerList[i].classList.add(mobile ? 'mobile' : 'desktop');
if (!mobile) {
// Determine location to look up required assets
var assetRoot = encodeURIComponent(document.location.origin + '/react-native');
// Set iframe src. Do this dynamically so the iframe never loads on mobile.
var iframe = webPlayerList[i].querySelector('iframe');
iframe.src = iframe.getAttribute('data-src') + '&assetRoot=' + assetRoot;
}
}
var backdrop = document.querySelector('.modal-backdrop');
if (!backdrop) return;
+11
View File
@@ -0,0 +1,11 @@
{
"title": "The Basics - Networking",
"description": "Your app fetched this from a remote endpoint!",
"movies": [
{ "title": "Star Wars", "releaseYear": "1977"},
{ "title": "Back to the Future", "releaseYear": "1985"},
{ "title": "The Matrix", "releaseYear": "1999"},
{ "title": "Inception", "releaseYear": "2010"},
{ "title": "Interstellar", "releaseYear": "2014"}
]
}
+141 -1048
View File
File diff suppressed because it is too large Load Diff
+12 -20
View File
@@ -29,38 +29,30 @@ var support = React.createClass({
<h1>Need help?</h1>
<div className="subHeader"></div>
<p>
<strong>React Native</strong> is worked on full-time by Facebook&#39;s
product infrastructure user interface
engineering teams. They&#39;re often around and available for
questions.
At Facebook, there are dozens of engineers who work on React Native full-time. But there are far more people in the community who make key contributions and fix things. So if you need help with your React Native app, the right place to go depends on the type of help that you need.
</p>
<H2>Community translation</H2>
<p>The following is a list of translated docs offered by community volunteers. Send a pull request to fill the list!</p>
<ul>
<li><a href="http://reactnative.cn">Chinese</a> (<a href="https://github.com/reactnativecn/react-native-docs-cn">source</a>)</li>
</ul>
<H2>Technical Questions</H2>
<p>If you're wondering how to solve a specific technical problem in React Native, the best place to ask is on Stack Overflow. You can check <a href="http://stackoverflow.com/questions/tagged/react-native">existing questions</a> tagged with react-native, <a href="http://stackoverflow.com/questions/ask">ask your own</a>, or just Google it and click on the Stack Overflow answer that will inevitably come up.</p>
<H2>Stack Overflow</H2>
<p>Many members of the community use Stack Overflow to ask questions. Read through the <a href="http://stackoverflow.com/questions/tagged/react-native">existing questions</a> tagged with <strong>react-native</strong> or <a href="http://stackoverflow.com/questions/ask">ask your own</a>!</p>
<H2>Random Questions</H2>
<p>If you have an open-ended question or you just want to get a general sense of what React Native folks talk about, check out the <a href="https://www.facebook.com/groups/react.native.community">React Native Community</a> Facebook group. It has thousands of developers and almost all posts get a response.</p>
<H2>Chat</H2>
<p>Join us in <strong><a href="https://discord.gg/0ZcbPKXt5bZjGY5n">#react-native on Reactiflux</a></strong>.</p>
<H2>Urgent Questions</H2>
<p>If you need an answer right away, check out #react-native on the <a href="https://discord.gg/0ZcbPKXt5bZjGY5n">Reactiflux chat</a>. There are usually a number of React Native experts there who can help out or point you to somewhere you might want to look.</p>
<H2>Product Pains</H2>
<p>React Native uses <a href="https://productpains.com/product/react-native/">Product Pains</a> for feature requests. It has a voting system to surface which issues are most important to the community. GitHub issues should only be used for bugs.</p>
<H2>Feature Requests</H2>
<p>React Native uses <a href="https://productpains.com/product/react-native/">Product Pains</a> for feature requests. It has a voting system to surface which issues are most important to the community. So if you have a feature request, add it or upvote a similar one.</p>
<iframe
width="100%"
height="600px"
scrolling="yes"
src="https://productpains.com/widget.html?token=3b929306-e0f7-5c94-7d7c-ecc05d059748"
/>
/>
<H2>Twitter</H2>
<p><a href="https://twitter.com/search?q=%23reactnative"><strong>#reactnative</strong> hash tag on Twitter</a> is used to keep up with the latest React Native news.</p>
<p><center><a className="twitter-timeline" data-dnt="true" data-chrome="nofooter noheader transparent" href="https://twitter.com/search?q=%23reactnative" data-widget-id="565960513457098753"></a></center></p>
<H2>Bug Reports</H2>
<p>If you have discovered a bug in React Native, keep in mind that it's an open source project. Take a look at the <a href="https://github.com/facebook/react-native/">code on GitHub</a>, and see if it's something you could fix yourself. If you don't think you can fix it yourself, you can file it as a GitHub issue. Be sure to providing a crisp description and reproduction of the bug, to improve the chance that someone will be able to help you out.</p>
</div>
</section>