react native 研究

一、React Native所做的工作


1)更新DOM 

    只更新不读取。 


2)响应事件 

    响应事件,状态变化,告知渲染。 

二、React Native的优点与缺点


1、优点: 

    1)最后生成原生应用,交互和性能优于Webview。 

    2)有标准组件,可以自由组合。 

    3)支持Native原生动画。 

    4)通过更新远端JS,直接更新APP。 

    5)缓解移动开发人员不足:跨平台,JavaScript用户群体更大。 


2、缺点: 

    1)交互和性能比Native差。 

    2)扩展性弱于Web和Native。 


三、集成使用


1、环境搭建: 

    

    1)安装node: brew install node 


    2)安装watchman: brew install --HEAD watchman 


    3)安装flow: brew install flow 


    4)安装react-native命令行工具: npm install -g react-native-cli 


2、新建项目: 


    1)通过reactnative创建项目:react-native init Project 


    2)通过Project.xcodeproj运行项目 


    3)编辑index.ios.js文件修改实现视图代码 


3、已有项目: 

    1)安装CocoaPods: sudo gem install cocoapods  


    2)解绑node:brew unlink node 


    3)安装io.js: brew install homebrew/versions/iojs 


    4)配置io.js:brew link iojs —force 


    5)建立Podfile文件 

       pod ‘React’ 

       pod ‘React/RCTText’ 

       在终端运行:pod install 



    6)在已有应用目录下建立React Native内容目录 

       mkdir ReactComponent 


    7)增加index.ios.js文件 

     ‘use strict’ 

       var React = require(‘react-native’); 

       var{ 

           Text, 

           View 

       } = React; 


       var styles = React.StyleSheet.create({ 

           container:{ 

               flex: 1, 

               backgroundColor: ‘red’ 

          } 

       }); 


       class SimpleApp extends React.Component{ 

           render(){ 

               <View style = {styles.container}> 

               <Text>This is a simple application.</Text> 

               </View> 

          } 

       } 


       React.AppRegistry.registerComponent(‘SimpleApp’, () => SimpleApp); 


    8)创建RCTRootView视图 

       NSString *urlString = @“http://localhost:8081/index.ios.bundle”; 

       NSURL *jsCodeLocation = [NSURL URLWithString:urlString]; 

       RCTRootView *rootView = [[RCTRootView alloc] initWithBundleURL:jsCodeLocation moduleName:@“SimpleApp” launchOptions:nil]; 


    9)启动服务器: 

       JS_DIR=pwd/ReactComponent; cd Pods/React; npm run start --root $JS_DIR 





4、离线包:把JS文件打包到ipa。 

    终端进入应用根目录,运行react-native bundle命令。根目录的index.ios.js文件的配置信息将会写入/ios/main.jsbundle文件。 


四、Node实现服务端API


1、启动Apache 服务器 

     sudo apachectl -k start 

     检测:输入命令curl 127.0.0.1,出现<html><body><h1>It works!</h1></body></html> 


2、安装Express框架:npm install express 


3、创建server目录:mkdir todoserver 


4、在server目录下配置server:npm init 


5、把Express集成到server: 

     npm install —save express 

     touch index.js 

6、创建public目录:mkdir public 


7、在public目录创建index.html文件 

    <!DOCTYPE html> 

    <html lang="en"> 

    <head> 

         <meta charset="UTF-8"> 

         <title>Todos</title> 

    </head> 

    <body> 

        <hl>Todo</hl> 

    </body> 

    </html>


8、编辑index.js文件 

    var express = require('express'); 

    var app = express(); 


    app.get('/',function(request, response){ 

          response.send('Hello World'); 

    }); 


    app.get('/todos',function(request, response){ 

          var todos = ["Todo item 1","Todo item 2","Todo item 3"]; 

    //    response.redirect(301,'/parts'); 

         response.send(todos); 

    }); 


    app.get('/blocks',function(request, response){ 

         var blocks = '<ul><li>Todo item 1</li><li>Todo item 2</li><li>Todo item 3</li><ul>'; 

         response.send(blocks); 

    }); 


    app.get('/sendfile',function(request, response){ 

         response.sendFile(__dirname + '/public/index.html'); 

    }); 


    app.listen(3000, function(){ 

         console.log('Listening on port 3000'); 

    }); 


9、启动服务:node index.js 


10、在终端输入命令curl -i http://localhost:3000/todos、curl -i http://localhost:3000/sendfile等,测试请求。 


