└── Blog ├── React Native 组件的生命周期.md ├── iOS现有项目集成React Native.html └── iOS现有项目集成React Native.md /Blog/React Native 组件的生命周期.md: -------------------------------------------------------------------------------- 1 | # React Native 组件的生命周期 2 | 3 | 4 | > 本文的React Native版本为0.25 5 | 6 | ## 概述 7 | iOS开发中,我们知道视图控制器ViewController具有生命周期(Lifecycle)。同样React Native(RN)中的组件也具有生命周期。所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态。理解RN组件的生命周期,有助于我们更好地使用RN开发合理的功能。 8 | 9 | RN系统组件和我们自定义的组件基本上都会继承于react的Component,也就是基组件,类似于OC的NSObject类。从Component的源代码中我们能看到Component的生命周期函数主要包括以下几个: 10 | ![](http://ww2.sinaimg.cn/large/8bd0decfgw1f52mgacmcwj20kr053jtd.jpg) 11 | 12 | 这些函数的执行流程如下图: 13 | ![](http://ww4.sinaimg.cn/large/8bd0decfgw1f52mgt0ot3j20jv0ik0uv.jpg) 14 | 15 | React Native升级到ES6语法后,组件中还会有一个构造函数:constructor,我们一般在这个函数做一些初始化的工作。 16 | 17 | 上图中的生命周期可以分为三个阶段: 18 | 19 | * 第一阶段:组件的第一次绘制,完成了组件的加载和初始化 20 | * 第二阶段:组件的运行和交互,这里处理用户交互或接收事件更新界面。 21 | * 第三阶段:组件的卸载和消亡,可以做一些组件的清理工作 22 | 23 | ## 生命周期回调函数 24 | 25 | ### componentWillMount 26 | 组件创建后,在第一次绘制`render()`之前会调用`componentWillMount()`,可以在这里做一些业务初始化操作,也可以通过`setState`设置组件状态。这个函数在整个生命周期中只调用一次。 27 | 28 | ### componentDidMount 29 | 在组件第一次绘制以后,会调用`componentWillMount()`,通知组件已经加载完成。这个函数调用的时候,其虚拟 DOM 已经构建完成,你可以在这个函数开始获取其中的元素或者子组件了。需要注意的是,RN 框架是先调用子组件的 `componentDidMount()`,然后调用父组件的函数。从这个函数开始,就可以和 JS 其他框架交互了,例如设置计时 `setTimeout` 或者 `setInterval`,或者发起网络请求。这个函数也是只被调用一次。这个函数之后,就进入了稳定运行状态,等待事件触发。 30 | 31 | ### componentWillReceiveProps 32 | 如果组件收到新的属性(props),就会调用`componentWillReceiveProps()`,其原型如下: 33 | ``` 34 | void componentWillReceiveProps( 35 | object nextProps 36 | ) 37 | ``` 38 | 输入参数 `nextProps` 是即将被设置的属性,旧的属性还是可以通过 this.props 来获取。在这个回调函数里面,你可以根据属性的变化,通过调用 this.setState() 来更新你的组件状态,这里调用更新状态是安全的,并不会触发额外的 `render()` 调用。如下: 39 | 40 | ``` 41 | 42 | componentWillReceiveProps: function(nextProps) { 43 | this.setState({ 44 | likesIncreasing: nextProps.likeCount > this.props.likeCount 45 | }); 46 | } 47 | 48 | ``` 49 | ### shouldComponentUpdate 50 | 51 | 当组件接收到新的属性和状态改变的话,都会触发调用 `shouldComponentUpdate(...)`,函数原型如下: 52 | 53 | ``` 54 | boolean shouldComponentUpdate( 55 | object nextProps, object nextState 56 | ) 57 | ``` 58 | 输入参数 `nextProps` 和上面的 `componentWillReceiveProps` 函数一样,`nextState` 表示组件即将更新的状态值。这个函数的返回值决定是否需要更新组件,如果 `true` 表示需要更新,继续走后面的更新流程。否者,则不更新,直接进入等待状态。 59 | 60 | 默认情况下,这个函数永远返回 `true` 用来保证数据变化的时候 UI 能够同步更新。在大型项目中,你可以自己重载这个函数,通过检查变化前后属性和状态,来决定 UI 是否需要更新,能有效提高应用性能。 61 | 62 | ### componentWillUpdate 63 | 64 | 如果组件状态或者属性改变,并且上面的 `shouldComponentUpdate(...)` 返回为 `true`,就会开始准更新组件,并调用 `componentWillUpdate()`,其函数原型如下: 65 | 66 | ``` 67 | void componentWillUpdate( 68 | object nextProps, object nextState 69 | ) 70 | ``` 71 | 72 | 输入参数与 `shouldComponentUpdate` 一样,在这个回调中,可以做一些在更新界面之前要做的事情。需要特别注意的是,在这个函数里面,你就不能使用 `this.setState` 来修改状态。这个函数调用之后,就会把 `nextProps` 和 `nextState` 分别设置到 `this.props` 和 `this.state` 中。紧接着这个函数,就会调用 `render()` 来更新界面了。 73 | 74 | ### componentDidUpdate 75 | 76 | 调用了 `render()` 更新完成界面之后,会调用 `componentDidUpdate()` 来得到通知,其函数原型如下: 77 | 78 | ``` 79 | void componentDidUpdate( 80 | object prevProps, object prevState 81 | ) 82 | ``` 83 | 84 | 因为到这里已经完成了属性和状态的更新了,此函数的输入参数变成了 `prevProps` 和 `prevState`。 85 | 86 | ### componentWillUnmount 87 | 当组件要被从界面上移除的时候,就会调用 `componentWillUnmount()`,其函数原型如下: 88 | 89 | ``` 90 | void componentWillUnmount() 91 | ``` 92 | 在这个函数中,可以做一些组件相关的清理工作,例如取消计时器、网络请求等。 93 | 94 | > 参考文章:[http://www.race604.com/react-native-component-lifecycle/](http://www.race604.com/react-native-component-lifecycle/) 95 | 96 | -------------------------------------------------------------------------------- /Blog/iOS现有项目集成React Native.md: -------------------------------------------------------------------------------- 1 | ###iOS现有项目集成React Native 2 | ---- 3 | 4 | ####前提 5 | 已经配置好React Native命令行环境 6 | 7 | ####通过CocoaPods集成React Native 8 | 参考官方文档: 9 | http://reactnative.cn/docs/0.27/embedded-app-ios.html#content 10 | 11 | 使用CocoaPods集成会出现很多问题,下面重点讲一下如何在原有项目中手工快速集成React Native。 12 | 13 | #### 手工集成React Native 14 | 15 | ##### 第一步:初始化React Native环境 16 | 17 | 在我们要集成的项目中,进入到`*.xcodeproj`文件的上级目录,运行React Native初始化命令`react-native init [Project Name]` 18 | 会出现`prompt`, 输入`yes`,这样会在`ios`目录下生成一个同名工程。`init`过程会需要一点时间,耐心等待。 19 | 20 | ![](http://ww3.sinaimg.cn/large/8bd0decfgw1f51fs6b9vyj20n708j0vy.jpg) 21 | 22 | 完成后项目文件目录会变成这样: 23 | 24 | ![](http://ww1.sinaimg.cn/large/8bd0decfgw1f51fsxdrffj205t07oaai.jpg) 25 | 26 | * `node_modules`:react native依赖包 27 | * `ios`:iOS项目相关代码,Xcode工程文件 28 | * `android`:Android项目相关代码 29 | * `index.ios.js`:iOS平台加载的JS脚本 30 | * `index.android.js`:Android平台加载的JS脚本 31 | * `package.json`:当前项目的npm package的配置文件,内容如下: 32 | ``` 33 | { 34 | "private": true, 35 | "scripts": { 36 | "start": "node node_modules/react-native/local-cli/cli.js start" 37 | }, 38 | "name": "Project", 39 | "dependencies": { 40 | "react": "^15.1.0", 41 | "react-native": "^0.27.2" 42 | }, 43 | "version": "0.0.1" 44 | } 45 | ``` 46 | 接下来,我们可以先把Android相关的文件给干掉: 47 | * `android` 48 | * `index.android.js` 49 | * `node_modules/react-native/android` 50 | * `node_modules/react-native/ReactAndroid` 51 | 52 | ##### 第二步:添加React Native的Libraries 53 | 54 | 打开`ios`目录下的那个同名工程,可以看到这个工程引用的React Native库如下: 55 | 56 | ![](http://ww4.sinaimg.cn/large/8bd0decfgw1f4uk13ff3ij207y069js2.jpg) 57 | 58 | 打开我们原有的项目,右键工程目录,选择`New Group`,新建一个名为`Libraries`的目录 59 | 60 | 然后把前面项目`Libraries`下的`*.xcodeproj`文件全部拖到这个项目的`Libraries`下,效果跟上图一样。 61 | 62 | ##### 第三步:添加React Native shell脚本 63 | 64 | React Native的iOS项目在编译时会先运行一个shell脚本,其作用有两个: 65 | * 从Terminal启动了一个Node.js的server用于React Native调试 66 | * 将React Native的资源文件打包放在编译目录下 67 | 68 | 具体添加方式: 69 | * 选择`TARGETS`的`Build Phases`界面,点击左上角的`+`号 70 | ![](http://ww2.sinaimg.cn/large/8bd0decfgw1f51g3d62raj20p707cq45.jpg) 71 | * 选择`New Run Script Phase`添加一个脚本,并命名为`Bundle React Native code and images` 72 | * 把`ios`下工程中的脚本引用代码复制过来,如下图。注意路径,因为我们的原有的`*.xcodeproj`文件跟`node_modules`是在同一个目录下的,所以我们要去掉两个点中的一个点。 73 | ![](http://ww3.sinaimg.cn/large/8bd0decfgw1f4ukyiv2xfj20j2059jse.jpg) 74 | 75 | ##### 第四步:链接.a文件和添加搜索头文件的地址 76 | 到这一步,我们就可以干掉`ios`目录了,然后关闭原有的工程,再重新打开。 77 | 在工程的`Build Phases`界面的` Link Binary With Libraries`,点击 78 | 最下面的`+`号,可以看到在`Workspace`下多了很多`.a`文件,如下图,把它们全部添加进去。 79 | ![](http://ww4.sinaimg.cn/large/8bd0decfgw1f4ulgll4i7j20dp08dt9o.jpg) 80 | * 接下来还需要添加`React`的搜索头文件,在`TARGETS->Build Settings->Header Search Paths`中添加一条`$(SRCROOT)/node_modules/react-native/React`,选择`recursive`,如下图所示。 81 | 82 | ![](http://ww3.sinaimg.cn/large/8bd0decfgw1f51g6722ebj20r807v0uf.jpg) 83 | 84 | ##### 第五步:编译 85 | 86 | 我们先编译一下,会发现编译不通过,一堆报错。 87 | 原因是我们还没有导入`JavaScriptCore`库。因为React Native与原生的交互需要依赖于`JavaScriptCore.framework`。 88 | 再次编译,发现可以编译成功了。 89 | 90 | #### 测试运行React Native界面 91 | 92 | 在`AppDelegate.m`中的`didFinishLaunchingWithOptions:`方法中添加如下代码: 93 | 94 | ``` 95 | RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation 96 | moduleName:@"Project" 97 | initialProperties:nil 98 | launchOptions:launchOptions]; 99 | rootView.backgroundColor = [[UIColor alloc] initWithRed:1.0f green:1.0f blue:1.0f alpha:1]; 100 | 101 | self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; 102 | UIViewController *rootViewController = [UIViewController new]; 103 | rootViewController.view = rootView; 104 | self.window.rootViewController = rootViewController; 105 | [self.window makeKeyAndVisible]; 106 | ``` 107 | `CMD+R`运行,会看到如下界面: 108 | 109 | ![](http://ww2.sinaimg.cn/large/8bd0decfgw1f4us1odirnj207y0eh0sx.jpg) 110 | 111 | 至此,原有项目集成React Native大功告成。祝在React Native的世界中玩得开心! 112 | 113 | --------------------------------------------------------------------------------