{"id":15043432,"url":"https://github.com/unbug/react-native-train","last_synced_at":"2025-04-06T09:10:36.363Z","repository":{"id":148064870,"uuid":"62988803","full_name":"unbug/react-native-train","owner":"unbug","description":"I use this book to train my team, help them to know how to build React-native app in the right way.","archived":false,"fork":false,"pushed_at":"2019-06-07T10:38:32.000Z","size":9656,"stargazers_count":419,"open_issues_count":1,"forks_count":55,"subscribers_count":31,"default_branch":"master","last_synced_at":"2025-03-30T08:11:12.439Z","etag":null,"topics":["flux","react","react-native","react-router","reactjs","redux"],"latest_commit_sha":null,"homepage":"https://github.com/unbug/react-native-train/blob/master/README.md","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/unbug.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2016-07-10T08:10:53.000Z","updated_at":"2025-01-16T10:26:50.000Z","dependencies_parsed_at":"2023-04-05T18:18:54.706Z","dependency_job_id":null,"html_url":"https://github.com/unbug/react-native-train","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Freact-native-train","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Freact-native-train/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Freact-native-train/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/unbug%2Freact-native-train/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/unbug","download_url":"https://codeload.github.com/unbug/react-native-train/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247457803,"owners_count":20941906,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["flux","react","react-native","react-router","reactjs","redux"],"created_at":"2024-09-24T20:49:02.225Z","updated_at":"2025-04-06T09:10:36.336Z","avatar_url":"https://github.com/unbug.png","language":null,"readme":"# React Native Training\n\n![](QQ20160705-3.png)\n\nThe videos are here - [Udemy](https://www.udemy.com/react-native-train/?couponCode=LUCKY-0)\n\n![](QQ20160727-3.png)\n\nPlease [leave a message](https://www.gitbook.com/book/unbug/react-native-training/discussions) or twitter [@unbug](https://twitter.com/unbug) for further inquiries. Any help will be appreciated :\\)\n\n# Table of contents\n\n* [1 First look](#1-first-look)\n  * [1.1 Building an app in 5 minutes](#11-building-an-app-in-5-minutes)\n  * [1.2 How it works](#12-how-it-works)\n  * [1.3 Debug tools](#13-debug-tools)\n  * [1.4 DOCs \u0026 APIs](#14-docs--apis)\n  * [1.5 Resources](#15-resources)\n* [2 Components](#2-components)\n  * [2.1 Render \u0026 JSX](#21-render--jsx)\n  * [2.2 View, Text, Image, etc](#22-view-text-image-etc)\n  * [2.3 Lifecyle](#23-lifecyle)\n  * [2.4 Props \u0026 States](#24-props--states)\n  * [2.5 Events](#25-events)\n  * [2.6 Resources](#26-resources)\n* [3 Styles](#3-styles)\n  * [3.1 Flexbox](#31-flexbox)\n  * [3.2 Absolute \u0026 Relative](#32-absolute--relative)\n  * [3.3 Size \u0026 Dimensions \u0026 onLayout](#33-size--dimensions--onlayout)\n  * [3.4 Inheritance](#34-inheritance)\n  * [3.5 Resources](#35-resources)\n* [4 Architecture](#4-architecture)\n  * [4.1 Redux](#41-redux)\n  * [4.2 react-redux](#42-react-redux)\n  * [4.3 Containers \u0026 Components](#43-containers--components)\n  * [4.4 Todo React Native App](#44-todo-react-native-app)\n  * [4.5 Naming convention](#45-naming-convention)\n  * [4.6 Resources](#46-resources)\n* [5 Data](#5-data)\n  * [5.1 Fetch](#51-fetch)\n  * [5.2 Persistent](#52-persistent)\n  * [5.3 Resources](#53-resources)\n* [6 Router](#6-router)\n  * [6.1 Navigator](#61-navigator)\n  * [6.2 Resources](#62-resources)\n* [7 Native Modules \\(draft\\)](#7-native-modules)\n  * 7.1 iOS\n    * 7.1.1 JS call OC\n    * 7.1.2 OC call JS\n    * 7.1.3 Native View Component\n  * 7.2 Android\n    * 7.2.1 JS call Java\n    * 7.2.2 Java call JS\n    * 7.2.3 Native View Component\n  * 7.3 Resources\n* [8 Integration \\(draft\\)](#8-integration)\n  * [8.1 iOS](#81-ios)\n    * [8.1.1 Package](#811-package)\n    * 8.1.2 Image\n  * [8.2 Android](#82-android)\n    * [8.2.1 Package](#821-package)\n    * 8.2.2 Image\n  * [8.3 Before publishing](#83-before-publishing)\n  * [8.4 Resources](#83-resources)\n* [9 Hot Update \\(draft\\)](#9-hot-update-draf)\n  * 9.1 iOS\n  * 9.2 Android\n  * 9.3 Resources\n* [10 Performance \\(draft\\)](#10-performance)\n  * [10.1 shouldComponentUpdate](#101-shouldcomponentupdate)\n  * [10.2 Resources](#102-resources)\n* [Resources](#resources)\n\n---\n\n# 1 First Look\n\n[Introducing React Native](https://facebook.github.io/react/blog/2015/03/26/introducing-react-native.html)\n\n\u003e What we really want is the user experience of the native mobile platforms, combined with the developer experience we have when building with React on the web.  \n\u003e With a bit of work, we can make it so the exact same React that's on GitHub can power truly native mobile applications. The only difference in the mobile environment is that instead of running React in the browser and rendering to divs and spans, we run it an embedded instance of JavaScriptCore inside our apps and render to higher-level platform-specific components.  \n\u003e It's worth noting that we're not chasing **“write once, run anywhere.”** Different platforms have different looks, feels, and capabilities, and as such, we should still be developing discrete apps for each platform, but the same set of engineers should be able to build applications for whatever platform they choose, without needing to learn a fundamentally different set of technologies for each. We call this approach **“learn once, write anywhere.”**\n\n[Showcase](https://facebook.github.io/react-native/showcase.html)\n\n![](QQ20160630-4.png)\n\n# 1.1 Building an app in 5 minutes\n\n1. Requirement follow [Getting Started ](http://facebook.github.io/react-native/releases/next/docs/getting-started.html)\n2. Generate a new React Native project\n   ```shell\n   react-native init testRn\n   ```\n3. Build \u0026 run project\n\n   ```shell\n   react-native run-ios\n   ```\n\n   or open `testRn/ios/testRn.xcodeproj` and build with XCode's play button\n\n![](QQ20160622-0.png)\n\nor if the app already builded, start the webserver\n\n```shell\nnpm start\n//or\nreact-native start\n```\n\n# 1.2 How it works\n\n1.[JavaScript bridge](https://www.infoq.com/articles/react-native-introduction)\n\n![](21.jpg)\n\n2.[React Native Packager](https://github.com/facebook/react-native/tree/master/packager)\n\n![](Pasted Graphic.jpg)\n\n# 1.3 Debug tools\n\n1.[developer menu](https://facebook.github.io/react-native/docs/debugging.html)\n\n![](QQ20160623-0.png)\n\n2.Chrome Devtools\n\n![](QQ20160623-2.png)  \n3.log\n\n```shell\nconsole.log('some text');\nconsole.dir({a:1, b:2, c:3});\ndebugger;//breaking point\n```\n\n4.[Atom](https://atom.io/) \u0026 [nuclide](https://nuclide.io/)\n\n![](QQ20160623-3.png)\n\n5.inspect\n\nOpen Atom [Command Palette package](https://atom.io/packages/command-palette) with `cmd-shift-p` and search \"inspector\", then click \"Nuclide React Native Inspector:Show\"\n\n![](QQ20160624-0.png)\n\n![](QQ20160623-4.png)\n\n6.[Real device](https://facebook.github.io/react-native/docs/debugging.html#chrome-developer-tools)\n\n6.1 Deploy to real device  \n`project_name/ios/project_name/AppDelegate.m`\n\n```c\n  //jsCodeLocation = [NSURL URLWithString:@\"http://localhost:8081/index.ios.bundle?platform=ios\u0026dev=true\"];\n\n  /**\n   * OPTION 2\n   * Load from pre-bundled file on disk. The static bundle is automatically\n   * generated by the \"Bundle React Native code and images\" build step when\n   * running the project on an actual device or running the project on the\n   * simulator in the \"Release\" build configuration.\n   */\n\n   jsCodeLocation = [[NSBundle mainBundle] URLForResource:@\"main\" withExtension:@\"jsbundle\"];\n```\n\n6.2 Debug in real device\n\n1.`project_name/ios/project_name/AppDelegate.m`\n\n```c\n  jsCodeLocation = [NSURL URLWithString:@\"http://172.28.0.230:8081/index.ios.bundle?platform=ios\u0026dev=true\"];\n```\n\n2.`node_modules/react-native/Libraries/WebSocket/RCTWebSocketExecutor.m`\n\n```c\n  if (!_url) {\n    NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];\n    NSInteger port = [standardDefaults integerForKey:@\"websocket-executor-port\"] ?: 8081;\n    NSString *URLString = [NSString stringWithFormat:@\"http://172.28.0.230:%zd/debugger-proxy?role=client\", port];\n    _url = [RCTConvert NSURL:URLString];\n  }\n```\n\n3.\n\n![](QQ20160826-0.png)\n\n# 1.4 DOCs \u0026 APIs\n\n* [ReactJS](https://facebook.github.io/react/docs/getting-started.html)\n* [React Native](https://facebook.github.io/react-native/docs/getting-started.html)\n* [Nuclide](https://nuclide.io/docs/quick-start/getting-started/)\n\n# 1.5 Resources\n\n* [React Native: Bringing modern web techniques to mobile](https://code.facebook.com/posts/1014532261909640/react-native-bringing-modern-web-techniques-to-mobile/)\n* [React Native通信机制详解](http://blog.cnbang.net/tech/2698/)\n* [React Native 调研报告](http://blog.csdn.net/lihuiqwertyuiop/article/details/45241909)\n* [React Native概述：背景、规划和风险](https://github.com/tmallfe/tmallfe.github.io/issues/18)\n* [JavaScriptCore](http://trac.webkit.org/wiki/JavaScriptCore)\n* [React Native iOS 真机调试](http://www.jianshu.com/p/cc64bcb58df2)\n\n# 2 Components\n\n1.MyComponent.js\n\n```javascript\n//define component\nclass MyComponent extends React.Component {\n  render() {\n    return \u003cText\u003eMy component!\u003c/Text\u003e;\n  }\n}\n//export component\nexport default MyComponent;\n```\n\n2.Main.js\n\n```javascript\n//import component\nimport MyComponent from './MyComponent';\nclass Main extends React.Component {\n  render() {\n    //use component\n    return \u003cMyComponent\u003e;\n  }\n}\n```\n\n3.AppRegistry\n\n```javascript\nAppRegistry.registerComponent('MyApp', () =\u003e Main);\n```\n\n# 2.1 Render \u0026 JSX\n\n```javascript\n..\n...\nrender() {\n  const txt = 'Hello';\n  function say(name){\n    return 'I am '+name;\n  }\n  return (\n    \u003cView\u003e\n      \u003cText\u003eThis is a title!\u003c/Text\u003e\n      \u003cText\u003e{txt}\u003c/Text\u003e\n      \u003cView\u003e\n        \u003cText\u003e{say('React')}\u003c/Text\u003e\n      \u003c/View\u003e\n    \u003c/View\u003e\n  );\n}\n..\n...\n```\n\n# 2.2 View, Text, Image, etc\n\n1. [Core Components](https://facebook.github.io/react-native/docs/tutorial-core-components.html)\n\n```javascript\n..\n...\nimport {\n  StyleSheet,\n  Text,\n  View,\n  Image\n} from 'react-native';\n\nclass Main extends Component {\n  render() {\n    return (\n      \u003cView\u003e\n        \u003cImage source={require('./img/bg.png')}\u003e\n          \u003cImage source={require('./img/icon.png')}/\u003e\n          \u003cText\u003e\n            some text!\n          \u003c/Text\u003e\n        \u003c/Image\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n# 2.3 Lifecyle\n\n1. Instantiation\n\n   1.1 The lifecycle methods that are called the first time an instance is created\n\n   * getDefaultProps\n   * **getInitialState**\n   * componentWillMount\n   * **render**\n   * **componentDidMount**\n\n   1.2 For all subsequent uses of that component class:\n\n   * getInitialState\n   * componentWillMount\n   * render\n   * componentDidMount”\n\n2. Lifetime\n\n   * componentWillReceiveProps\n   * **shouldComponentUpdate // return true\\|false**\n     ```javascript\n     shouldComponentUpdate(nextProps, nextState) {\n     return nextProps.id !== this.props.id;\n     }\n     ```\n   * componentWillUpdate //not called for the initial render\n   * render\n   * componentDidUpdate\n\n3. Teardown \u0026 cleanup\n\n   * componentWillUnmount\n\n![](QQ20160627-0.png)\n\n# 2.4 Props \u0026 States\n\n1.props: properties are passed to a component and can hold any data\n\n```javascript\nclass User extends Component {\n  render(){\n    const user = this.props.data;\n    this.props.onReady('I am ready!');\n    return(\n      \u003cView\u003e\n        \u003cText\u003e\n          score: {this.props.score}\n          type: {this.props.type}\n          Name: {user.name}\n          Age: {user.age}\n        \u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n//dufaultProps\nUser.propTypes = { score: React.PropTypes.number };\nUser.defaultProps = { score: 0 };\n\nvar user = {name: 'foo', age: 21};\nclass Main extends Component {\n  handleReady(str){\n    console.log(str);\n  }\n  render(){\n    return(\n      \u003cView\u003e\n        \u003cUser type=\"Dev\" data={user} onReady={this.handleReady}/\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n2.state: State differs from props in that it is internal to the component.\n\n```javascript\nclass Timer extends Component {\n  constructor(props) {\n    super(props);\n    this.state = {count: 0};\n  }\n\n  componentDidMount() {\n    let that = this;\n    setInterval(function () {\n      that.increase();\n    }, 1000);\n  }\n\n  increase() {\n    this.setState({count: this.state.count + 1});\n  }\n\n  render() {\n    return (\n      \u003cView\u003e\n        \u003cText\u003ecount: {this.state.count}\u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n\nclass Main extends Component {\n  render(){\n    return(\n      \u003cView\u003e\n        \u003cTimer/\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n3._props_ VS _state_\n\n* Use props to pass data and settings through the component tree.\n* Never modify this.props inside of a component; consider props immutable.\n* Use props to for event handlers to communicate with child components.\n* Use state for storing simple view state like wether or not drop-down options are visible.\n* Never modify this.state directly, use this.setstate instead.\n\n![](QQ20160702-0.png)\n\n4.Stateless Component\n\n```javascript\nconst Heading = ({title}) =\u003e \u003cText\u003e{title}\u003c/Text\u003e;\n\n..\n...\n\u003cHeading title=\"test title\"/\u003e\n...\n..\n```\n\n# 2.5 Events\n\n1.Basic events\n\n1.1.[`\u003cTouchableHighlight/\u003e`](https://facebook.github.io/react-native/docs/touchablehighlight.html)\n\n```javascript\nclass Touch extends Component {\n  handlePress(){\n    console.log('press');\n  }\n  handleLongPress(){\n    console.log('longPress');\n  }\n  render() {\n    return (\n      \u003cTouchableHighlight\n        onPress={this.handlePress}\n        onLongPress={this.handleLongPress}\u003e\n        \u003cView\u003e\n          \u003cText\u003ePress me!\u003c/Text\u003e\n        \u003c/View\u003e\n      \u003c/TouchableHighlight\u003e\n    );\n  }\n}\n```\n\n1.2. [`\u003cTextInput/\u003e`](https://facebook.github.io/react-native/docs/textinput.html)\n\n```javascript\nclass Test extends Component {\n  //...\n  //handle events\n  //...\n  render() {\n    return (\n      \u003cTextInput \n        onBlur={...}\n        onChange={...}\n        onEndEditing={...}\n        onSelectionChange={...}\n        onSubmitEditing={...}\n      \u003c/TextInput\u003e\n    );\n  }\n}\n```\n\n1.3.[DeviceEventEmitter](https://kpetrovi.ch/2015/09/30/react-native-ios-keyboard-events.html)\n\n```javascript\n//keyboardWillShow, keyboardDidShow, keyboardWillHide, keyboardDidHide\n//keyboardWillChangeFrame, keyboardDidChangeFrame\n//add the listener\n var listener = DeviceEventEmitter.addListener('keyboardWillShow', (e) =\u003e{\n   console.log('Event is fired!');\n });\n //remove the listener\n listener.remove();\n```\n\n2.[Gesture Responder System](https://facebook.github.io/react-native/docs/gesture-responder-system.html#responder-lifecycle)\n\n2.1 Lifecycle  \n![](QQ20160630-2.png)  \n 2.2 example\n\n```javascript\nclass Test extends Component {\n  /* Capture handles */\n  //the responder system bubbles up from the deepest component, \n  //a parent View wants to prevent the child from becoming responder on a touch start\n  handleStartShouldSetResponderCapture(evt){\n    return true;\n  }\n  //the responder system bubbles up from the deepest component, \n  //a parent View wants to prevent the child from becoming responder on a touch move\n  handleMoveShouldSetResponderCapture(evt){\n    return true;\n  }\n\n  /* Lifecycle handles */\n  //Does this view want to become responder on the start of a touch?\n  handleStartShouldSetResponder(evt){\n    return true;\n  }\n  //Called for every touch move on the View when it is not the responder: \n  //does this view want to \"claim\" touch responsiveness?\n  handleMoveShouldSetResponder(evt){\n    return true;\n  }\n  //The View is now responding for touch events. \n  handleResponderGrant(evt){\n    console.log('you are touching me');\n  }\n  //Something else is the responder right now and will not release it\n  handleResponderReject(evt){\n    console.log('please wait in line');\n  }\n\n  /* event handles */\n  //touch move\n  handleResponderMove(evt){\n    console.log('touch move at:', 'X='+evt.pageX, 'Y='+evt.pageY);\n  }\n  //touch end/up\n  handleResponderRelease(evt){\n    console.log('touch end');\n  }\n  //Something else wants to become responder. Should this view release the responder?\n  handleResponderTerminationRequest(evt){\n    return true;\n  }\n  //touch cancel\n  handleResponderTerminate(evt){\n    console.log('touch canceled');\n  }\n  render() {\n    return (\n      \u003cView \n        onStartShouldSetResponderCapture={this.handleStartShouldSetResponderCapture}\n        onMoveShouldSetResponderCapture={this.handleMoveShouldSetResponderCapture}\n        onStartShouldSetResponder={this.handleStartShouldSetResponder}\n        onMoveShouldSetResponder={this.handleMoveShouldSetResponder}\n        onResponderGrant={this.handleResponderGrant} \n        onResponderReject={this.handleResponderReject}\n        onResponderMove={this.handleResponderMove}\n        onResponderRelease={this.handleResponderRelease}\n        onResponderTerminationRequest={this.handleResponderTerminationRequest}\n        onResponderTerminate={this.handleResponderTerminate}\u003e\n          \u003cText\u003ePress me!\u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n2.3 evt is a synthetic touch event with the following form nativeEvent:\n\n* changedTouches - Array of all touch events that have changed since the last event\n* identifier - The ID of the touch\n* locationX - The X position of the touch, relative to the element\n* locationY - The Y position of the touch, relative to the element\n* pageX - The X position of the touch, relative to the root element\n* pageY - The Y position of the touch, relative to the root element\n* target - The node id of the element receiving the touch event\n* timestamp - A time identifier for the touch, useful for velocity calculation\n* touches - Array of all current touches on the screen\n\n3.[PanResponder](https://facebook.github.io/react-native/docs/panresponder.html)\n\n3.1\n\n```javascript\nthis._panResponder = PanResponder.create({\n  // Ask to be the responder:\n  onStartShouldSetPanResponder: (evt, gestureState) =\u003e true,\n  onStartShouldSetPanResponderCapture: (evt, gestureState) =\u003e true,\n  onMoveShouldSetPanResponder: (evt, gestureState) =\u003e true,\n  onMoveShouldSetPanResponderCapture: (evt, gestureState) =\u003e true,\n  //touch start\n  onPanResponderGrant: (evt, gestureState) =\u003e {},\n  //touch move\n  onPanResponderMove: (evt, gestureState) =\u003e {},\n  onPanResponderTerminationRequest: (evt, gestureState) =\u003e true,\n  //touch end/up\n  onPanResponderRelease: (evt, gestureState) =\u003e {},\n  //touch cancel\n  onPanResponderTerminate: (evt, gestureState) =\u003e {},\n  onShouldBlockNativeResponder: (evt, gestureState) =\u003e true,\n});\n```\n\n3.2 A gestureState object has the following:\n\n* stateID - ID of the gestureState- persisted as long as there at least one touch on screen\n* moveX - the latest screen coordinates of the recently-moved touch\n* moveY - the latest screen coordinates of the recently-moved touch\n* x0 - the screen coordinates of the responder grant\n* y0 - the screen coordinates of the responder grant\n* dx - accumulated distance of the gesture since the touch started\n* dy - accumulated distance of the gesture since the touch started\n* vx - current velocity of the gesture\n* vy - current velocity of the gesture\n* numberActiveTouches - Number of touches currently on screen\n\n3.3 [PanResponder example in UIExplorer](https://github.com/facebook/react-native/blob/master/Examples/UIExplorer/PanResponderExample.js)\n\n# 2.6 Resources\n\n* [react.parts](https://react.parts/native)\n* [js.coach](https://js.coach/)\n* [props vs state](https://github.com/uberVU/react-guide/blob/master/props-vs-state.md)\n* [Thinking in React](https://facebook.github.io/react/docs/thinking-in-react.html)\n* [JSX in Depth](https://facebook.github.io/react/docs/jsx-in-depth.html)\n* [DEMO scripts for this chapter](https://github.com/unbug/react-native-train-scripts)\n\n# 3 Styles\n\n1.Declare Style\n\n```javascript\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    backgroundColor: 'blue',\n  },\n  text: {\n    fontSize: 14,\n    color: 'red'\n  }\n});\n```\n\n2.Using Styles\n\n```javascript\nclass Main extends Component {\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cText style={styles.text}\u003eI am red.\u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n3.Properties\n\n* [View Properties](https://facebook.github.io/react-native/docs/view.html#style)\n* [Image Properties](https://facebook.github.io/react-native/docs/image.html#style)\n* [Text Properties](https://facebook.github.io/react-native/docs/text.html#style)\n* [Flex Properties](https://facebook.github.io/react-native/docs/flexbox.html#content)\n* [Transform Properties](https://facebook.github.io/react-native/docs/transforms.html#content)\n\n# 3.1 Flexbox\n\n1.[Flexbox layout](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)\n\n\u003e The main idea behind the flex layout is to give the container the ability to alter its items' width/height \\(and order\\) to best fill the available space \\(mostly to accommodate to all kind of display devices and screen sizes\\). A flex container expands items to fill available free space, or shrinks them to prevent overflow.\n\n![](QQ20160705-15.png)\n\n2.flex:1\n\n![](QQ20160705-2.png)\n\n```javascript\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1\n  },\n  header: {\n    height: 200,\n    backgroundColor: 'red'\n  },\n  main: {\n    flex: 1,\n    backgroundColor: 'blue'\n  },\n  footer: {\n    height: 200,\n    backgroundColor: 'green'\n  },\n  text: {\n    color: '#ffffff',\n    fontSize: 80\n  }\n});\n```\n\n3.flexDirection:'row'\\|'column'\n\n![](QQ20160705-7.png)\n\n![](QQ20160705-8.png)\n\n4.justifyContent:'flex-start'\\|'flex-end'\\|'center'\\|'space-between'\\|'space-around'\n\n![](QQ20160705-10.png)\n\n5.alignItems:'flex-start'\\|'flex-end'\\|'center'\\|'stretch'\n\n![](QQ20160705-12.png)\n\n6.alignSelf:'auto'\\|'flex-start'\\|'flex-end'\\|'center'\\|'stretch'\n\n![](QQ20160705-13.png)\n\n7.flexWrap:'wrap'\\|'nowrap'\n\n![](QQ20160705-14.png)\n\n8.Box model\n\n![](QQ20160705-16.png)\n\nwidth = borderLeftWidth\\(25\\)+paddingLeft\\(25\\)+100+borderRightWidth\\(25\\)+paddingRight\\(25\\)=200\n\nheight = borderTopWidth\\(25\\)+paddingTop\\(25\\)+100+borderBottomWidth\\(25\\)+paddingBottom\\(25\\)=200\n\n```javascript\nclass Main extends Component {\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cView style={styles.header}\u003e\n          \u003cText style={styles.text}\u003e200X100\u003c/Text\u003e\n        \u003c/View\u003e\n        \u003cView style={styles.main}\u003e\n          \u003cView  style={styles.mainContent}\u003e\n            \u003cText style={styles.text}\u003e100X100\u003c/Text\u003e\n          \u003c/View\u003e\n        \u003c/View\u003e\n        \u003cView style={styles.footer}\u003e\n          \u003cText style={styles.text}\u003e200X100\u003c/Text\u003e\n        \u003c/View\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center'\n  },\n  header: {\n    height: 100,\n    width: 200,\n    backgroundColor: 'red'\n  },\n  main: {\n    height: 200,\n    width: 200,\n    padding: 25,\n    borderWidth: 25,\n    borderColor: 'black',\n    margin: 25,\n    backgroundColor: 'blue'\n  },\n  mainContent: {\n    flex: 1,\n    justifyContent: 'center',\n    alignItems: 'center',\n    backgroundColor: 'red'\n  },\n  footer: {\n    height: 100,\n    width: 200,\n    backgroundColor: 'green'\n  },\n  text: {\n    color: '#ffffff',\n    fontSize: 20\n  }\n});\n```\n\n![](QQ20160705-17.png)\n\n# 3.2 Absolute \u0026 Relative\n\n1.absolute\n\n![](QQ20160706-0.png)\n\n```javascript\nclass Position extends Component {\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cView style={styles.box1}\u003e\n          \u003cText style={styles.text}\u003e1\u003c/Text\u003e\n        \u003c/View\u003e\n        \u003cView style={styles.box2}\u003e\n          \u003cText style={styles.text}\u003e2\u003c/Text\u003e\n        \u003c/View\u003e\n        \u003cView style={styles.box3}\u003e\n          \u003cText style={styles.text}\u003e3\u003c/Text\u003e\n        \u003c/View\u003e\n      \u003c/View\u003e\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1\n  },\n  box1: {\n    position: 'absolute',\n    top: 40,\n    left: 40,\n    width: 100,\n    height: 100,\n    backgroundColor: 'red'\n  },\n  box2: {\n    position: 'absolute',\n    top: 80,\n    left: 80,\n    width: 100,\n    height: 100,\n    backgroundColor: 'blue'\n  },\n  box3: {\n    position: 'absolute',\n    top: 120,\n    left: 120,\n    width: 100,\n    height: 100,\n    backgroundColor: 'green'\n  },\n  text: {\n    color: '#ffffff',\n    fontSize: 80\n  }\n});\n```\n\n2.zIndex, [v0.29](https://github.com/facebook/react-native/commit/d64368b9e239b574039f4a6508bf2aeb0806121b) or [transform](http://facebook.github.io/react-native/docs/transforms.html)\n\n![](QQ20160706-2.png)\n\n```javascript\n  box2: {\n    position: 'absolute',\n    top: 80,\n    left: 80,\n    width: 100,\n    height: 100,\n    backgroundColor: 'blue',\n    transform: [{'translate': [0,0, 1]}]\n  },\n```\n\n3.relative\\(default\\)\n\n![](QQ20160706-1.png)\n\n```javascript\nclass Relative extends Component {\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cView style={styles.box1}\u003e\n          \u003cText style={styles.text}\u003e1\u003c/Text\u003e\n          \u003cView style={styles.ball}/\u003e\n        \u003c/View\u003e\n        \u003cView style={styles.box2}\u003e\n          \u003cText style={styles.text}\u003e2\u003c/Text\u003e\n        \u003c/View\u003e\n      \u003c/View\u003e\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1\n  },\n  box1: {\n    position: 'relative',\n    top: 40,\n    left: 40,\n    width: 100,\n    height: 100,\n    backgroundColor: 'red'\n  },\n  box2: {\n    position: 'absolute',\n    top: 100,\n    left: 100,\n    width: 100,\n    height: 100,\n    backgroundColor: 'blue'\n  },\n  ball: {\n    position: 'absolute',\n    top: 40,\n    left: 40,\n    width: 40,\n    height: 40,\n    borderRadius: 20,\n    backgroundColor: 'yellow'\n  },\n  text: {\n    color: '#ffffff',\n    fontSize: 80\n  }\n});\n```\n\n4.fixed\n\n![](QQ20160706-3.png)\n\n```javascript\nclass Fixed extends Component {\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cView style={styles.tbar}\u003e\n          \u003cText style={styles.text}\u003eFixed top bar\u003c/Text\u003e\n        \u003c/View\u003e\n        \u003cScrollView style={styles.main}\u003e\n          \u003cView style={styles.item}\u003e\u003cText style={styles.text}\u003e1\u003c/Text\u003e\u003c/View\u003e\n          \u003cView style={styles.item}\u003e\u003cText style={styles.text}\u003e2\u003c/Text\u003e\u003c/View\u003e\n          \u003cView style={styles.item}\u003e\u003cText style={styles.text}\u003e3\u003c/Text\u003e\u003c/View\u003e\n        \u003c/ScrollView\u003e\n        \u003cView style={styles.bbar}\u003e\n          \u003cText style={styles.text}\u003eFixed bottom bar\u003c/Text\u003e\n        \u003c/View\u003e\n      \u003c/View\u003e\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1\n  },\n  tbar: {\n    width: 375,\n    height: 100,\n    borderBottomWidth: 5,\n    borderColor: 'black',\n    backgroundColor: 'red'\n  },\n  main: {\n    flex: 1\n  },\n  item: {\n    height: 200,\n    width: 375,\n    marginTop: 10,\n    backgroundColor: 'green'\n  },\n  bbar: {\n    width: 375,\n    height: 100,\n    borderTopWidth: 5,\n    borderColor: 'black',\n    backgroundColor: 'red'\n  },\n  text: {\n    color: '#ffffff',\n    fontSize: 40\n  }\n});\n```\n\n# 3.3 Size \u0026 Dimensions \u0026 onLayout\n\n1.window size\n\n![](QQ20160706-4.png)\n\n```javascript\nlet winSize = Dimensions.get('window');\nconsole.log(winSize);\nclass Size extends Component {\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cView style={styles.block}/\u003e\n        \u003cText style={styles.text}\u003esome text\u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1,\n    alignItems: 'flex-start'\n  },\n  block: {\n    height: 100,\n    width: winSize.width,\n    backgroundColor: 'red'\n  },\n  text: {\n    color: '#ffffff',\n    fontSize: 40/winSize.scale,\n    backgroundColor: 'blue'\n  }\n});\n```\n\n2.[onLayout](http://facebook.github.io/react-native/releases/0.28/docs/view.html#onlayout)\n\n```javascript\nclass Size extends Component {\n  handleTextLayout(evt){\n    console.log(evt.nativeEvent.layout);\n  }\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cView style={styles.block}/\u003e\n        \u003cText style={styles.text}\n          onLayout={this.handleTextLayout}\u003esome text\u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n# 3.4 Inheritance\n\n1.pass styles as props\n\n```javascript\nclass InheritanceStyle extends Component {\n  render() {\n    return (\n      \u003cView style={this.props.parentColor}\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n\nclass Main extends Component {\n  handleReady(str){\n    console.log(str);\n  }\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cInheritanceStyle parentColor={styles.blue}/\u003e\n      \u003c/View\u003e\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  container: {\n    flex: 1\n  },\n  blue: {\n    flex: 1,\n    backgroundColor: 'blue'\n  }\n});\n```\n\n2.concatenation styles\n\nBaseStyles.js\n\n```javascript\nimport { StyleSheet,Dimensions } from 'react-native';\nlet winSize = Dimensions.get('window');\nconst BaseStyles = StyleSheet.create({\n  text: {\n    fontSize: 40/winSize.scale\n  }\n});\nexport default BaseStyles;\n```\n\n```javascript\nimport BaseStyles from './BaseStyles';\n\nclass InheritanceStyle extends Component {\n  render() {\n    return (\n      \u003cView style={this.props.parentColor}\u003e\n        \u003cText style={[BaseStyles.text, styles.text]}\u003e this is a long text \u003c/Text\u003e\n      \u003c/View\u003e\n    );\n  }\n}\nconst styles = StyleSheet.create({\n  text:{\n    color: '#ffffff'\n  }\n});\n```\n\n![](QQ20160706-5.png)\n\n# 3.5 Resources\n\n* [A Complete Guide to Flexbox](https://css-tricks.com/snippets/css/a-guide-to-flexbox/)\n* [A Visual Guide to CSS3 Flexbox Properties](https://scotch.io/tutorials/a-visual-guide-to-css3-flexbox-properties)\n* [Understanding Flex Direction](http://www.standardista.com/understanding-flex-direction/)\n* [DEMO scripts for this chapter](https://github.com/unbug/react-native-train-scripts)\n\n# 4 Architecture\n\n1.MVC problems\n\n![](QQ20160722-0.png)\n\n2.[Flux](http://facebook.github.io/flux/docs/overview.html)\n\n![](flux-diagram-white-background.png)  \n3.Data flow\n\n![](QQ20160719-1.png)\n\n[Flux TodoMVC Example](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/)\n\n# 4.1 Redux\n\n1.[Actions](https://github.com/acdlite/flux-standard-action) \u0026 Action Creators\n\n```javascript\n//action type\nconst ADD_TODO = 'ADD_TODO';\n\n//action creator, semantic methods that create actions\n//collected together in a module to become an API\nfunction addTodoAction(title, hour) {\n  //action, an object with a type property and new data, like events\n  return {type: ADD_TODO, title, hour}\n}\n```\n\n2.[Reducers](http://redux.js.org/docs/basics/Reducers.html)\n\n```javascript\n//a function that accepts an accumulation and a value and returns a new accumulation.\nfunction todoReducers(state = [], action) {\n  switch (action.type) {\n    case ADD_TODO:\n      //always return a new state, never mutate old state\n      return [\n        {\n          id: Utils.GUID(),\n          title: action.title,\n          endTime: getEndTime(action.hour),\n          completed: false\n        },\n        ...state\n      ]\n    default:\n      //return default state\n      return state\n  }\n}\n```\n\n3.Store\n\n```javascript\nimport { createStore } from 'redux';\n//1. define store\nlet store = createStore(todoReducers);\n\nclass App extends Component {\n  constructor(props){\n    super(props);\n    this.state = {todos: []};\n  }\n  componentDidMount(){\n    //2. subscribe store\n    this.unsubscribeStore = store.subscribe(() =\u003e{\n      //3. getState\n      this.setState({todos: store.getState()});\n    });\n  }\n  componentWillUnmount(){\n    //5. unsubscribe store\n    this.unsubscribeStore();\n  }\n  renderTodoList = ()=\u003e{\n    //reder todo list\n    return this.state.todos.map( (todo)=\u003e {\n      return \u003cText key={todo.id}\u003eTodo: {todo.title}\u003c/Text\u003e\n    });\n  }\n  handleAddTodo = ()=\u003e{\n    //4. dispatching actions\n    store.dispatch( addTodoAction('Create a new todo', 8) );\n  }\n  render() {\n    return (\n      \u003cView\u003e\n        \u003cTouchableHighlight onPress={this.handleAddTodo}\u003e\n          \u003cText\u003eAdd Todo\u003c/Text\u003e\n        \u003c/TouchableHighlight\u003e\n        \u003cScrollView\u003e{this.renderTodoList()}\u003c/ScrollView\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n```\n\n4.Data flow\n\n![](QQ20160724-0.png)\n\n![](QQ20160721-2.png)\n\n![](QQ20160721-3.png)\n\n# 4.2 [react-redux](https://github.com/reactjs/react-redux)\n\n1.Actions\n\n```javascript\nimport * as  navigationActions from './navigation';\nimport * as  todosActions from './todos';\n\nexport default {...navigationActions, ...todosActions};\n```\n\n2.combineReducers\\(\\)\n\n```javascript\nimport { combineReducers } from 'redux';\nimport navigation from './navigation';\nimport todos from './todos';\n\nconst rootReducer = combineReducers({\n  navigation, todos\n});\n\nexport default rootReducer;\n```\n\n3.Application state by configureStore\\(\\)\n\n```javascript\nimport { createStore } from 'redux';\nimport reducers from '../reducers';\n\nexport default function configureStore() {\n  const store = createStore(reducers);\n  return store;\n}\n```\n\n4.mapStateToProps \u0026 mapDispatchToProps \u0026 bindActionCreators\n\n```javascript\nimport { bindActionCreators } from 'redux';\nimport { connect } from 'react-redux';\n\nclass App extends Component {\n  renderTodoList = ()=\u003e{\n    //reder todo list\n    return this.props.todos.map( (todo)=\u003e {\n      return \u003cText key={todo.id}\u003eTodo: {todo.title}\u003c/Text\u003e\n    });\n  }\n  handleAddTodo = ()=\u003e{\n    this.props.actions.addTodoAction('Create a new todo', 8);\n  }\n  render() {\n    return (\n      \u003cView\u003e\n        \u003cTouchableHighlight onPress={this.handleAddTodo}\u003e\n          \u003cText\u003eAdd Todo\u003c/Text\u003e\n        \u003c/TouchableHighlight\u003e\n        \u003cScrollView\u003e{this.renderTodoList()}\u003c/ScrollView\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n\nfunction mapStateToProps(state) {\n  return {\n    todos: state.todos\n  };\n}\n\nfunction mapDispatchToProps(dispatch) {\n  return {\n    actions: bindActionCreators(Actions, dispatch)\n  }\n}\n\nexport default connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(App);\n```\n\n5.Passing the Store with `\u003cProvider/\u003e`\n\n```javascript\nimport React, { Component } from 'react';\nimport { Provider } from 'react-redux';\n\nimport App from './containers/App';\nimport configureStore from './store/configureStore';\n\nclass Root extends Component {\n  render() {\n    return (\n      \u003cProvider store={configureStore()}\u003e\n        \u003cApp /\u003e\n      \u003c/Provider\u003e\n    );\n  }\n}\n\nexport default Root;\n```\n\n# 4.3 Containers \u0026 Components\n\n1.[Presentational and Container Components](http://redux.js.org/docs/basics/UsageWithReact.html)\n\n\u003ctable\u003e\n    \u003cthead\u003e\n        \u003ctr\u003e\n            \u003cth\u003e\u003c/th\u003e\n            \u003cth scope=\"col\" style=\"text-align:left\"\u003ePresentational Components\u003c/th\u003e\n            \u003cth scope=\"col\" style=\"text-align:left\"\u003eContainer Components\u003c/th\u003e\n        \u003c/tr\u003e\n    \u003c/thead\u003e\n    \u003ctbody\u003e\n        \u003ctr\u003e\n          \u003cth scope=\"row\" style=\"text-align:right\"\u003ePurpose\u003c/th\u003e\n          \u003ctd\u003eHow things look (markup, styles)\u003c/td\u003e\n          \u003ctd\u003eHow things work (data fetching, state updates)\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n          \u003cth scope=\"row\" style=\"text-align:right\"\u003eAware of Redux\u003c/th\u003e\n          \u003ctd\u003eNo\u003c/th\u003e\n          \u003ctd\u003eYes\u003c/th\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n          \u003cth scope=\"row\" style=\"text-align:right\"\u003eTo read data\u003c/th\u003e\n          \u003ctd\u003eRead data from props\u003c/td\u003e\n          \u003ctd\u003eSubscribe to Redux state\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n          \u003cth scope=\"row\" style=\"text-align:right\"\u003eTo change data\u003c/th\u003e\n          \u003ctd\u003eInvoke callbacks from props\u003c/td\u003e\n          \u003ctd\u003eDispatch Redux actions\u003c/td\u003e\n        \u003c/tr\u003e\n        \u003ctr\u003e\n          \u003cth scope=\"row\" style=\"text-align:right\"\u003eAre written\u003c/th\u003e\n          \u003ctd\u003eBy hand\u003c/td\u003e\n          \u003ctd\u003eUsually generated by React Redux\u003c/td\u003e\n        \u003c/tr\u003e\n    \u003c/tbody\u003e\n\u003c/table\u003e\n\n2.`components/home-view` \u0026 `containers/HomeView`\n\n2.1 home-view components\n\n![](QQ20160721-1.png)\n\n2.2 HomeView container\n\n```javascript\nimport {\n  Header,\n  Main,\n} from '../components/home-view';\nimport Actions from '../actions';\n\nclass HomeView extends Component {\n  render() {\n    return (\n      \u003cView\u003e\n        \u003cHeader {...this.props}/\u003e\n        \u003cMain {...this.props} isVisible={this.state.isVisible}/\u003e\n      \u003c/View\u003e\n    );\n  }\n}\n\nfunction mapStateToProps(state) {\n  return {\n    todos: state.todos\n  };\n}\n\nfunction mapDispatchToProps(dispatch) {\n  return {\n    actions: bindActionCreators(Actions, dispatch)\n  }\n}\n\nexport default connect(\n  mapStateToProps,\n  mapDispatchToProps\n)(HomeView);\n```\n\n# 4.4 [Todo React Native App](https://github.com/unbug/TodoRN)\n\n1.Overview\n\n![](QQ20160722-1.png)\n\n2.Structure\n\n![](QQ20160721-8.png)\n\n3.Containers \u0026 Components\n\n![](QQ20160721-6.png)\n\n\n\n# 4.5 Naming convention\n\n1.Containers \u0026 Components\n\n1.1. Container file: \n```javascript\nsrc/containers/ModuleNameView.js\n```\nComponent files:\n\n```javascript\nsrc/components/module-name-view\n - index.js\n - Main.js\n - Header.js\n - ...\n - img\n   - icon@2x.png\n   - icon@3x.png\n```\n\n1.2. Event name: \n\n```javascript\nhandleEventName = ()=\u003e{//todo}\n...\n\u003cMyComponent onEventName={this.handleEventName}/\u003e\n```\n\n1.3. Render methods:\n\n```javascript\n  renderMethodName = () =\u003e {\n   //todo\n  }\n  render() {\n    return (\n      \u003cView\u003e\n        {this.renderMethodName()}\n      \u003c/View\u003e\n    );\n  }\n````\n1.4. mapStateToProps \u0026 mapDispatchToProps\n\n```javascript\nfunction mapStateToProps(state) {\n  return {\n    todos: state.todos\n  };\n}\n\nfunction mapDispatchToProps(dispatch) {\n  return {\n    actions: bindActionCreators(Actions, dispatch)\n  }\n}\n```\n\n2.actions ```src/actions```\n\n```\nindex.js\ntodos.js\nnavigation.js\n```\n\n2.1```src/constants/ActionTypes.js```\n\n```javascript\nexport const SWITCH_MAIN_TAB = 'SWITCH_MAIN_TAB';\n\n```\n2.2```src/actions/todos.js````\n```javascript\nimport * as types from '../constants/ActionTypes'\n\nexport function addTodo(title, hour) {\n  return {type: types.ADD_TODO, title, hour}\n}\n```\n\n3.reducers```src/reducers```\n```\nindex.js\ntodos.js\nnavigation.js\n```\n3.1.```src/reducers/todos.js```\n```javascript\nimport { ADD_TODO, DELETE_TODO, EDIT_TODO, COMPLETE_TODO } from '../constants/ActionTypes'\nconst initialState = []\n\nexport default function todos(state = initialState, action) {\n  switch (action.type) {\n    case ADD_TODO:\n      //todo\n    default:\n      return state\n  }\n}\n\n```\n4.styles```src/styles```\n\n```\nindex.js\nBasic.js\nTheme.js\n```\n4.1```src/styles/Basic.js```\n\n```javascript\nimport { StyleSheet, Dimensions } from 'react-native';\nlet winSize = Dimensions.get('window');\nconst Basic = StyleSheet.create({\n  text: {\n    fontSize: 32/winSize.scale\n  }\n});\nexport default Basic;\n\n```\n4.2```src/styles/Theme.js```\n\n```javascript\n//colors\nconst color = {\n  green: '#00551e',\n  brown: '#693504',\n  red: '#db2828'\n}\n\n//other\nconst active = {\n  opacity: 0.6\n}\n\nexport default {color, active}\n```\n4.3```import {Theme, BasicStyle} from '../../styles';```\n\n# 4.6 Resources\n- [Flux](http://facebook.github.io/flux/docs/overview.html)\n- [Facebook: MVC Does Not Scale, Use Flux Instead ](https://www.infoq.com/news/2014/05/facebook-mvc-flux)\n- [Redux](http://redux.js.org/index.html)\n- [fluxchat by Bill Fisher](https://speakerdeck.com/fisherwebdev/fluxchat)\n- [Introduce Flux \u0026 react in practices (KKBOX)](http://www.slideshare.net/randylien/introduce-flux-react-in-kkbox)\n- [react-flux-fluent-2015 by Bill Fisher](https://speakerdeck.com/fisherwebdev/react-flux-fluent-2015)\n- [Flux TodoMVC Example](https://github.com/facebook/flux/tree/master/examples/flux-todomvc)\n- [Todo React Native App](https://github.com/unbug/TodoRN)\n\n\n# 5 Data\n1.[Networking](http://facebook.github.io/react-native/releases/0.30/docs/network.html)\n - Fetch\n - XMLHttpRequest API\n - WebSocket\n\n\n# 5.1 Fetch\n\n1.apply [redux-thunk](https://github.com/gaearon/redux-thunk) middleware\n\n```javascript\nimport { applyMiddleware, createStore, compose } from 'redux';\nimport thunk from 'redux-thunk';\nimport createLogger from 'redux-logger';\nimport reducers from '../reducers';\n\nvar middlewares = compose(applyMiddleware(thunk), autoRehydrate());\n\nexport default function configureStore() {\n  const store = createStore(reducers, undefined, middlewares);\n  return store;\n}\n\n```\n\n2.start \u0026 end action types\n\n```javascript\n//todo action types\nexport const START_FETCH_ALL_TODOS = 'START_FETCH_ALL_TODOS';\nexport const FETCH_ALL_TODOS = 'FETCH_ALL_TODOS';\n```\n3.fetch flow\n```javascript\nimport * as types from '../constants/ActionTypes';\nimport * as APIs from '../constants/ServerAPIs';\n\n\nfunction shouldFetchAllTodos(state) {\n  const data = state.todos;\n  if (data \u0026\u0026 data.isFetchingAllTodos) {\n    return false\n  }\n  return true;\n}\n\nexport function fetchAllTodos() {\n  return async (dispatch, getState) =\u003e{\n    //verify\n    if(!shouldFetchAllTodos(getState())){\n      return Promise.resolve();\n    }\n\n    //dispatch fetch start action\n    dispatch({type: types.START_FETCH_ALL_TODOS});\n\n    //fetching\n    const response = await fetch(APIs.allTodos);\n    //response\n    const data = await response.json();\n\n    //dispatch fetch end action\n    return dispatch({\n      type: types.FETCH_ALL_TODOS,\n      data\n    });\n  }\n}\n```\n\n4.reducer\n\n```javascript\nexport default function todos(state = initialState, action) {\n  switch (action.type) {\n    case types.START_FETCH_ALL_TODOS:\n      return Object.assign({}, state, {isFetchingAllTodos: true});\n\n    case types.FETCH_ALL_TODOS:\n      return Object.assign({}, state, {\n        isFetchingAllTodos: false,\n        data: action.data.data.reduce(function (pre, cur) {\n          //remove duplicates\n          !pre.find( key=\u003e key.id===cur.id) \u0026\u0026 pre.push(cur);\n          return pre;\n        }, [...state.data])\n      });\n    ...\n    ...\n    default:\n      return state\n  }\n}\n```\n5.dispatch \u0026 render\n\n```javascript\n...\n  componentDidMount(){\n    //fetch data from server\n    this.props.actions.fetchAllTodos();\n  }\n...\n...\n  renderLoading = () =\u003e {\n    if (this.props.todos.isFetchingAllTodos) {\n      return (\n        \u003cView style={styles.loading}\u003e\n          \u003cText style={styles.loadingText}\u003eLoading...\u003c/Text\u003e\n        \u003c/View\u003e\n      )\n    }\n    return null;\n  }\n...\n```\n\n![](QQ20160726-2.png)\n\n\n# 5.2 Persistent\n\n1.[AsyncStorage](https://facebook.github.io/react-native/docs/asyncstorage.html)\n\n2.apply [redux-persist](https://github.com/rt2zz/redux-persist) middlewear\n\n```javascript\nimport { AsyncStorage } from 'react-native';\nimport { applyMiddleware, createStore, compose } from 'redux';\nimport thunk from 'redux-thunk';\nimport {persistStore, autoRehydrate} from 'redux-persist';\nimport reducers from '../reducers';\n\nvar middlewares = compose(applyMiddleware(thunk), autoRehydrate());\n\nexport default function configureStore() {\n  const store = createStore(reducers, undefined, middlewares);\n  persistStore(store, {storage: AsyncStorage});\n  return store;\n}\n\n```\n\n# 5.3 Resources\n\n - [Redux Async Actions](http://redux.js.org/docs/advanced/AsyncActions.html)\n - [Todo React Native App](https://github.com/unbug/TodoRN)\n \n # 6 Router\n\n - [NavigatorIOS](https://facebook.github.io/react-native/docs/navigatorios.html)\n - [Navigator](https://facebook.github.io/react-native/docs/navigator.html)\n \n \n # 6.1 Navigator\n\n1.define routes\n\n```javascript\n\nimport MainTabsView from './MainTabsView';\nimport EditView from './EditView';\nimport BroswerView from './BroswerView';\n\nconst ROUTES = { MainTabsView,  BroswerView, EditView };\n```\n\n2.config Navigator\n\n```javascript\nclass App extends Component {\n  renderScene = (route, navigator) =\u003e {\n    let Scene = ROUTES[route.name];\n    return \u003cScene {...route} navigator={navigator}/\u003e;\n  }\n  configureScene = (route, routeStack) =\u003e {\n    switch (route.name){\n      case 'EditView':\n        return Navigator.SceneConfigs.FloatFromBottom;\n      default:\n        return Navigator.SceneConfigs.PushFromRight;\n    }\n  }\n  render() {\n    return (\n      \u003cView style={styles.container}\u003e\n        \u003cStatusBar barStyle=\"light-content\"/\u003e\n        \u003cNavigator\n          initialRoute={{name: 'MainTabsView'}}\n          renderScene={this.renderScene}\n          configureScene={this.configureScene}/\u003e\n      \u003c/View\u003e\n    )\n  }\n}\n```\n\n3.forward \u0026 back\n\n![](QQ20160727-2.png)\n\n\n\n```javascript\n...\n  handleEdit = ()=\u003e{\n    //Navigate forward to a new scene\n    this.props.navigator.push({name: 'EditView', data: this.props.data});\n  }\n...\n```\n\n```javascript\n...\n  close = ()=\u003e{\n    //Transition back and unmount the current scene\n    this.props.navigator.pop();\n  }\n...\n```\n![](QQ20160727-1.png)\n\n\n4.onDidFocus \u0026 onWillFocus\n\n```javascript\n...\ncomponentDidMount(){\n    this.currentRoute = this.props.navigator.navigationContext.currentRoute;\n    this.bindEvents();\n  }\n  componentWillUnmount(){\n    this.unBindEvents();\n  }\n  bindEvents = ()=\u003e{\n    this.willFocusSubscription  = this.props.navigator.navigationContext.addListener('willfocus', (event) =\u003e {\n      if (this.currentRoute !== event.data.route) {\n        this.setState({isVisible: false});\n      }\n    });\n    this.didFocusSubscription  = this.props.navigator.navigationContext.addListener('didfocus', (event) =\u003e {\n      if (this.currentRoute === event.data.route) {\n        this.setState({isVisible: true});\n      }\n    });\n  }\n  unBindEvents = ()=\u003e{\n    this.willFocusSubscription.remove();\n    this.didFocusSubscription.remove();\n  }\n...\n```\n\n# 6.2 Resources\n\n- [Routing and Navigation in React Native](http://blog.paracode.com/2016/01/05/routing-and-navigation-in-react-native/)\n\n\n# 7 Native Modules\n\nSomewhere in your RN codes, insert: \n\n```console.log(__fbBatchedBridge);```\n\nthen in your debugger (http://localhost:8081/debugger-ui) you'll see something like below,\n\n![](native_modules_screenshot.png)\nthat's what we're going to talk about in this chapter.\n\n\n# 8 Integration\n\nMost of the time we are not starting a new app, we just want to use react-native to develop some new features, so integration should be a necessary skill for react-native developers.\n\nAssume that you have create some features in the AwesomeProject, you want to create an exactly same environment for your current project.\n\n![](integrationdemo.png)\n\n**Notice that** version is very important after your app published. If you want to upgrade react-native and package codes, that almost means you don't want to maintain the old version any longer. \n\n\n# 8.1 iOS\n\n- \n## Cocoapods with local path\n\n    Requirement : [CocoaPods](https://cocoapods.org/) \n\n    After pod **version \u003e 1.0**, you need to identify the target. Create 'Podfile' in project root folder :\n    ```\n target 'MyiOSApp' do \n\tpod 'React', :path =\u003e '../../AwesomeProject/node_modules/react-native', :subspecs =\u003e [\n  \t  'Core',\n  \t  'RCTImage',\n  \t  'RCTNetwork',\n  \t  'RCTText',\n  \t  'RCTWebSocket',\n\t]\n  end\n    ```\n    \n  then ```pod install```\n  \n  ![](pod_integration.png)\n  \n\n# 8.1.1 Package\n\n```\nreact-native bundle \n--platform ios \n--dev false \n--entry-file index.ios.js \n--bundle-output ios/bundle/index.ios.bundle \n--assets-dest ios/bundle```\n \n \n # 8.2 Android\n\nAt first I followed the official instruction (which seems very simple) but lots of build or runtime\nerror occurs 😂.\n\nSuch as:\n\n``` Can't find variable: __fbBatchedBridge (\u003cunknown file\u003e:1)```\n\n```java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so```\n\n```android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@5d992cf -- permission denied for this window type```\n\nBut the demo works corrcetly, so I decided to copy the build settings of it. And finally it works normally on my Nexus 5X. Steps:\n\n- Add the path to the root gradle file,\n![](integration_android_step11.png)\n\n- Modify the app gradle file,\n![](integration_android_step22.png)\n\n    *1. Official demo use this variable to control wheather building different apps for cpus, that will reduce the size of each app, I just ignore it here.\n\n    *2. The version support package matters..\nAs react-native Android use many open source projects, if you use some of them already, you should check the version or exclude the from dependencies.  [The list currently](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle) \n\n    ```\n    compile 'com.android.support:appcompat-v7:23.0.1'\n    compile 'com.android.support:recyclerview-v7:23.0.1'\n    compile 'com.facebook.fresco:fresco:0.11.0'\n    compile 'com.facebook.fresco:imagepipeline-okhttp3:0.11.0'\n    compile 'com.fasterxml.jackson.core:jackson-core:2.2.3'\n    compile 'com.google.code.findbugs:jsr305:3.0.0'\n    compile 'com.squareup.okhttp3:okhttp:3.2.0'\n    compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'\n    compile 'com.squareup.okhttp3:okhttp-ws:3.2.0'\n    compile 'com.squareup.okio:okio:1.8.0'\n    compile 'org.webkit:android-jsc:r174650'\n```\n- Modify root gradle.properties,\n![](integration_android_step3.png)\n\n- Add proguard rules,\n![](integration_android_step4.png)\n\n- AndroidManifest.xml, you can remove the permission if you don't need debug mode.\n![](integration_android_step5.png)\n\n\n# 8.2 Android\n\nAt first I followed the official instruction (which seems very simple) but lots of build or runtime\nerror occurs 😂.\n\nSuch as:\n\n``` Can't find variable: __fbBatchedBridge (\u003cunknown file\u003e:1)```\n\n```java.lang.UnsatisfiedLinkError: could find DSO to load: libreactnativejni.so```\n\n```android.view.WindowManager$BadTokenException: Unable to add window android.view.ViewRootImpl$W@5d992cf -- permission denied for this window type```\n\nBut the demo works corrcetly, so I decided to copy the build settings of it. And finally it works normally on my Nexus 5X. Steps:\n\n- Add the path to the root gradle file,\n![](integration_android_step11.png)\n\n- Modify the app gradle file,\n![](integration_android_step22.png)\n\n    *1. Official demo use this variable to control wheather building different apps for cpus, that will reduce the size of each app, I just ignore it here.\n\n    *2. The version support package matters..\nAs react-native Android use many open source projects, if you use some of them already, you should check the version or exclude the from dependencies.  [The list currently](https://github.com/facebook/react-native/blob/master/ReactAndroid/build.gradle) \n```\n    compile 'com.android.support:appcompat-v7:23.0.1'\n    compile 'com.android.support:recyclerview-v7:23.0.1'\n    compile 'com.facebook.fresco:fresco:0.11.0'\n    compile 'com.facebook.fresco:imagepipeline-okhttp3:0.11.0'\n    compile 'com.fasterxml.jackson.core:jackson-core:2.2.3'\n    compile 'com.google.code.findbugs:jsr305:3.0.0'\n    compile 'com.squareup.okhttp3:okhttp:3.2.0'\n    compile 'com.squareup.okhttp3:okhttp-urlconnection:3.2.0'\n    compile 'com.squareup.okhttp3:okhttp-ws:3.2.0'\n    compile 'com.squareup.okio:okio:1.8.0'\n    compile 'org.webkit:android-jsc:r174650'\n```\n- Modify root gradle.properties,\n![](integration_android_step3.png)\n\n- Add proguard rules,\n![](integration_android_step4.png)\n\n- AndroidManifest.xml, you can remove the permission if you don't need debug mode.\n![](integration_android_step5.png)\n\n\n# 8.2.1 Package\n\n```\nreact-native bundle \n--platform android \n--dev false \n--entry-file index.android.js \n--bundle-output android/bundle/index.android.bundle \n--assets-dest android/bundle/\n```\n\n# 8.3 Before publishing\n\n- Turn off debug Settings. \n- Implementation of exception handler.\n\n\n# 8.3 Resources\n \n - [Integrating with Existing Apps - iOS](https://facebook.github.io/react-native/docs/embedded-app-ios.html) \n - [Integrating with Existing Apps - Android](https://facebook.github.io/react-native/docs/embedded-app-android.html)\n \n\n# 9 Hot Update (draf)\n\n# 10 Performance\n\n# 10.1 shouldComponentUpdate\n\n\nThis chapter can be applied to all react apps.\n## shouldComponentUpdate\n\nReact is usually fast, but you still can improve performance by optimizing function [shouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate). By default it returns true, if returns false, the render function will be skipped.\n\nThis function is frequently invoked when states or props are changed. So it's important to **keep it simple and fast**.\nWhen you called `setState`, the `render` function will always be excuted even if previous states are equal to current. This is where we can make some optimization.\n\n[demo1](https://jsbin.com/figuse/edit?html,js,output)\n\nIn demo1, when click button, it will set same state, but render times will still increase.\n\n[demo2](http://jsbin.com/culipes/5/edit?html,js,output)\n\nIn demo2, we check the value of name is equal to before or not, if equal return false, then we reduce the times of render function.\n\nBut if our states structure is complicated, such as `{ a: { b: { c: [1, 2, 3] }}}`, we have to compare them deeply. This is obviously against the rules we mentioned above, ** keep shouldComponentUpdate simple**\n\n\n## Immutable-js\n[Immutable](https://en.wikipedia.org/wiki/Immutable_object) is a concept from [functional programming](https://en.wikipedia.org/wiki/Functional_programming), one of immutable data features is that it can not be modified after being created. So there are some algorithm to create hash for every data structure(for more [detail](https://en.wikipedia.org/wiki/Persistent_data_structure)).\nWe can use this feature to prevent deeply compare, shallow compare is enough.\nHere we will use [immutable-js](https://facebook.github.io/immutable-js/) from facebook\n\n[demo3](http://jsbin.com/vofubiy/8/edit?html,js,output)\n\nIn demo3, we click first button several times, times will only plus one time, click second button , times will increase.\n\n# 10.2 Resources\n - [React.js Reconciliation](https://www.infoq.com/presentations/react-reconciliation)\n - [Reconciliation](https://facebook.github.io/react/docs/reconciliation.html)\n - [Advanced Performance](https://facebook.github.io/react/docs/advanced-performance.html)\n - [Immutable-js](https://facebook.github.io/immutable-js/)\n - [ShouldComponentUpdate](https://facebook.github.io/react/docs/component-specs.html#updating-shouldcomponentupdate)\n - [Functional Programming](https://en.wikipedia.org/wiki/Functional_programming)\n\n\n# Resources\n\n- [ReactJS](https://facebook.github.io/react/)\n- [React Native](https://facebook.github.io/react-native/)\n- [awesome-react](https://github.com/enaqx/awesome-react)\n- [awesome-react-native](https://github.com/jondot/awesome-react-native)\n- [build with react](http://buildwithreact.com/)\n\n### Books\n - [Learning React Native](http://shop.oreilly.com/product/0636920041511.do)\n - [Developing a React Edge](http://shop.oreilly.com/product/9781939902122.do)\n---\n\n## Created by [@unbug](https://twitter.com/unbug):\n\n* [MIHTool - iOS Web Debugger Pro](https://www.mihtool.com): MIHTool helps Front-End Engineers to debug and optimize their webpages on iPad and iPhone.\n* [Codelf - 变量命名神器](https://unbug.github.io/codelf/): Organize your GitHub stars and repositories. Search over projects from GitHub to find real-world usage variable names.\n* [js-middleware](https://github.com/unbug/js-middleware): Powerful Javascript Middleware Pattern implementation, apply middleweares to any object. A painless solution to make codes as scalable and maintainable as ReduxJS and ExpressJS.\n* [SAY NO TO SUICIDE PUBLIC LICENSE](https://github.com/unbug/snts): We've lost so many genius developers, who committed suicide, such as Aaron Hillel Swartz \\(November 8, 1986 – January 11, 2013\\). As a developer, the community needs you, the world needs you, please keep yourself alive.\n\n\n\n","funding_links":[],"categories":["Others"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funbug%2Freact-native-train","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Funbug%2Freact-native-train","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Funbug%2Freact-native-train/lists"}