由于他们三者实际使用中可能会有或多或少的联系,为了便于理解和后续的使用,这里先拥挤一下,写到一起,方便查看,这里分解介绍 状态机state、父子组件、props
状态机state
顾名思义状态机就是保存状态的装置,在RN里面,其实就是state,我们可以通过设置state和改变state里面的值来设置和调整UI元素的变动,对于不需要变动的UI写死即可
举个例子:
1.初始化UI
//构造方法 constructor里面设置初始state
this.state= {
name: '充电宝',
gender: '未知'
}
//render里面设置UI
<View>
<Text>{this.state.name}</Text>
{
this.state.gender !== '未知'
&&
<Text>{this.state.gender}</Text>
}
</View>
以上代码设置完毕后,会发现界面上只显示了一个充电宝,正常显示
下面的gener是在gender不为未知的情况下显示的,可以通过其条件性的控制UI的显隐,注意:{} 必须要有
2.更新UI
如果我们在网络请求完毕后,需要更新UI怎么办呢,以上为例
一般是在componentDidMout方法里面进行网络请求,这里界面初次初始化渲染成功,比较适合网络请求,此时网络请求完成值后只需要调用setState方法即可更新UI了,例如:
let result = request.fetch(params)
let name = result.name
let gender = result.gender
let age = result.age
this.setState({
name,
gender: gender,
age
})
//设置完成之后,name和gender就会根据最新值更新了,age由于UI的xml上没有用到,实际不会渲染的
通过setState方法设置成功后的变量其实就是,this.state = {} 里面的对象,当执行完毕setState方法之后,便会对新设置的值和以前UI树上面的值进行对比,如果不一样系统会自动更新替换xml树上的变量保存的内容,没有的状态值也不会影响渲染(但是会占用状态机控件,对比渲染时,影响渲染效率,性能优化时尽量避免此情况)
在上面可以看到设置state的时候,有的是直接写了一个键值就可以了,有的写上键值对的形式,其实,只要你上面声明的变量名和需要渲染的变量的键值一样,那么可以使用键值代替键值对
扩展: 学习了props可以尝试一下,在子视图或者别的视图中能不能通过父视图的引用设置父视图的state吧,相信掌握了会对以后的进阶有帮助的
父子组件和props
顾名思义,就是父组件和子组件,父组件在下,子组件在上,通过flexbox布局以及合理的使用他们的关系可以布局出各种各样的UI出来,在flexbox布局里面相信已经了解到他们之间是怎么结合布局的
这里介绍父子组件的传值,正常我们想的父子组件看到的view可能是这个样子的(这样传值好像没必要哈)
<View>
<View type={1}></View>
</View>
实际可能是这个样子,实际传值的内容可能是根据当前控制器(也是他的父视图),来传值的
<View>
<ChildView type={this.data.type}>
<ChileView>
</View>
//这样一个叫做type的属性就会传入到子视图当中去了,而子视图当中怎么接收呢,这就涉及到props了
props即属性,this.props自己的属性集合,父视图传过来的参数(属性),会存到子视图props里
子视图中可以通过this.props可以获取子视图自己的属性列表,如果传入了type,那么调用的时候可以通过这样获取,父视图也同理可以同样的方式获取到自己的
let type = this.props.type
const {type, name, gender} = this.props //一次获取多个属性变量
是不是很简单这样就可以传值了,那么子组件如果回调结果给父组件呢,方法如下
1.父视图设置一个回调(接口或者函数),子视图在合适的时机调用(推荐)
//fatherView
//render
render() {
return (
<ChildView onSubmit={()=>{
//父视图设置的回调方法,快捷方法
}}> </ChildView>
//当然有洁癖也可以也可以这样
<ChildView onSubmit={()=>this.submit()}> </ChildView> //推荐写法,避免错误
<ChildView onSubmit={this.submit.bind(this)}> </ChildView> //也可以这么调用
)
}
//如果view的回调声明onSubmit那里没有()=>或者调用bind(this),这里必须这么声明,一个好习惯,不然调用不到这个方法
submit = () => {
}
submit () {
}
//子视图
//render
render() {
return (
<TouchableOpacity
onPress={()=>{
this.props.onSubmit && this.props.onSubmit() //先判断一下是否存在在调用
}}>
</TouchableOpacity>
)
}
2.由于对象里面的方法均为public,那么可以通过传递父视图的引用,在子视图调用传值
//fatherView
//render
render() {
return (
//当然有洁癖也可以也可以这样
<ChildView superView={this}> </ChildView>
)
}
//如果view的回调声明onSubmit那里没有()=>或者调用bind(this),这里必须这么声明,一个好习惯,不然调用不到这个方法
submit = () => {
}
//子视图
//render
render() {
return (
<TouchableOpacity
onPress={()=>{
this.superView && this.superView.submit && this.superView.submit() //先判断一下是否存在在调用
}}>
</TouchableOpacity>
)
}
上面就是比较简单易用的父子组件传值了,以props为媒介来完成
上面子视图中通过传递父视图引用,是不是发现也可以拿到父视图的props和更新state了呢,由于方法都是public,试试去看看能不能拿到并且操作吧
属性声明
子控件prop如果未声明,正常写外面可能没有代码提示,正常该怎么声明让外界调用更方便呢
附上实例代码:
//默认属性,外面没实现里面使用这个(这个类似于类方法)
static defaultProps={
onUpdate: f => f //意思是什么也不执行,回调
title: '123'
}
//外面实现了里面会发生改变
static propTypes={
onUpdate: f => f //意思是什么也不执行,回调
title: text
}
}
父子组件渲染流程:
父组件:componentWillMount->render->componentDidMount
父子组件:componentWillMount(父)->componentWillMount(子)->render->componentDidMount(子)->componentDidMount(父)
又粘出来了,可以自己测试一下他们的顺序哈