从零学React Native之02状态机
2016-08-02 09:00
246 查看
本篇文章首发于简书 欢迎关注
之前我们介绍了RN相关的知识:
是时候了解React Native了
从零学React Native之01创建第一个程序
本篇文章主要介绍下下面的知识:
1.简单界面的搭建
2.状态机添加
3.渲染框架简介
4.语法简化
进入项目目录下,修改下index.android.js(开发IOS程序修改index.ios.js)
在上面的代码里, AwesomeProject和创建的项目的名称一样, 在这里代表创建的一个组件, 是继承自Component,React Native 每个组件都具备render()方法,该方法用来绘制UI, 这个方法直接return了一个JSX代码描述的UI组件。
const styles定义了组件的样式.
当一个组件通过AppRegistry API向React Native注册后,React Native框架将把这个组件渲染到手机屏幕上,并在发生UI事件时,将相应的UI事件通知给组件.这样,代码就能进行UI处理与相应的业务逻辑处理了.
大家也不难猜到,当React Native框架渲染一个组件到手机屏幕时,会调用该组件的render函数,并按render函数返回的JSX代码描述的可渲染元素来渲染手机UI界面.
React框架将所有的UI视为一个简单的状态机,那么任意一个UI场景就是状态机中的一种状态.
状态机的值一旦变化, 默认界面就会重新渲染,这样一个过程可以很轻松的做到数据与UI保持一致.我们只需要空间状态机中的值就行.
修改代码:
其中构造函数中初始化了状态机的值, 然后在组件中声明了两个方法用来修改状态机的值, 在TextInput中onChangeText时 调用该方法, 说白了就是当用户输入的时候状态机的值就会变化.
当需要改变状态机变量的值时, 一定要并且只能使用this.setState函数,永远不要出现”this.state.某状态机变量名=某值” 这样的语句.这样的语句从JS语法上来说是合法的, 站在RN角度上就是不合法的.
RN开发的一个原则是努力让自己定义的RN组件成为无状态的RN组件,或者说在不影响程序结构的情况下,尽可能减少所有状态的RN组件数目.
这句话新手可能不太理解, 说白了就是本来可以不用状态机变量就可以实现的功能就不要用, 因为状态机变量的改变就会导致界面重新刷新.浪费性能.
哪些是必须有的状态机变量呢? 比如文本输入,摄像头拍照等等,这些都必须依赖状态机刷新界面.
一个好的React Native设计思路是: 创建多个只负责渲染数据的无状态React Native组件,将它们封装在一个有状态的React Native组件中,并把这个有状态的React Native组件的状态机变量的值通过props传给无状态的React Native组件. 这种思路后面的文章会专门介绍.
千万不要把一个React Native组件放在状态机变量中. 正确的做法是把它放在render函数中,让它成为本RN组件的子组件
setState函数的原型是:
RN会根据哪个状态机值变化,从而去做相应的渲染,如果setState函数将传入函数的返回值与当前状态机相比没有任何修改与增加,那么将不会进行渲染.
this.setState函数提供的第一个参数是之前的状态,提供第二个可选参数——一个回调函数,它将在setState完成并且重新渲染完成后调用.
我们来修改下updateNum函数并加入一个新的函数changeNumDone作为setState的第二个参数.
当我们在TextInput中分别输入 1 和 3 在chrome中调试来看看输出的日志
可以看到 输入1的时候 之前的状态机里面没有值, 这时候我们在return中添加了一个新的状态机的键值对——aBrandnewStateVariable, changeNumDone函数在之后调用,当输入3的时候就把之前状态机的键值对输出了.
如果在组件中实现这个函数,当RN决定重新渲染组件时,会先调用这个函数.如果返回false, RN将放弃渲染组件. 方法里面接收两个参数,分别代表接下里准备进行渲染所基于的props与state. props里面就包含的styles属性等等.
在当前组件中实现下面代码,看到的效果就是当输入的电话号码不超过3位的时候不会渲染.
甚至可以不定义上面的函数 直接在onChangeText中按照下面的写法, 实现的效果和上面一样,
更多精彩请关注微信公众账号likeDev,公众账号名称:爱上Android。
之前我们介绍了RN相关的知识:
是时候了解React Native了
从零学React Native之01创建第一个程序
本篇文章主要介绍下下面的知识:
1.简单界面的搭建
2.状态机添加
3.渲染框架简介
4.语法简化
搭建界面
之前我们介绍了如何创建一个应用,现在我们来开发一个简单的注册界面。注释都写在代码里了, 如下:进入项目目录下,修改下index.android.js(开发IOS程序修改index.ios.js)
import React, { Component } from 'react'; import { AppRegistry, //框架提供的API StyleSheet, Text, // RN提供的组件 View, TextInput // 记得引入组件 } from 'react-native'; //let是更完美的var let Dimensions = require('Dimensions');// 宽高 let totalWidth = Dimensions.get('window').width; //声明了三个变量,根据屏幕动态变化 let leftStartPoint = totalWidth * 0.1; let componentWidth = totalWidth * 0.8; class AwesomeProject extends Component { render() { return ( // 绘制渲染的控件 <View style={styles.container}> <TextInput style={styles.numberInputStyle} placeholder={'请输入手机号'}/> <Text style={styles.textPromptStyle}> 您输入的手机号: </Text> <TextInput style={styles.passwordInputStyle} placeholder={'请输入密码'} secureTextEntry={true}/> <Text style={styles.bigTextPrompt}> 确 定 </Text> </View> ); } } // 样式 const变量只能在声明的时候赋值一次 const styles = StyleSheet.create({ //各个组件都没有定义高度,父View设置了flex1,他会沾满整个高度,子组件没有设置会包裹内容 container: { flex: 1, //表示宽高会自动扩展 backgroundColor: 'white' }, numberInputStyle: { top: 20, // top left表示从父组件的顶端(左侧) 向下(向右) 多少位置显示 left: leftStartPoint, // height:30, // IOS开发需要加上该高度 width: componentWidth, backgroundColor: 'gray', fontSize: 20 }, textPromptStyle: { top: 30, left: leftStartPoint, // // height:30, // IOS开发需要加上该高度 因为IOS中TextInput不会自动设置高度 width: componentWidth, fontSize: 20 }, passwordInputStyle: { top: 50, left: leftStartPoint, width: componentWidth, backgroundColor: 'gray', fontSize: 20 }, bigTextPrompt:{ top:70, left:leftStartPoint, width:componentWidth, backgroundColor:'gray', color:'white', textAlign:'center',//位置居中显示 fontSize:60 } }); // 注册了 AwesomeProject 组件 AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
在上面的代码里, AwesomeProject和创建的项目的名称一样, 在这里代表创建的一个组件, 是继承自Component,React Native 每个组件都具备render()方法,该方法用来绘制UI, 这个方法直接return了一个JSX代码描述的UI组件。
const styles定义了组件的样式.
当一个组件通过AppRegistry API向React Native注册后,React Native框架将把这个组件渲染到手机屏幕上,并在发生UI事件时,将相应的UI事件通知给组件.这样,代码就能进行UI处理与相应的业务逻辑处理了.
大家也不难猜到,当React Native框架渲染一个组件到手机屏幕时,会调用该组件的render函数,并按render函数返回的JSX代码描述的可渲染元素来渲染手机UI界面.
添加状态机
接下来我们来处理下输入框了,如果你做过Android或者IOS开发, 对比下React Native,你会发现RN的设计思维和这俩不一样.React框架将所有的UI视为一个简单的状态机,那么任意一个UI场景就是状态机中的一种状态.
状态机的值一旦变化, 默认界面就会重新渲染,这样一个过程可以很轻松的做到数据与UI保持一致.我们只需要空间状态机中的值就行.
修改代码:
/** * Sample React Native App * https://github.com/facebook/react-native * @flow */ import React, { Component } from 'react'; import { AppRegistry, //框架提供的API StyleSheet, Text, // RN提供的组件 View, TextInput // 记得引入组件 } from 'react-native'; //let是更完美的var let Dimensions = require('Dimensions');// 宽高 let totalWidth = Dimensions.get('window').width; //声明了三个变量,根据屏幕动态变化 let leftStartPoint = totalWidth * 0.1; let componentWidth = totalWidth * 0.8; class AwesomeProject extends Component { //构造函数, 组件创建的时候会执行 constructor(props) { super(props); //必须有这句代码 父组件向子组件传递属性, 比如styles属性等 // 声明状态机的初始值 this.state = { inputedNum: '', inputedPw: '' }; } // 定义函数 updateNum(newText) { this.setState((state)=> { return { inputedNum: newText } }); } // 定义函数 updatePW(newText) { this.setState(()=> { // 用不到的参数也可以不用写 return { inputedPw: newText } }); } // 绘制渲染的控件 render() { return ( /*(newText)=>this.updateNum(newText) 它将收到的字符串为参数调用当前组件的updateNum函数,并且将updateNum函数的返回值返回 当前函数在输入框文本变化的时候会调用 语句可以改成 this.updateNum 但一定不要写成 this.updateNum(newText) 因为有右箭头函数的时候newText是形式参数 没有箭头函数的时,newText就没有定义 */ <View style={styles.container}> <TextInput style={styles.numberInputStyle} keyboardType={'phone-pad'} placeholder={'请输入手机号'} onChangeText={(newText)=>this.updateNum(newText)}/> <Text style={styles.textPromptStyle}> 您输入的手机号:{this.state.inputedNum} </Text> <TextInput secureTextEntry={true} style={styles.passwordInputStyle} placeholder='请输入密码' onChangeText={(newText)=>this.updatePW(newText)}/> <Text style={styles.bigTextPrompt}> 确 定 </Text> </View> ); } } // 样式 const变量只能在声明的时候赋值一次 const styles = StyleSheet.create({ //各个组件都没有定义高度,父View设置了flex1,他会沾满整个高度,子组件没有设置会包裹内容 container: { flex: 1, //表示宽高会自动扩展 backgroundColor: 'white' }, numberInputStyle: { top: 20, // top left表示从父组件的顶端(左侧) 向下(向右) 多少位置显示 left: leftStartPoint, // height:30, // IOS开发需要加上该高度 width: componentWidth, backgroundColor: 'gray', fontSize: 20 }, textPromptStyle: { top: 30, left: leftStartPoint, // // height:30, // IOS开发需要加上该高度 因为IOS中TextInput不会自动设置高度 width: componentWidth, fontSize: 20 }, passwordInputStyle: { top: 50, left: leftStartPoint, width: componentWidth, backgroundColor: 'gray', fontSize: 20 }, bigTextPrompt: { top: 70, left: leftStartPoint, width: componentWidth, backgroundColor: 'gray', color: 'white', textAlign: 'center',//位置居中显示 fontSize: 60 } }); // 注册了 AwesomeProject 组件 AppRegistry.registerComponent('AwesomeProject', () => AwesomeProject);
其中构造函数中初始化了状态机的值, 然后在组件中声明了两个方法用来修改状态机的值, 在TextInput中onChangeText时 调用该方法, 说白了就是当用户输入的时候状态机的值就会变化.
当需要改变状态机变量的值时, 一定要并且只能使用this.setState函数,永远不要出现”this.state.某状态机变量名=某值” 这样的语句.这样的语句从JS语法上来说是合法的, 站在RN角度上就是不合法的.
RN开发的一个原则是努力让自己定义的RN组件成为无状态的RN组件,或者说在不影响程序结构的情况下,尽可能减少所有状态的RN组件数目.
这句话新手可能不太理解, 说白了就是本来可以不用状态机变量就可以实现的功能就不要用, 因为状态机变量的改变就会导致界面重新刷新.浪费性能.
哪些是必须有的状态机变量呢? 比如文本输入,摄像头拍照等等,这些都必须依赖状态机刷新界面.
一个好的React Native设计思路是: 创建多个只负责渲染数据的无状态React Native组件,将它们封装在一个有状态的React Native组件中,并把这个有状态的React Native组件的状态机变量的值通过props传给无状态的React Native组件. 这种思路后面的文章会专门介绍.
千万不要把一个React Native组件放在状态机变量中. 正确的做法是把它放在render函数中,让它成为本RN组件的子组件
充分了解状态机
我们再来充分了解下状态机, 修改状态机可以使用setState函数, 其实RN还提供了另外两个函数, replaceState函数与forceUpdate函数,但是不建议大家用.setState函数的原型是:
setState(object oldState,function callback)
RN会根据哪个状态机值变化,从而去做相应的渲染,如果setState函数将传入函数的返回值与当前状态机相比没有任何修改与增加,那么将不会进行渲染.
this.setState函数提供的第一个参数是之前的状态,提供第二个可选参数——一个回调函数,它将在setState完成并且重新渲染完成后调用.
我们来修改下updateNum函数并加入一个新的函数changeNumDone作为setState的第二个参数.
updateNum(newText) { this.setState((state)=> { for(var aName in state){ // 遍历之前的状态的 键和值 console.log(aName); console.log(state[aName]); } return { // 改变状态机变量 inputedNum: newText, aBrandnewStateVariable:'I am a new variable.' //添加了新的状态机变量 }; },this.changeNumDone); // setSate函数的回调函数, 当设置完成重新渲染完成后调用 } changeNumDone(){ console.log('React Native has changed inputed Num'); }
当我们在TextInput中分别输入 1 和 3 在chrome中调试来看看输出的日志
可以看到 输入1的时候 之前的状态机里面没有值, 这时候我们在return中添加了一个新的状态机的键值对——aBrandnewStateVariable, changeNumDone函数在之后调用,当输入3的时候就把之前状态机的键值对输出了.
判断是否渲染
如果你有些特殊需求,不想让状态机的值一变化就刷新,RN也提供了另一个方法boolean shouldComponentUpdate(object nextProps,object nextState)
如果在组件中实现这个函数,当RN决定重新渲染组件时,会先调用这个函数.如果返回false, RN将放弃渲染组件. 方法里面接收两个参数,分别代表接下里准备进行渲染所基于的props与state. props里面就包含的styles属性等等.
在当前组件中实现下面代码,看到的效果就是当输入的电话号码不超过3位的时候不会渲染.
// 接下来是否进行渲染 shouldComponentUpdate(object nextProps, object nextState) shouldComponentUpdate() { //接下来是否进行渲染 if(this.state.inputedNum.length<3) return false; return true; }
简化写法
有些方法还可以简化, 比如下面的函数就可以简化一下//updatePW(newText) { // this.setState(()=> { // 用不到的参数也可以不用写 // return { // inputedPw: newText // } // }); //} // 简化写法 updatePW(inputedPw) { this.setState({inputedPw}); }
甚至可以不定义上面的函数 直接在onChangeText中按照下面的写法, 实现的效果和上面一样,
onChangeText={(inputedPw)=>this.setState({inputedPw})
更多精彩请关注微信公众账号likeDev,公众账号名称:爱上Android。
相关文章推荐
- 从零学React Native之02状态机
- Java基础复习笔记 对象状态、引用种类、垃圾回收形式02
- 最近状态纪实02-21
- T-CODE:IE02修改设备数据(一般数据,状态),通过bapi实现
- Git学习笔记02—git文件的三种状态
- 黑马程序员--04.多线程--02.【run()和start()】【线程的运行状态】【获取想成对象及其名称】
- ios-day08-02(ios的通知机制:通知的发布、监听、移除,一些常见的系统通知、键盘状态的通知、通知和代理的异同)
- 02_ARM汇编自学笔记模型之ARM微处理器的工作状态
- ESFramework 开发手册(02) -- 基础功能与状态通知
- Java多线程下载框架02:观察者模式通知下载内容状态更新
- 10-02-04 再说状态
- Rhythmk 学习 Hibernate 02 - Hibernate 之 瞬时状态 离线状态 持久化状态 三状态
- 02-Hibernate实体类的三种状态
- 【hibernate】02-对象的四种状态
- 网络开始---多线程---NSThread-02-线程状态(了解)(三)
- 下拉框,绑定数据,无法保持状态(绑定列必须是值类型)
- 三、ASP.NET应用程序状态管理
- HTTP 1.1状态代码及其含义说明
- UML总结—状态图(State Diagram)
- 卸载KDE / Xfce / LXDE 回到纯Unity 的状态