react-native 开发
1.React-native的运行机制
RN 这套框架让 JS开发者可以大部分使用JS代码就可以构建一个跨平台APP。 Facebook官方说法是learn once, run everywhere, 即在Android 、 IOS、 Browser各个平台,程序画UI和写逻辑的方式都大致相同。因为JS 可以动态加载,从而理论上可以做到write once, run everywhere, 当然要做额外的适配处理。如图:
RN需要一个JS的运行环境, 在IOS上直接使用内置的javascriptcore, 在Android 则使用webkit.org官方开源的jsc.so。 此外还集成了其他开源组件,如fresco图片组件,okhttp网络组件等。
RN 会把应用的JS代码(包括依赖的framework)编译成一个js文件(一般命名为index.android.bundle), , RN的整体框架目标就是为了解释运行这个js 脚本文件,如果是js 扩展的API, 则直接通过bridge调用native方法; 如果是UI界面, 则映射到virtual DOM这个虚拟的JS数据结构中,通过bridge 传递到native , 然后根据数据属性设置各个对应的真实native的View。 bridge是一种JS 和 JAVA代码通信的机制, 用bridge函数传入对方module 和 method即可得到异步回调的结果。
对于JS开发者来说, 画UI只需要画到virtual DOM 中,不需要特别关心具体的平台, 还是原来的单线程开发,还是原来HTML 组装UI(JSX),还是原来的样式模型(部分兼容 )。RN的界面处理除了实现View 增删改查的接口之外,还自定义一套样式表达CSSLayout,这套CSSLayout也是跨平台实现。 RN 拥有画UI的跨平台能力,主要是加入Virtual DOM编程模型,该方法一方面可以照顾到JS开发者在html DOM的部分传承, 让JS 开发者可以用类似DOM编程模型就可以开发原生APP , 另一方面则可以让Virtual DOM适配实现到各个平台,实现跨平台的能力,并且为未来增加更多的想象空间, 比如react-cavas, react-openGL。而实际上react-native也是从react-js演变而来。
对于 Android 开发者来说, RN是一个普通的安卓程序加上一堆事件响应, 事件来源主要是JS的命令。主要有二个线程,UI main thread, JS thread。 UI thread创建一个APP的事件循环后,就挂在looper等待事件 , 事件驱动各自的对象执行命令。 JS thread 运行的脚本相当于底层数据采集器, 不断上传数据,转化成UI 事件, 通过bridge转发到UI thread, 从而改变真实的View。 后面再深一层发现, UI main thread 跟 JS thread更像是CS 模型,JS thread更像服务端, UI main thread是客户端, UI main thread 不断询问JS thread并且请求数据,如果数据有变,则更新UI界面。
2.react jsx的标准使用方式
(1).组件的定义必须是以大写字母开头的,否则会被认为是html的内置标签
(2).展开属性:…props
function App1() {
return <Greeting firstName="Ben" lastName="Hector" />;
}
function App2() {
const props = {firstName: 'Ben', lastName: 'Hector'};
return <Greeting {...props} />;
}
上面的两个是等价的
(3).jsx中的子代:在既包含开始标签又包含结束标签的 JSX 表达式中,这两个标签之间的内容被传递为专门的属性:props.children。有几种不同的方法来传递子代:
例如:
<MyContainer>
<MyFirstComponent />
<MySecondComponent />
</MyContainer>
(4). React 组件也可以返回包含多个元素的一个数组
例如:
render() {
// 不需要使用额外的元素包裹数组中的元素!
return [
// 不要忘记 key :)
<li key="A">First item</li>,
<li key="B">Second item</li>,
<li key="C">Third item</li>,
];
}
(5).可以在花括号中放入js表达式.
(6).rn自带的类型检查propTypes。
(7).rn自带的属性默认值配置defaultProps
(8).refs属性不可以在函数式的组件上使用,因为他们没有实例
3.redux-saga
(1).Redux 倡导action 和reducer尽可能"纯净",没有什么“副作用”。可是像一些异步操作比如获取数据是必须的,在哪处理这些副作用呢?redux 把这些"不纯净的"任务交给了中间件,通过 向createStore里应用中间件,在交由store处理action之前就可以对其完成一些其他的操作:
(2).优点:
查询与责任分离,保证了action的纯洁性,符合redux设计思想
实现以同步方式写异步操作,容易理解,逻辑清晰
通过发送指令而不是直接调用让异步操作变得容易测试
监听、执行自动化
提供了丰富强大的指令来完成复杂的操作,比如无阻塞调用,同时执行多个任务等
(3).put并不是立即执行dispatch,而是交给了mw来处理。
(4).使用try catch 来处理异常的数据。
3.javaScript基础知识
(1).js拥有动态类型
var x; // x 为 undefined
var x = 5; // 现在 x 为数字
var x = "John"; // 现在 x 为字符串
(2).变量的作用域
函数内使用 var 声明的变量只能在函数内容访问,如果不使用 var 则是全局变量。
使用 var 关键字声明的变量不具备块级作用域的特性,它在 {} 外依然能被访问到。
例如:
{ var x = 2; }
// 这里可以使用 x 变量
在 ES6 之前,是没有块级作用域的概念的。
ES6 可以使用 let 关键字来实现块级作用域。
let 声明的变量只在 let 命令所在的代码块 {} 内有效,在 {} 之外不能访问。
(3).this指针
总结:函数实际上是一个特殊的变量这个变量默认是属于window的。
显式函数绑定
在 JavaScript 中函数也是对象,对象则有方法,apply 和 call 就是函数对象的方法。这两个方法异常强大,他们允许切换函数执行的上下文环境(context),即 this 绑定的对象。
在下面实例中,当我们使用 person2 作为参数来调用 person1.fullName 方法时, this 将指向 person2, 即便它是 person1 的方法:
例如:
var person1 = {
fullName: function() {
return this.firstName + " " + this.lastName;
}
}
var person2 = {
firstName:"John",
lastName: "Doe",
}
person1.fullName.call(person2); // 返回 "John Doe"
(4).函数
箭头函数式不能提升的,需要在使用之前定义。
Js中的隐式参数是值传递,对象传递是引用传递。
ES6支持函数带有默认参数,就判断undefined和||的操作
例如:
function f(x,y=10)
{
return x+y;
}
f(0,2) //输出2
f(5) //输出15
js函数内置的对象arguments对象包含了函数调用的参数数组
例如:
x=findMax(1,123,500,115,55,66);
function findMax(){
var i,max=arguments[0]
if(arguments.length.<2) return max;
for(i=0;i<arguments.length;i++){
if(arguments[i]>max)
max=arguments[i];
}
return max;
}
(5).typeof
js中数组是一种特殊的对象类型
var person=null; //值null为(空),但类型为对象
var person=undefined; //值为undefined,类型undefined
null和undefined的值相等,但类型不等
null===undefined //false
null==undefined //true
(6).js类型
js中有5中不同的数据类型string number boolean object function
3种对象类型Object Date Array
2个不包含任何值得数据类型 null undefined
constructor属性返回所有js变量的构造函数
“str”.constructor //返回函数String(){ [native code] }
(7).Number对象
可以使用toString方法输出16进制,8进制,2进制
例如:
var number=128;
number.toStirng(16) //return 80
number.toString(8) //return 200
number.toString(2) //return 10000000
NaN非数字值:可以使用isNaN()全局函数来判断一个值是否是NaN值.
(8).js 的类型是动态的
在运行时确定数据类型,变量使用之前不需要类型声明
(9).js 是弱类型的
计算时可以不同类型之间对使用者透明地转换。即使类型不正确,也能通过隐式转换来得到正确的类型。
(10).函数是一种特殊的类型,类可以用函数来声明,函数中的属性是原型属性。
(11).promise是将多个异步执行的任务可以让链式的执行。例如:当一个任务执行完后才可以执行某个任务就可以用promise实现,成功的时候是then函数执行,失败的时候是执行catch函数中的任务。
4.rn的本地存储
(1).AsyncStorage存储:
优点:使用简单,异步机制
缺点:不可以处理复杂的数据,有存储上限。
(2).react-native-sqlite-storage:是对端sqlite的封装。
(3).realm:功能强大,既不是sqlite,也不熟使用coredata,性能高。
5.rn组件的生命周期
(1).组件的生命周期图:
(2).生命周期是否可以setState
生命周期 调用次数 能否使用 setSate()
getDefaultProps 1(全局调用一次) 否
getInitialState 1 否
componentWillMount 1 是
render >=1 否
componentDidMount 1 是
componentWillReceiveProps >=0 是
shouldComponentUpdate >=0 否
componentWillUpdate >=0 否
componentDidUpdate >=0 否
componentWillUnmount 1 否
6.react的diff机制
(1)、不同节点类型直接删除。
(2)、一层一层进行节点比较。
(3)、相同类型节点会对属性进行重设从而实现节点的转换。
(4)、同一层尽量都有唯一的key
7.npm install 的作用
每一个rn项目都有一个package.json文件,里面有很多组件信息,使用npm install将按照package.json安装所需要的组件放在node_modules文件夹中,rn项目下的每一个文件中都可以通过import引入node_modules的组件加以使用。
8.js的事件循环机制
(1).js是单线程的,原因是js最初设计的是和浏览器交互。
(2).js的事件循环机制图
9.浏览器内核和javascript引擎
浏览器内核负责对网页语法的解释并渲染网页。
Javascript引擎是一个专门处理JavaScript脚本的虚拟机,一般会附带在网页浏览器之中。
10.typeof 和 instanceof的区别
(1).typeof 用以获取一个变量的类型typeof一般只能返回number,Boolean,string,function,object,undefined。所以我们要判断array或者null类型的时候是用不了的。
(2).instanceof用以判断一个变量是否是某个对象的实例,改方式可以解决判断array和null的问题。
11.Rn 控件中key的作用
react利用key来识别组件,它是一种身份的象征。每一个key对应一个组件,相同的key,react认为是同一个组件,这样相同key对应的组件都不会被创建。
12.Promise
(1).promise.all是将多个promise放在一起执行,如果执行成功是按着传入的顺序返回的,如果失败返回的是最先reject的。
(2).Promise.race是将多个promise放在一起执行,返回顺序是按赛跑的方式决定的。
(3).promise出来是为了更好的解决js中异步实现的问题。
(4).promise.then最后返回的是一个新的promise
13.realm数据库
(1).realm数据库中查询出来的数据只有在访问属性的时候才会读取出来,这种方式非常适合读取大量的数据。
14.埋点主流的几个技术
(1).代码埋点:
在代码的关键部位植入一些代码,追踪用户的行为,得到想要的数据。
(2).框架是埋点:
框架式埋点也称‘可视化埋点’,很好的解决了代码埋点代价大和更新代价大的两个问题。
(3).无埋点:
所谓的无埋点,只要页面上嵌入sdk,就可以采集页面上所有的点击行为,然后通过界面配置的方式对关键行为进行监听。使用这种方案必须在产品中嵌入sdk。
15.graphql的工作原理
(1).每个字段都有相应的resolver函数,每当一个字段要求被返回时与其对应的resolver函数就会被执行,并产生下一个值。当所有的字段都处理完毕后,结果值构成一个从叶子节点到根节点全链路的键值对映射,键为字段名值为resolver返回的结果,最终按照请求的结构返回给客户端对应的数据结构(json格式)。
16.js中数组合并
(1).通过a.concat(b)来合并一个数组。
(2).通过[…a,…b]来合并数组。
17.rn属性的默认值
(1).实现方式
static defaultProps = {
duration:1000,
}
18.rn npm install 解决慢的问题
npm install --registr=http://registry.npm.taobao.org
19.realm数据库更新数据
database.write(() => {
// 创建一条user数据
database.create('user', {id: 123, name: 'daodao'});
// 更新主键id为123的user数据
realm.create('user', {id: 123, name: 'daodao'}, true);
});
20.Image resizeMode属性
(1)Image必须在样式中声明图片的款和高。如果没有声明,则图片将不会被呈现在界面上。我们一般将Image定义的宽和高乘以当前运行环境的像素密度称为Image的实际宽高.当Image的实际宽、高与图片的实际宽、高不符时,视图片样式定义中resizeMode的取值不同而分为三种情况, 三个取值分别是: contain, cover和stretch.默认值是cover.
(2)cover模式在显示比例不失真的情况下填充整个显示区域。可以对图片进行放大或者缩小,超出显示区域的部分不显示。
(3)contain模式是显示整张图片, 可以对它进行等比缩小, 图片会显示完整,可能会露出Image控件的底色。 如果图片宽高都小于控件宽高,则不会对图片进行放大。
(4)stretch模式不考虑保持图片原来的宽,高比.填充整个Image定义的显示区域,这种模式显示的图片可能会畸形和失真。
21.overflow (iOS)
overflow取值为enum(‘visible’, ‘hidden’)。它用来定义当View组件的子组件的宽高超过View组件宽高时的行为,默认值为hidden,即隐藏超出的部分。overflow只在iOS平台有效,在Android平台即使设置overflow为visible,呈现的还会是hidden的效果。
22.可以通过marginTop为负值来实现覆盖的效果。
23.string的match用法:
match() 方法可在字符串内检索指定的值,或找到一个或多个正则表达式的匹配。
const expression = /data=\/\/(.*)/;
const res=url.match(expression)[0];
24.json从后台返回的date类型数据是一个时间戳最后使用的时候要转换成Date类型。
const date=new Date(fromServer);
25.justify-content参数说明
(1)、space-between:两个组件之间最远。
(2)、space-around:两个组件之间的距离比space-between近一点。
(3)、space-evenly:两个组件之间的距离最近。
26.react-native 使用linking实现app直接跳转
(1)、首先app通过schema启动会有两种方式冷启动和热启动。
(2)、以andoird为例需要在activity中添加schema
<activity
android:name="com.example.android.GizmosActivity"
android:label="@string/title_gizmos" >
<intent-filter android:label="@string/filter_view_http_gizmos">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "http://www.example.com/gizmos” -->
<data android:scheme="http"
android:host="www.example.com"
android:pathPrefix="/gizmos" />
<!-- note that the leading "/" is required for pathPrefix-->
</intent-filter>
<intent-filter android:label="@string/filter_view_example_gizmos">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<!-- Accepts URIs that begin with "example://gizmos” -->
<data android:scheme="example"
android:host="gizmos" />
</intent-filter>
</activity>
(3)、在react-native中处理冷启动的情况
componentDidMount() {
Linking.getInitialURL().then((url) => {
if (url) {
console.log('Initial url is: ' + url);
}
}).catch(err => console.error('An error occurred', err));
}
(4)、在react-native中处理热启动的情况
componentDidMount() {
Linking.addEventListener('url', this._handleOpenURL);
},
componentWillUnmount() {
Linking.removeEventListener('url', this._handleOpenURL);
},
_handleOpenURL(event) {
console.log(event.url);
}
27.背景透明
设置背景色的时候需要用rgba
container:{
backgroundColor: 'rgba(178,178,178,0.0)',
}
28.list在加载大数据
(1)、在加载很多的数据的时候需要将数据分段加载。
(2)、使用一个标示位来标记目前加载的数据。
(3)、需要做锁机制,不实现锁机制将会有同一段数据加载两遍的情况。
29.FlatList渲染原理
FlatList 之所以节约内存、渲染快,是因为它只将用户看到的(和即将看到的)部分真正渲染出来了。而用户看不到的地方,渲染的只是空白元素。渲染空白元素相比渲染真正的列表元素需要内存和计算量会大大减少,这就是性能好的原因。
FlatList 将页面分为 4 部分。初始化部分/上方空白部分/展现部分/下方空白部分。初始化部分,在每次都会渲染;当用户滚动时,根据需求动态的调整(上下)空白部分的高度,并将视窗中的列表元素正确渲染出来。
30.LifecycleEventListener
(1)、作用是用来监听原生activity生命周期。
(2)、使用方式:
LifecycleEventListener listener = new LifecycleEventListener() {
@Override
public void onHostResume() {
}
@Override
public void onHostPause() {
}
@Override
public void onHostDestroy() {
}
};
reactContext.addLifecycleEventListener(listener);
31.native向RN发送消息
private void sendEvent(ReactContext reactContext, String eventName, WritableMap params) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class) .emit(eventName, params);
}
32.react-native 获取地理位置慢的解决方案
navigator.geolocation.getCurrentPosition(
(position) => {
console.log(position);
},
(error) => {
console.log(error)
},
{enableHighAccuracy: true, timeout: 20000, maximumAge: 10000}
);
上面这样的代码在android中获取地理位置是非常慢的,因为获取的是高精度的地理位置。将enableHighAccuracy改为false可以解决获取慢的问题。
32.image resizeMode
(1)、contain:容器完全容纳图片,图片等比例进行拉伸
(2)、cover( 默认):图片居中显示且不拉伸图片,超出的部分剪裁掉
(3)、stretch:图片被拉伸至与容器大小一致,可能会发生变形
33.loading
(1)、ActivityIndicator是用来显示loading的组件
(2)、animating:是否显示,默认true(显示)
(3)、color: 指示器的颜色, ios默认为gray(#999999),android 默认使用progressBar的系统样式,取决于你设置的style。
(4)、size: 表示大小,可以设置的值有:
‘small’: 宽高各20
‘large’: 宽高各36
(5)、hidesWhenStopped:此属性只在ios生效,当停止动画的时候,是否隐藏。默认为true。