五、整体框架(从上到下,各个部分)



React应用组成: 


   ‘use strict’ //加入严格模式 

    var React = require(‘react-native’); //引用ReactNative 


1、标准组件:可嵌套组合 

    var { 

        AppRegistry, 

        Image, 

        ListView, 

        NavigatorIOS, 

        StyleSheet, 

        Text, 

        TextInput, 

        TouchableHighlight, 

        View, 

    } = React; 

    React.createClass 传入包含函数的JSON对象创建自定义组件。 

    

2、自定义组件: 

    var GithubFinder = React.createClass({ 

        render:function(){ 

            return( 

                <View style = {styles.container}> 

                    <Text></Text> 

                </View> 

            ); 

        } 

    }); 


render方法:返回组件渲染的视图。return的根标签为单个<View>。 

视图表示方式:可嵌套的标签,通过标签属性定义不同的渲染效果。 





3、通过StyleSheet标准组件的create方法创建样式表。 

var styles = StyleSheet.create({ 

    container:{ 

        flex:1, 

        justifyContent: ‘center’, 

        alignItems: ‘center’, 

        backgroundColor: ‘#F5FCFF’, 

    } 

}); 


4、通过标准组件AppRegistry的registerComponent方法注册根组件。 

AppRegistry.registerComponent(‘GithubFinder’, () => GithubFinder); 

此行代码,一般放到React Native应用代码的最后一行。 


{}表示变量 

{{}}表示javascript对象 


5、方法代理绑定 

var GithubFinder = React.createClass({ 

    render: function(){ 

        return( 

            <View> 

                <TextInput onEndEditing = {this.onSearchChange}/> 

            </View> 

        ); 

    }, 

    onSearchChange: function(event: Object){ 

        fetch(queryURL) 

        .then ({ 

            this.setState({ 

                dataSource: this.state.dataSource.cloneWithRows() 

            }); 

        }) 

        .done(); 

    }, 

}); 


6、组件状态:存储组件数据 

通过getInitialState方法初始化组件状态: 

var GithubFinder = React.createClass({ 

    getInitialState: function(event: Object){ 

        return{ 

            dataSource: new ListView.DataSource({ 

                rowHasChanged: (row1,row2) => row1 !== row2, 

            }), 

       }; 

    }, 

    render: function(){ 

    }, 

    onSearchChange: function(event: Object){ 

    }, 

}); 


7、在render方法中添加组件: 

var GithubFinder = React.createClass({ 

    render: function() { 

        var content; 

        if(this.state.dataSource.getRowCount() == 0){ 

            content = <Text></Text>; 

        } else { 

            content = <ListView 

                    ref=“listview” 

                    dataSource={this.state.dataSource} 

                    renderRow={this.renderRow}/>; 

        } 


        return ( 

            <View> 

                {content} 

            </View> 

        ); 

    }, 

    renderRow: function(repo: Object){ 

        return ( 

            <View> 

                    <Image /> 

                    <View> 

                        <Text>{repo.name}</Text> 

                        <Text>{repo.owner.login}</Text> 

                    </View> 

                   <View /> 

            </View> 

        ); 

    }, 

}; 


8、React Native导航: 

var NavDemo = React.createClass({ 

    onRightButtonPress: function(){ 

        this.refs.nav.push({ 

            title: ‘From Right’, 

            component: ForRightScene //跳转显示组件 

            *//如何带参数 


        }) 

    }, 


    render () { 

         return ( 

           <NavigatorIOS ref=“nav”  

            initialRoute={

                component: HomeScene,//第一页面 

                title: ‘NavigatorIOS Demo’, 

                rightButtonTitle: ‘MORE!’, 

                onRightButtonPress: this.onRightButtonPress 

            }}/> 

        ); 

    } 

}); 


var HomeScene = React.createClass({ 

    onPress(){ 

        this.props.navigator.push({ 

            title; ‘From TouchableHighlight’, 

            component: ForTouchScene 

        }); 

    }, 


    render(){ 

        return ( 

            <View> 

                <TouchableHighlight onPress={this.onPress}> 

                    <Text>Something<Text/> 

                </TouchableHighlight> 

            </View> 

        ); 

    } 

}); 


var ForRightScene = React.createClass({ 

    render(){ 

        return ( 

            <View><Text>From Right Button</Text></View> 

        ); 

    } 

}); 


var ForTouchScene = React.createClass({ 

    render() { 

        return ( 

            <View><Text>From TouchableHighlight</Text></View> 

        ); 

    } 

}); 


