技术标签: React Native RN
组件的生命周期分成三个状态:
Mounting
装载已插入真实 DOM
Updating
正在被重新渲染
Unmounting
已移出真实 DOM
构造函数,在组件挂载之前调用一次。返回值将会作为 this.state 的初始值。
super(props)
。constructor(props: props, context: any) {
super(props, context);
//初始化状态变量
this.state = {
name: '张三',
};
//函数绑定
this.login = this.login.bind(this);
}
UNSAFE_componentWillMount
准备加载组件,这个函数调用时机是在组件创建,并初始化了状态之后,在第一次绘制 render() 之前。可以在这里做一些业务初始化操作,也可以设置组件状态。这个函数在整个生命周期中只被调用一次。
componentWillMount
函数之后
被调用。UNSAFE_componentWillMount(): void {
//加载本地数据
AsyncStorage.getItem('data')
.then((listData) => {
//TODO...
}).catch((error) => {
//TODO...
});
}
开始渲染
调用该方法,先对状态机变量与属性进行检查。
如果开发者不想渲染界面的话,可以在此处返回null或者false。
该方法适用于进行界面的JSX代码编写,因此不适合在此处对状态机变量进行修改或者访问服务器。
render() {
return (
<View>
<Text>
姓名:{
this.props.content}
</Text>
</View>
);
}
函数原型:void componentDidMount();
这个函数调用的时候,其虚拟 DOM 已经构建完成,可以在这个函数开始获取其中的元素或者子组件了。
从这个函数开始,就可以和 JS 其他框架交互了,例如设置计时 setTimeout 或者 setInterval,或者发起网络请求。这个函数也是只被调用一次。这个函数之后,就进入了稳定运行状态,等待事件触发。
componentDidMount
函数之前
被调用。componentDidMount(): void {
//发起网络请求
fetch(url)
.then((response) => response.json())
.then((responseData) => {
//TODO...
})
.catch((error) => {
//TODO...
});
}
UNSAFE_componentWillReceiveProps
函数原型:
UNSAFE_componentWillReceiveProps(nextProps);
当属性发生改变或接收到一个新的属性时候,该函数被调用。并接受一个输入参数,类型为Object,存放新的props,原先旧的props仍然可以通过this.props访问。
UNSAFE_componentWillUpdate
函数原型:
boolean UNSAFE_componentWillUpdate(nextProps,nextState);
组件是否需要更新,接受两个参数。根据返回的布尔值来决定是否需要对页面进行重新渲染,如果不进行渲染,那么该方法后续的componentWillUpdate与componentDidUpdate都不会被执行。
componentWillUpdate
和componentDidUpdate
都不会执行。函数原型:
componentWillUpdate(object nextProps, object nextState)
,当shouldComponentUpdate
返回true后立即调用,
函数原型:
componentDidUpdate(object prevProps, object prevState)
,在组件的更新已经同步到 DOM 中之后立刻被调用。
该方法会在RN卸载之前调用,无参无返回值,在该方法中,需要对该组件当中申请或者订阅的某些资源与消息进行释放。
在该方法中执行任何必要的清理,比如无效的定时器,或者清除在 componentDidMount 中创建的 DOM 元素。
state或props任何一个变化都会引起render重新执行渲染。
state表示一个组件内部自身状态,只能在自身组件中存在。
由于state任何属性的改变都会导致UI重绘,而UI重绘会消耗系统资源,所以在封装可复用的组件时,尽量不用或少用state,而是通过props将数据传递到组件内部(props在组件内部是不可变的,不会导致UI重绘)。
props是父组件中指定,传递给自组件的数据流,且一经指定,在被指定的组件的生命周期中不可更改。
在 React 中信息是单向的。我们维护着组件层次,在其中每个组件都仅依赖于它父组件和自己的状态。通过属性(props)我们将信息从上而下的从父组件传递到子元素。如果一个祖先组件需要自己子孙的状态,推荐的方法是传递一个回调函数给对应的子元素。
在RN中如果使用状态机变量存储于UI无关的变量,会导致不必要的判断是否需要重新渲染,从而导致应用性能下降,正确的做法是保存在组件的成员变量中(在构造函数中定义成员变量是一个不错的做法,可保证成员变量有初始值)。
定义
//构造函数中定义成员变量
constructor(props) {
super(props);
//成员变量
this.inputContent = '';
}
使用
<TextInput
placeholder={
'登陆账号 '}
onChangeText={
(content) => {
//将输入内容赋值给当前的局部变量
this.inputContent = content;
}}
/>
<Button
title="点击2"
onPress={
() => {
//输出局部变量
console.log('输入的账号为:' + this.inputContent);
}}
/>
React Native 允许组件有静态变量、静态成员函数。它们的作用与 C++,Java 中的类静态变量、类静态成员函数基本一样。
定义
export default class RegisterComponent extends Component {
//定义类的静态成员变量
static loginName = '';
static loginPwd = '';
//定义类的静态成员函数
static login() {
console.log('loginName:' + this.loginName);
console.log('loginPwd:' + this.loginPwd);
}
}
使用
访问方式
类名.变量名
、类名.函数名
,不能以this
调用。
export default class LoginComponent extends Component {
render() {
return (
<View>
<TouchableOpacity
style={
loginStyle.loginButtonTouchable}
activeOpactiv="0"
onPress={
() => {
//直接类名.静态变量/静态函数名调用
RegisterComponent.loginName = 'zcmain';
RegisterComponent.loginPwd = '99999';
RegisterComponent.login();
}}>
</TouchableOpacity>
</View>
);
}
步骤
创建继承
ReactContextBaseJavaModule
的Module类。1.1 实现
getName
方法,返回一个字符串,该字符串是标记导出的原生模块,供RN端调用 (不要使用
ToastAndroid
作为导出名字,会与RN内置的冲突)。1.2 定义并实现使用
ReactMethod
注解的Java方法,且方法返回值只能是void
类型(RN跨语言访问是异 步的,所以RN想要返回值唯一办法是使用回掉函数或者发送事件
参见:《Android原生调用RN方法实现》。
创建实现
ReactPackage
接口的RN包管理器类,并将前一步创建的Module类注册到该包管理器的createNativeModules
方法中。将创建的RN包管理器类添加到Application中的
getPackages
方法中。
实现
原生创建一个类继承ReactContextBaseJavaModule
类,实现getName
方法,用于提供给RN侧调用原生代码的接口名称。并使用@ReactMethod
注解定义给RN侧调用的函数
/**
*1.创建继承ReactContextBaseJavaModule的Module类
*/
public class AndroidNativeModule extends ReactContextBaseJavaModule {
ReactApplicationContext context;
public AndroidNativeModule(@NonNull ReactApplicationContext reactContext) {
super(reactContext);
this.context = reactContext;
}
//1.1 实现getName方法,返回一个字符串(该字符串是标记导出的原生模块)
@NonNull
@Override
public String getName() {
return "AndroidNativeModule";
}
/**
*1.2 定义并实现使用ReactMethod注解的Java方法,且方法返回值只能是void类型。
*/
//提供给RN调用的方法(无参)
@ReactMethod
public void callAndroidMethod() {
Log.d("AndroidNativeModule","from the RN call...");
}
//提供给RN调用的方法(有参)
@ReactMethod
public void callAndroidParamsMethod(String name, int age) {
Log.d("AndroidNativeModule", "from the RN call name:" + name + "\tage:" + age);
}
}
原生创建一个类实现ReactPackage
包管理器接口。实现该接口的createNativeModules
函数,将原生代码创建的AndroidNativeModule
添加到RN包管理器中。
/**
*2.创建类实现ReactPackage接口,实现createNativeModules方法将之前创建的 AndroidNativeModule
* 添加到该包管理器中。
*/
public class AndroidNativePackage implements ReactPackage {
@NonNull
@Override
public List<NativeModule> createNativeModules(@NonNull
ReactApplicationContext reactContext) {
//将之前创建的 AndroidNativeModule 添加到该包管理器中
List<NativeModule> nativeModules = new ArrayList<>();
nativeModules.add(new AndroidNativeModule(reactContext));
return nativeModules;
}
@NonNull
@Override
public List<ViewManager> createViewManagers(@NonNull
ReactApplicationContext reactContext) {
//返回空集合
return Collections.emptyList();
}
}
将原生创建的AndroidNativePackage
包管理器实例添加到在Application中的getPackages
函数中。
@Override
protected List<ReactPackage> getPackages() {
List<ReactPackage> packages = new PackageList(this).getPackages();
//将创建原生的包管理器添加到ReactPackage列表中
packages.add(new AndroidNativePackage());
return packages;
}
RN侧调用
//1.导入NativeModules组件
import {
NativeModules } from 'react-native';
//2.使用 NativeModules.原生导出模块.函数名称。
invokerNative() {
//调用原生无参函数
NativeModules.AndroidNativeModule.callAndroidMethod();
//调用原生有参函数
NativeModules.AndroidNativeModule.callAndroidParamsMethod('Android',30);
}
步骤
创建头文件(
*.h
)引入RCTBridgeModule.h
头文件,来使用RCTBridgeModule
协议。创建实现文件(
*.m
):2.1 使用
RCT_EXPORT_MODULE(js_name)
宏,标记导出的原生模块。如果你不指定名称,默认 就会使用这个 Objective-C 类的名字。如果类名以 RCT 开头,则 JavaScript 端引入的模块名会自动
移除这个前缀。
2.2 使用
RCT_EXPORT_METHOD()
宏,导出实现的原生函数,且函数返回值只能是void
(RN跨语言访问是 异步的,所以RN想要返回值唯一办法是使用回掉函数或者发送事件
参见《IOS原生调用RN方法实现》。
PS:React Native 还定义了一个
RCT_REMAP_METHOD()
宏,它可以指定 JavaScript 方法名。所以当原生 端存在重载方法时,可以使用这个宏来避免在 JavaScript 端的名字冲突。
实现
创建原生头文件(.h)
//1.创建头文件
#import <Foundation/Foundation.h>
//导入RCTBridgeModule.h文件
#import "RCTBridgeModule.h"
@interface Hello : NSObject <RCTBridgeModule>
@end
创建头文件实现文件(.m)
//2.创建实现文件
#import <Foundation/Foundation.h>
#import "Hello.h"
@implementation Hello
//2.1 使用RCT_EXPORT_MODULE(js_name)宏,标记导出的原生模块。
RCT_EXPORT_MODULE(IOSNativeModule);
/**
*2.2 使用RCT_EXPORT_METHOD()宏,导出实现的原生函数,且函数返回值只能是void
*/
//导出供RN调用方法(无参)
RCT_EXPORT_METHOD(callIosMethod){
NSLog(@"from the RN call...");
}
//导出供RN调用方法(有参)
RCT_EXPORT_METHOD(callIosParamsMethod:(NSString *)name age:(int)age)
{
NSLog(@"from the RN call name%@ age%d",name,age);
}
@end
RN侧实现调用
//导入 NativeModules 组件
import {
NativeModules } from 'react-native';
//使用 NativeModules.原生导出模块.函数名
invokerNative() {
//调用原生无参函数
NativeModules.IosNativeModule.callIosMethod();
//调用原生有参函数
NativeModules.IosNativeModule.callIosParamsMethod('IOS', 26);
}
- 被动调用:原生模块还支持一种特殊的参数——回调函数。它提供了一个函数来把返回值传回给 JavaScript,即RN先调用原生函数,然后原生通过回掉函数返回数据至RN。后引申为Promise机制实现。
- 主动调用:原生模块主动向 JavaScript 发送事件通知。最好的方法是继承
RCTEventEmitter
,实现suppportEvents
方法并调用self sendEventWithName:
。
Androd端通过Promise机制被动发消息到RN,实现上与RN调用Android端方法实现相似,唯一不同点是如果桥接原生方法的最后一个参数为Promise
对象,则对应的JS方就会返回一个Promise对象。
步骤
相同步骤参考《RN调用Android原生方法实现》
不同点原生的Module中:
2.1 使用
ReactMethod
注解的Java方法,最后一个参数为Promise
对象。
实现
创建原生Module、包管理器、添加到Application中步骤略(参考:《RN调用Android原生方法实现》)。
原生Module中ReactMethod
注解的方法,最后一个参数为Promise
对象
//提供给RN调用的方法,且通过Promise对象返回数据到RN
@ReactMethod
public void callAndroidParamsMethodAcceptBackMsg(String fromRnMsg, Promise promise) {
Log.d("AndroidNativeModule", "RN:" + fromRnMsg);
String toRnMsg = "Android:Hello RN Nice to meet you! !";
if (!TextUtils.isEmpty(toRnMsg)) {
//通过promise的resolve返回正常数据
promise.resolve("\n\n" + fromRnMsg + "\n" + toRnMsg);
} else {
//通过promise的reject返回异常
promise.reject("11", "msg cannot be empty!");
}
}
RN测调用
//NativeModules.原生导出模块.原生注解方法名称
NativeModules.AndroidNativeModule
.callAndroidParamsMethodAcceptBackMsg('RN:Hello Android!')
.then((response) => {
Alert.alert('Title', response);
}).catch((error) => {
Alert.alert('Title', error.message);
});
主动调用(RCTEventEmitter事件
)
即使没有使用Promise机制被RN被动调用,原生模块也可以主动给RN发送事件通知。最简单办法是通过RCTDeviceEventEmitter
,这可以通过ReactContext
来获得对应的引用。然后调用其ReactContext.getJSMethod(RCTDeviceEventEmitter.class).emit(事件名称,data参数)
来发送数据即可。
注意:使用emit发送的消息数据需要包装成WritableMap对象,否则会出现异常
使用emit发送的消息数据需要包装成WritableMap对象,否则会出现异常
使用emit发送的消息数据需要包装成WritableMap对象,否则会出现异常
步骤
创建原生Module、包管理器、添加到Application步骤略(参考:《RN调用Android原生方法实现》)。
我们通常封装成一个工具类
1.1 内部持有一个ReactContext对象的引用。
1.2 实现原生向RN发送消息的方法
然后在原生创建的RN包管理器的
createNativeModules
方法中初始化该工具类。RN端配置:
4.1 导入
NativeEventEmitter
、NativeModules
组件4.2 通过
NativeModules.原生导出模块
实例化NativeEventEmitter
对象4.3 调用
NativeEventEmitter
的addlistener(事件名,回调函数)
来监听事件 (推荐在
UNSAFE_componentWillMount
中开启事件订阅监听)。4.4 别忘记最后取消订阅(推荐在
componentWillUnmount
中取消订阅)。
实现
创建原生Module、包管理器、添加到Application步骤略(参考:《RN调用Android原生方法实现》)。
创建通信工具类
//1.创建原生向RN主动发送消息工具类
public class DeviceEventEmitterUtil {
//1.1内部持有ReactContext对象引用
private static ReactContext reactContext;
public DeviceEventEmitterUtil(ReactContext reactContext) {
this.reactContext = reactContext;
}
/**
* 1.2原生向RN发送消息
* @param eventName 事件名称
* @param params 参数(注意包装成WritableMap对象)
*/
public static void sendMsgToRn(String eventName, WritableMap params) {
reactContext.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
}
模拟客户端调用该方法
void sendMsgToRn() {
try {
//模拟订单信息(需要包装成WritableMap对象)
WritableMap orderParams = Arguments.createMap();
orderParams.putString("orderTime", "20191219154030");
orderParams.putString("orderAmount", "18888.09");
orderParams.putString("orderName", "MacBook Pro");
//发送提交订单消息到RN
DeviceEventEmitterUtil.sendMsgToRn("order", orderParams);
//模拟支付信息(需要包装成WritableMap对象)
WritableMap payParams = Arguments.createMap();
payParams.putString("orderId", "90888878789");
//发送支付消息到RN
DeviceEventEmitterUtil.sendMsgToRn("pay", payParams);
} catch (Exception e) {
Log.e("error", e.getMessage());
}
}
在原生创建的包管理器的createNativeModules
方法中实例化(注册)该工具类。
RN侧实现
//4.1 导入NativeEventEmitter、NativeModules组件
import {
NativeModules,
NativeEventEmitter,
} from 'react-native';
//4.2 通过【NativeModules.原生导出模块】实例化NativeEventEmitter对象
const androidEventEmitter = new NativeEventEmitter(
NativeModules.AndroidNativeModule);
/**
* 4.3 监听原生主动发送过来的消息
*/
listenerNativeMsg() {
//监听原生的order消息事件
this.subScriptOrder = androidEventEmitter.addListener('order', (data) => {
Alert.alert('order:', JSON.stringify(data));
});
//监听原生的pay消息事件
this.subScriptPay = androidEventEmitter.addListener('pay', (data) => {
Alert.alert('pay:', JSON.stringify(data));
});
}
//4.4 开启事件订阅(建议在UNSAFE_componentWillMount中)
UNSAFE_componentWillMount(): void {
console.log('开启订阅');
this.listenerNativeMsg();
}
//4.5取消事件订阅(建议在componentWillUnmount中)
componentWillUnmount(): void {
console.log('取消订阅');
this.subScriptOrder.remove();
this.subScriptPay.remove();
}
IOS端通过Promise机制被动发送消息到RN,实现上与RN调用IOS端方法实现相似,唯一不同点是参数最后两个分别是Promise的RCTPromiseResolveBlock
和RCTPromiseRejectBlock
类型。
步骤
相同步骤参考《RN调用IOS原生方法》
不同点实现文件中:
2.1 使用
RCT_EXPORT_METHOD
宏,导出的函数最后两个参数为RCTPromiseResolveBlock
和
RCTPromiseRejectBlock
。
实现
创建头文件略(参考《RN调用IOS原生方法》)
创建头文件实现文件(.m)
//2.创建实现文件
#import <Foundation/Foundation.h>
#import "Hello.h"
@implementation Hello
//使用RCT_EXPORT_MODULE(js_name)宏,标记导出的原生模块。
RCT_EXPORT_MODULE(IOSNativeModule);
//2.1 导出供RN调用的方法(有参且原生通过Promise机制返回数据到RN)
RCT_EXPORT_METHOD(callIosParamsMethodAcceptBackMsg:(NSString *)msg resolve:(RCTPromiseResolveBlock)resolve reject:(RCTPromiseRejectBlock)reject) {
NSString *toRnMsg = @"IOS:Hello RN Nice to meet you! !";
if (![msg isEqualToString:@""]) {
NSString *response =[NSString stringWithFormat:@"\n\n%@\n%@",msg,toRnMsg];
resolve(response);
} else {
reject(@"warning", @"msg cannot be empty!", nil);
}
}
@end
RN侧调用
//1.导入NativeModules组件
import {
NativeModules} from 'react-native';
//2.使用NativeModules.原生导出模块.方法名
NativeModules.IosNativeModule
.callIosParamsMethodAcceptBackMsg('RN:Hello IOS !')
.then((response) => {
Alert.alert('Title', response);
}).catch((error) => {
Alert.alert('Title', error.message);
});
即使没有使用Promise机制被RN被动调用,原生模块也可以主动给RN发送事件通知,最好的办法是继承RCTEventEmitter
,实现supportEvents
方法并调用self sendEventWithName:
实现。
步骤
创建头文件(
.h
)继承RCTEventEmitter
(需要导入RCTEventEmitter.h
和RCTBridgeModule.h
)创建实现文件(
.m
):2.1 使用
RCT_EXPORT_MODULE(js_name)
宏,导出原生模块。2.2 实现
supportedEvents
方法并且返回发送事件的名称(后续原生通过该事件名称发送消息到RN, RN端通过该事件名称接收消息)。
2.3 原生调用
[self sendEventWithName:事件名称,body:]
来发送消息到RN端。RN端使用:
3.1 导入
NativeEventEmitter
和NativeModules
组件。3.2 使用解构赋值原生导出模块实例化出
NativeEventEmitter
对象。3.3 构造函数中声明事件订阅的局部变量。
3.4 使用
NativeEventEmitter
实例对象调用addListener(evnetName,listenerFunaction)
指定原 生
supportedEvents
函数中声明的事件名称,以及回掉函数即可。3.5 在需要地方进行事件订阅(推荐在
UNSAFE_componentWillMount
中进行订阅)。3.6 在需要地方取消订阅(
componentWillUnmount
中取消订阅)。
实现
创建头文件(.h
)
//1.创建头文件
#import <Foundation/Foundation.h>
//导入RCTBridgeMOdule和RCTEventEmitter头文件
#import <React/RCTBridgeModule.h>
#import <React/RCTEventEmitter.h>
//继承RCTEventEmitter父类
@interface SendMsgToRn :RCTEventEmitter<RCTBridgeModule>
@end
创建实现文件(.m)
//2.创建头文件
#import "SendMsgToRn.h"
@implementation SendMsgToRn
//2.1使用RCT_EXPORT_MODULE(js_name)宏导出模块
RCT_EXPORT_MODULE(IosNativeModule)
//2.2实现RCTEventEmitter类中的supportedEvents方法,返回事件名称(可以定义多个事件名称)
- (NSArray<NSString *> *)supportedEvents{
return @[@"order",@"pay"];
}
//2.3原生主动向RN发送事件方法封装
-(void)sendMsgToRn:(NSString *)eventName eventData:(NSObject *)params{
NSLog(@"发送事件名称%@,发送事件参数%@",eventName,params);
//最终调用父类(RCTEventEmitter)的sendEventWithName方法指定事件名称来发送消息
[self sendEventWithName:eventName body:params];
}
@end
模拟客户端调用该类方法向RN发送消息
-(void)sendMsgToRn{
NSObject *order = @{
@"orderTime":@"20191218125942",
@"orderAmount":@"14888.88",
@"orderName":@"MacBook Pro"};
//调用提交订单方法
[self sendMsgToRn:@"order" eventData:order];
//调用支付方法
NSObject *payInfo = @{
@"orderId":[NSNumber numberWithInteger:9876563541]};
[self sendMsgToRn:@"pay" eventData:payInfo];
}
RN侧实现
//3.1 导入NativeModules、NativeEventEmitter组件
import {
NativeModules,
NativeEventEmitter,
} from 'react-native';
//3.2 通过【NativeModules.原生导出模块】实例化NativeEventEmitter对象
const iosEventEmitter = new NativeEventEmitter(NativeModules.IosNativeModule);
export default class MyCommonent extends Component{
//3.3 构造方法中定义局部订阅变量
constructor(props) {
super(props);
let subscribeOrder;
let subscribePay;
}
//3.4 使用实例化后的NativeEventEmitter对象调用addListener方法(指定事件名称和回调函数)
listenerNativeMsg(){
//监听原生的order事件
this.subscribeOrder = iosEventEmitter.addListener('order',(data)=>{
Alert.alert('order:', JSON.stringify(data));
});
//监听原生的pay事件
this.subscribePay = iosEventEmitter.addListener('pay',(data)=>{
Alert.alert('order:', JSON.stringify(data));
});
}
//3.5 UNSAFE_componentWillMount中开启订阅
UNSAFE_componentWillMount(): void {
console.log('开启订阅');
this.listenerNativeMsg();
}
//3.6 别忘记在componentWillUnmount声明周期方法中取消订阅
componentWillUnmount(): void {
console.log('取消订阅');
this.subscribeOrder.remove();
this.subscribePay.remove();
}
}
//ES6方式创建并导组件
export default class ComponentA extends Component{
render(){
return(
<Text>ES6方式创建组件</Text>
);
}
}
//ES5创建组件
//注意:React.createClass从0.48开始被删除,可以使用
//create-react-class 包中的 createReactClass 方法替代
var Hellocommpents=createReactClass({
render(){
return
<text style="{
{fontSize:15,backgroundColor:'green'"> Hellocommpents</text>
}
} )
module.exports=Hellocommpents;
//函数方式定义组件并导出
function Hellocommpents() {
//注意结尾需要带 ";"
return <text style="{
{fontSize:15,backgroundColor:'green'"> Hellocommpents</text>;
}
module.exports=Hellocommpents;
或者
//或者 函数方式定义组件并导出
const Hellocommpents = ({
title,onClick})=>(
<View>
<Text>标题{
title}</Text>
<Button
title={
'确认'}
onPress={
onClick}/>
</View>
)
//定义属性约束
Hellocommpents.propTypes = {
onClick: PropTypes.func.isRequired,
text: PropTypes.string.isRequired
}
//导出组件
export default Hellocommpents;
使用React-native创建的组件是可以复用的,所以我们封装的组件可以用在其他项目或给项目组其他人使用。但是别人可能对这个组件不熟悉,经常忘记使用某些属性,或者某些属性传递的数据类型有误。因此我们可以在开发React Native自定义组件时,可以通过PropTypes属性确认来声明这个组件需要哪些属性。这样,如果在调用这个自定义组件时没有提供相应的属性,则会在手机与调试工具中弹出警告信息,告知开发者该组件需要哪些属性。
简言之使用Prop-Types属性确认优点:
注意:
要求属性是指定的JavaScript基本类型
属性名: PropTypes.array, //指定属性为数组类型
属性名: PropTypes.bool, //指定属性为布尔类型
属性名: PropTypes.func, //指定属性为函数类型
属性名: PropTypes.number, //指定属性为数值类型
属性名: PropTypes.object, //指定属性为Object类型
属性名: PropTypes.string, //指定属性为字符串类型
要求属性是可渲染的节点
属性名:PropTypes.node,
要求属性是某个React元素
属性名:PropTypes.element,
要求属性是某个指定类的实例
属性名:PropTypes.instanceOf(NameOfAClass),
要求属性取值为特定的几个值
属性名:PropTypes.oneOf(['value1','value2']),
要求属性为指定类型中的一个
属性名:PropTypes.oneOfType([
PropTypes.bool,
PropTypes.number,
PropTypes.instanceOf(NameOfAClass),
])
要求属性为指定类型的数组
属性名: PropTypes.arrayOf(PropTypes.number),
要求属性是一个有特定成员变量的对象
属性名: PropTypes.objectOf(PropTypes.number),
要求属性是一个指定构成方式的对象
属性名: PropTypes.shape({
color: PropTypes.string,
fontSize: PropTypes.number,
}),
属性可以是任意类型
属性名: PropTypes.any
PS:上述十种语法中都可以通过在后面加上isRequired
声明它是必需的。
属性名: PropTypes.array.isRequired,
属性名: PropTypes.any.isRequired,
属性名: PropTypes.instanceOf(NameOfAClass).isRequired,
static defaultProps = {
name: 'scottDefault',
age: 12
}
import React,{
Component} from 'react';
import {
...} from 'react-native';
//定义组件并导出
export default class CompontentA extends Component{
//定义常量
const NAV_BAR_HEIGHT_ANDROID=50; //Android的NavigationBar高度
const NAV_BAR_HEIGHT_IOS = 44; //iOs的NavigationBar高度
const STATUS_BAR_HEIGHT=20; //状态栏高度
const StatusBarShape={
//状态栏形状的约束,用来属性确认
backgroundColor:PropTypes.string,
barStyle:PropTypes.oneOf('default' , 'light-content' , 'dark-content'),
hidden:PropTypes.bool,
}
//定义属性约束使用 static 修饰
static propTypes = {
style: PropTypes.object, //NavigationBar样式约束
title: PropTypes.string, //标题约束:文本类标题
titleView:PropTypes.element, //标题的样式约束
hide:PropTypes.bool, //是否隐藏NavigationBar
leftButton:PropTypes.element, //NavigationBar左侧按钮
rightButton:PropTypes.element, //NavigationBar右侧按钮
staturBar: PropTypes.shape(StatusBarShape), //状态栏
};
//给组件设置默认值使用static修饰
static defaultProps ={
staturBar:{
barStyle: 'light-content',
hidden:false,
}
}
render(
//获取用户设置的状态栏的样式,用于下面的取出
let statusView = <View
style={
[styles.staturBar , this.props.staturBar]}>
//取出用户设置的状态栏的样式
<StatusBar {
...this.props.staturBar}/>
</View>
let titleView = this.props.titleView ?
this.props.titleView :
<Text style={
styles.title}>{
this.props.title}</Text>;
let contentView = <View style={
styles.navBar}>
{
this.props.leftButton}
<View style={
styles.titleViewContainer}>
{
statusView}
{
titleView}
</View>
{
this.props.rightButton}
</View>;
return(
<View style={
styles.container}>
{
contentView}
</View>
);
}
}
构建完你的组件之后,你可能会想要去寻求一个办法,来直接调用你在
render()
返回的组件的实例的方法。在大部分情况下,这应该不是必须的,因为在响应式数据流中,你要输出一些数据,你应该在render()
中给子组件传递最新的属性。不过,在某些特殊情况下,直接操作组件实例的方法还是必要或者有利的。所以React提供了一个打破限制的办法,这就是refs
。refs
(reference,引用)在以下时候特别有用:当你需要直接操作一个组件渲染的DOM标记(譬如要调整它的绝对位置),或者在一个大型的非React应用中使用一个React组件,或者是把你已有的代码库在React中复用。
让我们来看看怎么获取一个ref
render() {
return(
//ES6箭头函数表示
<TextInput ref={(c)=>{this._input=c}}/>
);
}
//使用
componentDidMount() {
this._inputText.focus();
}
例如:A组件是登陆页面,B组件为自定义的输入框属于A组件的一个子组件,那么我们在B组件中的输入值在父组件A中如何获取呢?可通过props方式通过回调函数将子组件的数据回传到父组件中。
实现原理:
//自定义子组件
import React, {
Component} from 'react';
import {
View,
Text,
TextInput,
} from 'react-native';
export default class InPutComponent extends Component {
render() {
return (
<View style={
style.rootView}>
<Text
style={
{
backgroundColor: '#999', textAlign: 'center', flex: 1}}>
{
this.props.title}
</Text>
<TextInput
style={
{
flex: 3}}
placeholder={
this.props.placeholder}
//onChangeText绑定父组件传递过来的回调函数,将数据返回父组件
onChangeText={
(data)=>{
this.props.onChangeTextCallBack(data)}}/>
</View>
);
}
}
//父组件
import React, {
Component} from 'react';
import{
View} from 'react-native';
import InPutText from '../../common/InPutComponent';
export default class LoginComponent extends Component {
render() {
return (
<View>
{
/*父组件中使用子组件*/}
<InPutText
title='账号'
placeholder='请输入账号'
{
/*通过props传递一个回调函数给子组件*/}
onChangeTextCallBack={
(data,index) => {
console.log('index:' + index);
}}/>
</View>
}
这样当子组件输入框中的内容发生改变后会通过回调函数将数据返回到父组件的回调函数中。
Promise是什么?
Promise是ES6中新增的特性。在以往 JavaScript 中,所有代码都是单线程的,也就是同步执行的。而 Promise
就为异步编程
提供了一种解决方案。
Promise 对象是由关键字 new 及其构造函数来创建的。
const promise = new Promise(((resolve, reject))=>{
// do something here ...
if (success) {
resolve(value); // fulfilled成功
} else {
reject(error); // rejected失败
}
});
由上述代码我们可知:
resolve
和reject
。resolve
函数并执行,此时 Promise
对象状态从pending
变为fulfilled
;reject
函数并执行,此时 Promise
对象状态从pending
变为rejected
;接下来我们通过该对象的then
方法,分别指定resolved状态和rejected状态的回调函数
promise.then(function(value) {
// success
}, function(error) {
// failure
});
//或者
promise.then((value) => {
//success
}, (error)=> {
//failure
});
then
方法可以接收两个回调函数作为参数,第一个回调函数就是fulfilled
成功状态时调用;第二个回调函数就是rejected
失败时调用。这边的第二个参数是可选的,不一定要提供。
Promise 主要API方法
Promise.all(iterable)
参数
iterable 必须是一个可迭代对象,如 Array 或 String。
返回值
一个新的Promise
实例
Promise.all 的使用
如果传入的参数中存在不是
Promise
实例,则会先调用Promise.resolve
,将其转为Promise
实例,再进一步处理。
var p1 = Promise.resolve(3);
var p2 = 1337; //p2不是Promise对象,会通过Promise.resolve转换
var p3 = new Promise((resolve, reject) => {
setTimeout(resolve, 100, 'foo');
});
Promise.all([p1, p2, p3]).then(values => {
console.log(values);
});
// [3, 1337, "foo"]
Promise.resolve(value)
参数
如果参数是一个Promise
实例,则返回值是原封不动的返回该实例;
//通过resolve指定一个字符串为参数,返回一个Promise实例
var original = Promise.resolve('我在第二行');
//通过resolve指定一个Promise实例为参数,会将original Promise实例原封不动的返回;
var cast = Promise.resolve(original);
//比较两个Promise是否是同一个实例
console.log('original === cast ? ' + (original === cast));
cast.then((value)=>{
console.log('value: ' + value);
});
// "original === cast ? true"
// "value: 我在第二行"
如果参数是普通数据:[String|Array|Object|Number],直接将传入参数当最终结果并返回一个新的Promise
;
//通过resolve指定Number返回Promise实例
let p = Promsie.resolve(123);
//通过then方法指定回调函数
p.then((num)=>{
console.log(num);
});
// 123
如果不指定参数,直接返回一个resolved
状态的Promise
对象
//通过resovle不指定参数返回一个Promise实例
let p = Promsie.resovle();
//通过then方法回调函数接受的是无
p.then(()=>{
// do something here...
})
Promise.reject(reason)
参数:表示被拒绝的原因;
传入的参数会原封不动的作为 reject 函数的理由,并不会因为传入的参数 Promise 或者是 thenable 对象而有所不同;
返回值:一个含有reason
的状态为rejected
的Promise
async/await是什么?
async/await
是ES7提出的一种异步解决方案,相比较Promise
对象then 函数的嵌套Async/Await 可以让你轻松写出同步风格的代码同时又拥有异步机制,更加简洁,逻辑更加清晰。
async/await特性
返回值也是一个Promise对象
;最好把await放入try{}catch{}中,catch能够捕捉到Promise对象rejected的数据或者抛出的异常
;使用
await 后面跟着的应该是一个promise对象
(当然,其他返回值也没关系,只是会立即执行,不过那样就没有意义了…)//定义一个使用async修饰的函数,返回时一个Promise对象
const fetchPostTest = async (url, params) => {
console.log('url:' + url);
console.log('params:' + JSON.stringify(params));
//模拟请求返回数据(await后面跟着一个Promise对象,否则setTimeout无效会立即返回)
return await new Promise((resolve, reject) => {
setTimeout(() => {
resolve('返回数据了');
}, 5000);
});
}
安装npm和cnpm配置环境变量npm install cnpm -g --registry=https://registry.npm.taobao.orgnpm cache clean --force用当前项目下dos用 cnpm install --by=npm命令行环境的安装npm install --save-dev sass-loadernpm inst..._飞冰如何获取环境变量
并查集及例题
转 行业 | 做Quant,你以为靠Python和C++就够了吗?“对 Quant 而言 Python 的需求高吗,除 C++ 外还有哪些流行的编程语言?”1. 高2. 还有:Python, Java, Matlab, R, Q和一些公司内部自有语言(如高盛的自有语言)但是我不希望敷衍了事,说说我心中最重要的五类语言。这不仅仅是对于一个Quant必须的,而是一个丰满的程序员所必备的。在艺术..._pythn和c++
进程与线程的区别进程:CPU资源分配的最小的单位,由进程的各个线程共享线程:cpu执行调度的最小单位,优点充分利用CPU资源操作系统线程的实现主流的操作系统都提供了线程的实现(1)内核线程实现内核线程(KLT)就是由操作系统内核直接支持的线程,内核通过操纵调度器对线程进行调用,程序不直接与内核线程接触而是通过一种高级接口轻量级进程(LWP),它与内核线程一一对应,这就是我们...
一、Text输入框的属性属性 参考:Python学习笔记—— tkinter_03Button、Label_小橙子的博客-程序员宅基地Python学习笔记—— tkinter_04 Entry(单行输入框)_小橙子的博客-程序员宅基地二、Text输入框的方法1.理解行和列多行文本,确定一个位置需要使用坐标。列数从0开始数行数从1开始数2.删除,插入、获取文本框里的内容:随意输入充当测试数据删除,插入、获取 都需要使用坐标或光标处,结尾等确定位..._tkinter的文本框不支持键盘输入
1、这里实现一个4列多行的Grid布局代码片段。_qgridlayout 最小高度
codeblocks默认源代码文件编码根据OS而定,编译时编码UTF-8。 在你不更改任何codeblocks配置时: 在WINDOWS中:源代码——WINDOWS-936(即GBK),编译后文件默认UTF-8 而输出windows会按GBK来解释 ,所以从GBK->UTF-8->GBK就是乱码; 在LINUX中:源代码——..._code blocks _tmain
在Administrator(管理员)创建其他新用户时,忘记其他新用户的密码或者其他新用户密码是默认状态时,可以通过进行如下操作:1 点击如下在mysql中的Admin;j结果如下,再点击左边一栏的bugtracker;_mantis 忘记管理员密码
1 viakiba 325 天前 Sleuth + Zipkin 2 ayonel 325 天前 这些是监控系统干的活,国内比较好的是 CAT,但是系统比较庞大。或者 metrics,比较轻量。https://github.com/dropwizard/metrics 3 msaionyc 325 天前 java 平台 spri..._java接口调用统计开源组件
目录一.带宽与宽带的区别是什么?二.带宽、网速和流量之间的关系三.上行带宽和下行带宽是什么意思?各有什么作用?四.服务器的上行和下行带宽理解五.内网ip和外网ip区别一.带宽与宽带的区别是什么?带宽是量词,指的是网速的大小,比如1Mbps的意思是一兆比特每秒,这个数值就是指带宽。宽带是名词,说明网络的传输速率很高 。宽带的标准各不相同,最初认为128kbps以上带宽的就是宽带,而以下的就是窄带。但现在国内运营商一般提供至少512kbps带宽的宽带服务。也就是说,带宽是_服务器只要内网需要带宽带吗
dir /b转载于:https://www.cnblogs.com/sea-stream/p/10161818.html