本文主要是本人从Android原生到开发出一套完整的RN模块嵌入原生的经验。react
他们两者是RN的数据核心。state主要是自身数据更新,props主要是父组件传入到子组件中使用,也会有自身的默认props。 对于props,建议通常都传入子组件,防止之后进行修改。特定的flag则进行指定,好比:有一个Page A,他包含Component Bgit
A extends Component{
...
render(){
return (
...
<B url=this.state.url {...this.state}/>
...
);
}
...
}
复制代码
对于State,须要注意死循环,这种状况可能发生在render过程(不是事件响应过程),假如在渲染过程当中,咱们须要修改state,通常先进行判断,而后再去设置,不然可能一直死循环render好比下面的ImageHolderComponent例子。github
在RN中,提倡组件化。他是能够根据UI划分组件,对于底层组件,咱们须要实现逻辑不须要实现业务。好比,对于styles,咱们通常须要提供一个默认样式,而后再经过外部插入的props样式,经过数组组合一块儿,外部能够覆盖内部。 例如,下面例子是定义一个通用的Image组件,他能够在图片加载失败或者是URL为空等适合显示出place holder图片。json
export default class ImageHolderComponent extends Component {
static defaultProps = {
url: "",
imageStyle: {},
holderResizeMode: "cover"
};
constructor(props) {
super(props);
this.state = {
loadState: 0
}
}
_emptyUri = () => {
return <Image
resizeMode={this.props.holderResizeMode}
source={this._holder()}
style={[{
width: 60,
height: 60,
borderRadius: 60,
}, this.props.imageStyle]}/>;
};
_normal = () => {
return <Image
source={{uri: this.props.url}}
defaultSource={this._holder()}
onError={() => {
if (this.state.loadState === 1) {
//防止死循环
return;
}
this.setState({loadState: 1});
}}
onLoad={() => {
if (this.state.loadState === 2) {
////防止死循环
return
}
this.setState({loadState: 2});
}
}
style={[{
width: 60,
height: 60,
borderRadius: 60,
}, this.props.imageStyle]}/>;
};
_holder = () => {
const {holder} = this.props;
if (holder) {
return holder();
}
return require("../../img/pic_empty_data.png");
};
render() {
const showView = this.props.url && (this.props.url.indexOf("http") >= 0) && this.state.loadState !== 1 ? this._normal() : this._emptyUri();
return (
<TouchableWithoutFeedback onPress={() => {
const {onPress} = this.props;
if (onPress) {
onPress(this.props.url);
}
}}>
{showView}
</TouchableWithoutFeedback>
);
}
}
复制代码
他须要外部传入一个url便可,假如须要复写样式则传入参数名为imageStyle的style便可。 这样子,就作到Component独立,又能与外部进行交互。redux
由于fetch是返回一个Promise的,因此仍是比较友好的。 咱们能够对fetch进行一个比较好的封装,需求是:react-native
function _body(method, params) {
const _params = JSON.stringify(params);
console.log(("http=> params = " + _params));
return {method: method, headers: HEADER, body: _params}
}
function _get(url, params) {
return _request(url, _body("GET", params));
}
function _post(url, params) {
return _request(url, _body("POST", params))
}
//发起请求
function _request(url, params, timeout) {
console.log(("http=> url = " + url));
const request = fetch(url, params)
.then(result => {
if (result.ok) {
console.log(("http=> respond = " + result.json()));
return result.json();
} else {
return Promise.reject({code: -1, message: "请求失败"});
}
})
.then(value => {
//能够进行进一步刷选
return value;
})
.catch(error => {
return Promise.reject(error);
});
return _wrapRequest(request, timeout)
}
//设置超时,默认10000
function _wrapRequest(promise, timeout = 10000) {
return Promise.race([promise, new Promise(function (resolve, reject) {
setTimeout(() => {
reject({code: -1, message: "请求超时"});
},
timeout);
})]).catch(e => {
return Promise.reject(e)
})
}
复制代码
好比对于登录而言数组
//登录
function _body(password,username) {
const params = {};
params[USER_NAME] = username;
params[PASSWORD] = password;
....
return _post("loginurl",params)
}
复制代码
就能够了。promise
我的认为这个仍是比较有必要的,这样子能够统一代码风格,什么分号,括号,无用导入,一些可能出现错误的地方,经过ESLint均可以检测出来。须要能够前往ReactNativeDemo 查看.eslint文件和package.json文件。缓存
在开发中,通常独立页面使用Page结尾,通常组件使用Component结尾。 对于对内方法添加下划线,对外方法就不用,仍是使用驼峰的命名规则。 通常,咱们尽可能使用解构赋值取数据,这样子能够给一些默认值。bash
在RN中,他相对于CSS顶层的this是window,RN顶层的this是自己Component,因此咱们尽可能使用方法变量
而不是定义方法,这样子他就能够自动绑定this了。例如
A extends Component{
//不推荐
methodA(){
//...
}
//推荐
methodB = ()=>{
//。。
}
}
复制代码
咱们进行页面跳转的时候,好比使用的是react-navigation
,咱们尽可能带一个from
这样子一个key,value是该页面的String值。这样子方便下一个页面不管是goback仍是navigate去别的页面在过把存款都比较好操做
对于Android物理back键,咱们可能在特殊的页面须要进行特殊处理,好比back的时候须要弹窗什么的。 可是,在RN中,好比一个需求是A.navigate(B),而后B.navigate(C)。假如是有这样子一个跳转关系,在B中须要监听back键,这时候在C中没有监听,在C中按下back键就会把B也结束掉,由于B中的监听并无被移除,而在C中,他是没有处理back event的返回值的,致使B响应了,就连续返回了。 须要处理该问题,咱们就须要定义一个BaseComponent,之后每个独立页面Page,都须要继承该Component,假如是有特殊处理的,须要注意super。
function log(msg) {
console.log("BaseComponentPage==>" + msg);
}
export default class BaseComponentPage extends Component {
constructor(props) {
super(props);
log("addEventListener hardwareBackPress");
BackHandler.addEventListener("hardwareBackPress", this._onBackPress);
}
//子类须要重写该方法到时候,必须super
componentWillUnmount() {
log("removeEventListener hardwareBackPress");
BackHandler.removeEventListener("hardwareBackPress", this._onBackPress);
}
_onBackPress = () => {
this.props.navigation.goBack();
log("_onBackPress");
return true;
};
}
复制代码
react-navigation
导航react-native-router-flux
导航,他更加友好的封装了react-navigation
react-redux
,redux
,redux-logger
,redux-thunk
redux全家桶react-native-scrollable-tab-view
能够作到相似Android的TabLayoutprop-types
类型检测react-native-video
视频播放react-native-image-zoom-viewer
图片缩放react-native-fetch-blob
网络请求,也能够本身直接封装一下fetch。react-native-cached-image
图片缓存+显示