React Native总结
不过多描述原理和优缺点,可自行查阅官方手册
一、注意点
1.关于style
style用于标注组件的布局属性,一般情况下有两种写法形式:
内连形式一:
<View style={{flex:1,backgroundColor:'red'}}/>
抽象形式二:
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
})
<View style={styles.container}/>
两种形式都可以用于添加组件布局属性,但一般情况下,在组件所属目录下,创建名为styles.js的文件夹,使用第二种形式在文件内统一创建style,并对外export。
这样做的好处一方面是使代码清晰整洁,不冗余,方便复用和修改,另一方面是防止每次组件render时,频繁的进行style创建。
还有一种情况是内连和抽象形式连用形成包裹形式:
<View style={[styles.container,this.props.style]}/>
这种形式在进行自定义组件的时候十分常见,为style赋值一个数组,第一个数组对象一般设置为组件的固有布局属性或默认布局属性,第二个数组对象为组件使用时,外部对组件布局属性的自定义。如果两个布局属性存在同样的关键字时,以第二的布局属性为准。
2.关于ref
组件的ref字段一般被用来获取组件的对象,一般书写形式如下:
compoentDidMount(){
this.refs.view // 获取到view组件对象
this._scroll.scrollTo({y:10,x:10})//获取到ScrollView对象,并执行scrollTo()
}
....
<View ref='view'></View>
<TextInput ref={(input)=>{
//此处可以对TextInput组件进行操作,比如focus()
}}/>
<ScrollView ref={(scroll)=>this._scroll = scroll}/>
可以尝试打印一下通过ref获取到的组件对象,例如打印scrollview的组件对象,可以找到组件对象可以调用的方法、组件的属性和其子组件与父组件信息。
ref仅可以在组件被render到界面后,才可以调用,否则会返回undefined;
3.关于image
关于Image组件,目前版本,在iOS和Android平台上行为略微不一致,当不给Image设置source或source不可用时,仅设置布局属性时,iOS端会显示根据布局属性生成无图组件,进行占位;Android端则不会生成无图组件进行占位,即便设置了明确的长高属性。
4.关于onLayout和NativeMethodsMixin
每个组件都可以设置onLayout属性来获取组件的位置信息
<View onLayout={(e)=>{e.nativeEvent即是组件的位置信息}/>
但通过onLayout获取到的位置信息只是相对于父组件的位置坐标,而不是相对于屏幕位置的绝对坐标。
通过对NativeMethodsMixin方法的调用,可以帮助我们直接对组件进行操作,其中一方面功能就是获取组件在最底层视图上显示的尺寸。
this.refs.view.measure((x,y,width,height,pageX,pageY)=>{
console.log(x,y,width,pageX,pageY,height);
})
但是,这个方法需要预留反应时间,目前版本中,在componentDidMount中不可以调用此方法,虽然不会报错,但返回结果全部为0;正如官方文档所说,如果想更快的获取组件尺寸,请使用onLayout;
NativeMethodsMixin还有两个比较常用的方法:measureInWindow和measureLayout。当设计模式为在原生应用中嵌入React Native窗口时,可以使用measureInWindow获得组件相对于屏幕的坐标信息,参数是一个callBack,用法参照measure;measureLayout可以用来获取组件和目标组件之间的相对坐标。参数有三个:第一个为目标视图的节点,第二个参数为成功时的回调,第三个参数为失败时的回调。获取组件节点使用findNodeHandle,从0.27版本后,该方法引用方式变为
import {findNodeHandle} from 'react-native';
对于onLayout还有一点疑问,如果调用如下代码
<View onLayout={()=>log}>
<View onLayout={()=>log}>
<View onLayout={()=>log}>
</View>
</View>
</View>
即对一个多层级的组件都设置onLayout属性时,Android端外层onLayout的触发会比内层快一点,而iOS端onLayout的触发则是不固定的,同时触发时快时慢。虽然相差时间都是毫秒级别,目前没有发现影响,但不排除特定状态下会产生bug。
5.关于Immuatble.js
Immutable.js 是facebook的一个js库,目的就是为JavaScript添加不可变的数据类型。React Native中在使用state控制视图时,可以通过使用Immutable.js来进行state判断,确定是否刷新视图。
Immutable的语法不过多介绍,此处只介绍Immutable的is方法。
is方法用来比较两个Immutable类型的数据是否相等,此处的比较为值比较。与之对应的Object.is和 === 则是进行地址比较。
let test1 = Immutable.fromJS({a:{b:1}});
let test2 = Immutable.fromJS({a:{b:2}});
let temp = test2.setIn(['a','b'],1);//将键b的值改为1
console.log(Immutable.is(test1,temp));//打印结果为true
let test3 = {a:1,b:2};
let test4 = {a:1,b:2};
console.log(Object.is(test3,test4));//打印结果为false
console.log(test3===test4);//打印结果为false
通过使用Immutable.js,可以在shouldComponentUpdate中,完成对states和props的判断。其他用法详见文档和链接
<a>http://facebook.github.io/immutable-js/docs/#/<a/>
<a>https://zhuanlan.zhihu.com/p/20295971</a>
6.关于视图渲染刷新
6.1 过度渲染
React Native组件的渲染都在render函数中执行并return,即每触发一次render函数都要重新渲染一次组件。而每次对state的修改则会触发一次render,将整个组件重新渲染。这就将导致一个问题,即过度渲染。有时候我们频繁的进行state操作时,频繁的触发render,导致页面卡顿,性能下降,动画掉帧等一系列问题。
6.2 setNativeProps
setNativeProps其实是对组件底层进行操作,而不是在RN框架层面进行组件的设置,所以调用setNativeProps方法可以规避render等组件相关方法的触发,但是官方建议,能用state和shouldcomponentUpdate解决时就不用setNativeProps,因为使用setNativeProps可能会导致代码结构不是很清晰或state混乱。所以setNaiveprops一般被用于进行动画设置和增强视觉效果方面。用法如下:
this.refs.view.setNativeProps({backgroundColor:'red'})
//将view背景改为红色
6.3 shouldComponentUpdate
在shouldComponentUpdate方法中我们可以判断组件下一组props和state的变化来决定是否触发render,重新渲染组件。此处可以使用上面所提到的Immuatble.js库。
具体写法
shouldComponentUpdate(nextProps,nextState){
const thisProps = this.props || {}, thisState = this.state || {};
if (Object.keys(thisProps).length !== Object.keys(nextProps).length ||
Object.keys(thisState).length !== Object.keys(nextState).length) {
return true;
}
for (const key in nextProps) {
if ((thisProps[key] !== nextProps[key] || !is(Immutable.fromJS(thisProps[key]), Immutable.fromJS(nextProps[key])))&&typeof(thisProps[key])!="function") {
return true;
}
}
for (const key in nextState) {
if (thisState[key] !== nextState[key] || !is(thisState[key], nextState[key])) {
return true;
}
}
return false;
}
基本的shouldComponentUpdate的写法如上所示,根据组件需求进行微调即可。但需要注意的是,当state或者props中存在function时,此时比较state和props,总会返回false,即previousState(props)和nextState(props)始终不相等,所以一般情况下比较两者时,屏蔽function类型。
6.4 组件化
组件化的好处一方面是为了进行组件的复用,还有一方面是进行组件是否重新渲染的判断。例如一个组件有7个层级,当组件重新渲染时,就要把7个层级都渲染一遍,而且因为7个层级组件都写在了一个render里,不仅代码臃肿,而且无法进行区别判断是否渲染。所以尽量将代码抽离,实现组件化。
7.关于Promise、async和await
Promise对象是ES6新增的,常作为异步结果的返回值,例如:本地数据存储或fetch网络请求。async函数同样是ES6新增的,需要同await联合使用。所以一般情况下同时使用两者去进行异步处理,以网络请求为例
async someHandle(url){
try{
let result = await fetch(url);
console.log(result)
return result;
}catch(err){
console.log(err);
}
}
但是aysnc函数有一个特点是假如fetch等异步操作返回reject,那么async函数将直接返回reject状态,而不会往下继续执行。即假如fetch若返回reject,将不会执行下面的打印。
可以在async函数内加上try...catch,来收集异步操作的错误信息。
8.关于Redux
Redux是一个state管理框架,只存在一个store来存储所有的state,只可以通过触发action,action触发reducer,去修改store里的state,来确保state的状态改变行为可控。
8.0 必备框架
react-redux 、redux 、redux-thunk即可,全部可以通过
npm install --save 框架名
安装
8.1 action
action相当于一个触发动作,告诉reducer去修改state。
一般的action形式:
someHandle(value){
return{
type:someType,
value,
}
}
action函数必须返回一个包含type的对象,其他字段和对象结构可以自行设计,返回type的目的是为了在reducer进行响应的时候进行判断,具体如何哪个state。
8.2 reducer
reducer函数是通过action触发的,state的修改是在该函数内进行的。
一般的reducer形式:
const initialState = Map({
number:1,
opacity:0,
offset:0
})
export default function someHandle (state= initialState, action={}){
switch (action.type) {
case SOMETYPE:
return //此处返回操作过的state
default:
return state;
}
}
注意reducer中,不可以直接修改state,需要根据操作,生成新state,并返回,reducer需要保证数据的唯一和不可变,所以此处的state可以使用Immutable.js进行数据类型的定义。
8.3 redux-thunk
redux-thunk是一个redux的中间件,可以使某一action可以出发另一个action,目的是为了可以在action函数中进行异步操作,例如进行网络请求获取json数据并处理。
someHandle(){
return (dispatch,getState){
//一些异步处理
dispatch({
type:someType,
...
})//触发reducer
}
}
该框架不是实现redux的必须框架,中间件可以自行定义。
8.4 其他
使用redux结构管理state不一定总是有益的,在项目需求简单时,接入该结构完全没有必要。而且在自定义组件是也不需要引入该结构,具体情况还需要按照项目需求进行处理。
redux在React Native中的工作其实是控制每个组件的props,通过改变组件的props,达到组件渲染和状态的可控,所以redux的state并不代表RN框架的state,也不是对state的取代,而是另一种形式的状态机。两者各有利弊,结合使用效果更佳。
demo地址:<a>https://pan.baidu.com/s/1eS81cXG<a/>(非原创,但是原地址找不到了。。。)
网友评论