Reactive-Native框架的简单尝试(Part I)

从Reactive-Native的名字说起
字面意思,Reactive响应式,Native原生。就如JSPatch下发热更新修复线上问题,本质上还是利用OC的runtime特性,把JS解析并注入运行时,比如在class中加属性就是改变对象模型的offset,加方法就是在method list中增加对应的selector并映射到相关的method,改变方法Method Swizzling等等,总之runtime能做的事情,解析这段JS文件以后也可以执行,和原生的代码一样的性能,而不是在webview中去渲染,体验更佳流畅,这就是Native。经过FB大神们的封装,JS的写法不再是原生的JS,而是和React如出一辙(http://reactjs.cn/react/index.html),这就是Reactive。

接下来我们来试一下官方的几个basic demo
安装,自己看,要哪些东西(https://facebook.github.io/react-native/docs/getting-started.html)注意执行,react-native run-ios的时候,如果闪退,检查下网络配置,因为本地会有node.js的服务,全局代理冲突了会无法访问。
写一个hello world,文档(https://facebook.github.io/react-native/docs/tutorial.html)import, from, class, extends, and the () => 这些语法都是ES2015标准,<Text>Hello world!</Text>就是JSX,XML和嵌入JS的写法,类似于Rails当中的erb文件,嵌入式,<Text>是RN框架封装好的组件,注意RN框架有一些列已经封装好的组件,熟悉他们的特性也就是掌握这个框架的过程。在RN中所有东西都是组件,就算你要新建一个类也必须是extends Component,另外AppRegistry表明是root组件。完成以后cd到项目文件夹下的ios目录,用Xcode打开,看到AppDelegate.m,定位到application:didFinishLaunchingWithOptions:这个方法,在应用打开的时候加载了.js文件,并生成RCTRootView作为root view,看下node.js的server在干什么,浏览器中打开http://localhost:8081/index.ios.bundle,能看到相关的JS代码,由JavaScriptCore framework加载并执行。后来debug中每次cmd+R都是重新加载并执行应用开启时的动作。

再往下看文档你会发现,每一个RN框架中的class其实都继承于Component,而一个组件Component是由props和state控制的,写下这两个概念

Props:大多数组件可以被自定义创建,当然需要不同的初始化参数,这里叫做Props,看到demo(https://facebook.github.io/react-native/docs/props.html#content)<Greeting name=’Rexxar’ />,组件创建需要参数name, 然后在Greeting这个Class中访问这个参数需要从props进入,this.props.name。只在初始化组建的时候使用,不能改变的。

State:Props在组件的生命周期中是固定的,如果组件的状态发生改变,比如输入框输入新的内容,那么我们就要使用state来追踪这些改变。一般情况下,我们在constructor中初始化state,看到https://facebook.github.io/react-native/docs/state.html#content,this.state = {showText: true};,这里的state是个bool值。你可以选择一个状态容器state container比如Redux,但如果之前没有接触过,就会有学习成本,脑中迅速闪过一个个JS大神的名字,哈哈。

界面布局,总体来说,用JS来写,CSS可以嵌套,内容与样式分离和web app一个套路,还有flexbox流式布局等等,用到了就去查看文档和实例吧。简单过一下,TextInput组件,依赖state的改变,每次输入以后自动刷新页面。ScrollView会一次把数据都显示在页面上,没有复用的效果。ListView有点像UITableView可以复用,但也需要Datasource来初始化。网络层使用Mozilla的Fetch框架,你也可以用Ajax,支持WebSocket。有通用的Navigators,也有iOS定制的Navigators,那个页面的堆栈要自己来维护,推入推出操作要手动写,淡然也有现成的东西(https://github.com/react-community/react-navigation)。在iOS10.2的iPhone6上运行官方的demo,我看到那个导航栏在iOS上是看不到的,只是一行text,这种情况也是我担心的风险,OS升级带来的bug,所以RN要更新及时啊~

说了这么多,我们从头到尾写一个业务相关的demo吧,包括login,拿到token,传递token再次发起请求,解析数据,渲染布局等等。开始

我是个懒人,这里导航栏就用第三方的吧(https://reactnavigation.org/),其实人家写的真的挺不错的,省事儿

打开index.ios.js

StackNavigator的building block,可以看作是跳转的路由,现在新建的文件也都是在工程目录下,去掉后缀.js,最后的registerComponent只在第一个入口文件中需要。然后我们来写HomeScreen.js吧,先看下完成以后的效果,心中有数哪些组建时需要的引入的:

在请求网络的时候我们需要旋转的指示器,代表正在加载,所以需要ActivityIndicator,状态又分为加载和加载完毕,所以需要在state中保留这个状态

导航栏标题:

在render中加入indicator

现在我们没有分开样式,直接写在标签语言中像这样:

采用flex相对布局,数字代表权重,如果同一个层级的三个view,flex都是1,那么就是三等分

最后记得把这个类公开,因为其他文件要引用:

完整的HomeScreen.js代码见gist:https://gist.github.com/eb7f0e4c13d71eb202ae4ea06887a7aa

吐槽下那个Button,修改同一个color属性,发现两端表现不一样,而是还是by design😒,https://facebook.github.io/react-native/docs/button.html

接下去看Dashboard,我这里请求了该用户的所有Packages,新的请求需要登录以后的token,所以,涉及到页面之间的值传递,其实很简单,确定的值,初始化就要使用,Props对吧,请求的代码:

注意Listview,对应于iOS中的UITableView,展现时需要datasource,JS返回以后是一个promise对象,不停地点then一步步往下走拿到需要的数据,是一种链式写法,感觉像是语法糖。如果直接在控制台打印promise对象会感觉很奇怪,这不是一个正确的姿势。

进入页面的时候,我设置了一组假数据,当然也可以是空数据,只不过要再加一个state判断页面是否已经有数据,我又偷懒了……没有数据的时候,页面的样子:


假数据的代码:

注意既然是响应式,什么情况下是等同的,就不需要更新,所以要写equal方法,数据的哪个字段代表数据的唯一性要指出来,这个字段必须是存在的,不然报错

在看渲染每一个cell的代码:

注意JSX的写法,需要{}才能引入,样式我们添加样式表,做到内容和样式分离:

这是对刚才cell的渲染

最后记得,把组件公开:

点击底部抓取数据的按钮,拿到数据,重新渲染页面,你会看到:

 

完整的代码见gist: https://gist.github.com/4c1c955c2ee0a3929939457586472f89

这就是demo,很简单,但自己调试的时候,肯定会遇到问题,看文档就行了,需要很多web前端的知识,已经呼叫多名JS高手,有问题随时问。我是要成为全端万金油?嗯?哈哈哈哈😄。我在Part II中会讲怎么在现有的项目内,接入RN框架,在某些页面中使用JS来写,而且还支持下发,多好。如果原本是Swift的项目要接RN,本质上还是要桥接OC的,下回讲吧



发表评论

电子邮件地址不会被公开。 必填项已用*标注