var styles = StyleSheet.create({ 

    container:{}, 

    scene:{} 

}); 


AppRegitry.registerComponent(‘rctnavigator’, () => NavDemo); 


NavigatorIOS有后退按钮,执行pop操作。 


8、React组件数据流: 

    1)props(静态数据) 

       可以在挂载组件时设置,也可以调用setProps({})方法。通过this.props访问。通过PropTypes检查数据类型。通过getDefaultProps设置组件属性默认值。d 

    2)state(动态数据) 

       通过setState方法设置动态数据。 


六、实现原理(过程细节)


1、React Native通信原理: 

    React Native 使用iOS自带JavaScriptCore作为JS解析引擎。当数据变化,React组件的Render方法返回虚拟DOM树。与上次DOM树对比,得到区别,批量实际更新需要变化的部分。 


2、JS-OC通信: 

    1)普通OC调JS:webview 接口 stringByEvaluatingJavaScriptFromString 在当前context执行JS脚本并获取返回值,JS向OC传递信息。 

       JSValue //可以重点看看 

    2)React Native的OC调JS: OC定义模块方法,JS调用并衔接回调。 



    模块配置表:模块、方法信息 

    OC端/JS端各有bridge,保存同一份模块配置表,调用时把模块方法转为 

JS -> JS Bridge -> OC Bridge -> OC 


   (1)取所有模块类 

        模块类实现RCTBridgeModule接口,通过runtime接口objc_getClassList或objc_copyClassList取出项目所有类,逐个判断是否实现RCTBridgeModule接口。RCTBridgeModuleClassesByModuleID() 


   (2)取模块里暴露给JS的方法:改二进制文件 

        代替方法前缀,使用编译属性__attribute__ 

        宏 RCT_EXPORT() 

        #define RCT_EXPORT(JS_name) __attribute__((used, section(“__DATA,RCTExport”\))) static const char *__rct_export_entry__[] = {__func__, #JS_name} 


        用编译属性__attribute__给二进制文件新建section,__DATA数据段 RCTExport 加入当前方法名。 

        数据段多了RCTExport,内容为暴露给JS的方法,运行时获取。在RCTBridge RCTExportedMethodsByModuleID()获取这些内容,提取类名方法名。 

        整体模块类方法提取实现在RCTRemoteModulesConfig()。 


    (3)LinkMap 

        # Object files:  //目标文件列表 

        # Sections:  //段表 各段在可执行文件中的偏移位置大小 

        代码段:__TEXT //程序代码段机器码 

        数据段:__DATA //保存变量值 

        偏移位置、段大小、段类型、段名 

        __text 程序执行语句 __data全局变量局部静态变量 __bss未初始化全局变量 __cstring字符串常量 

        # Symbols: //每个文件(类)每个字段(方法)的位置占用空间 



3、React Native 的JS调OC: 

    JS函数调用转ModuleID/MethodID -> callback转CallbackID -> OC根据ID拿到方法 -> 处理参数 -> 调用OC方法 -> 回调CallbackID -> JS通过CallbackID拿到callback执行。 

    1)JS端调用OC模块方法 

    2)调用分解为ModuleName/MethodName,arguments,交给MessageQueue。 

       在BatchedBridgeFactory.js 的_createBridgedModule里实现。 

    3)把JS callback 缓存到MessageQueue成员变量,用CallbackID代表Callback 

       ModuleName、MethodName通过MessageQueue的模块配置表转为ModuleID和MethodID 

    4)发生事件时,OC调JS,JS处理完后,把ModuleID、MethodID、CallbackID和参数返回给OC。 

    5)OC通过模块配置表拿到对应的模块和方法。在_handleRequestNumber:moduleID:methodID:params:方法里实现。 

    6)RCTModuleMethod处理JS传过来的参数。实现JS到OC的类型转换。通过NSInvocation动态调用OC模块方法。 

    7)OC模块方法调用完,执行block回调。 

    8)调用RCTModuleMethod生成的block。 

    9)block用CallbackID和block参数调JS的MessageQueue的invokeCallbackAndReturnFlushedQueue。 

    10)MessageQueue通过CallbackID找到JS Callback方法。 

    11)调用Callback方法,传递OC的参数,完成回调。 


七、开发技术(工具、语言)


    1)JSX 

    2)Webpack 

    3)Browserify 

八、参考书籍


    1)《React Native 用JavaScript开发移动应用》 

    2)《React 引领未来的用户界面开发框架》 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值