本篇文章首发于简书 欢迎关注

之前我们介绍了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状态机的更多相关文章

  1. 从零学React Native之03页面导航

    之前我们介绍了RN相关的知识: 是时候了解React Native了 从零学React Native之01创建第一个程序 从零学React Native之02状态机 本篇主要介绍页面导航 上一篇文章给 ...

  2. 从零学React Native之13 持久化存储

    数据持久化就是指应用程序将某些数据存储在手机存储空间中. 借助native存储 这种方式不言而喻,就是把内容传递给native层,通过原生API存储,详见从零学React Native之05混合开发 ...

  3. 从零学React Native之11 TextInput

    TextInput 组件是用来通过键盘输入文字,可以使用View组件和Text组件样式,没有自己特定的样式. 与Text组件类似,TextInput组件内部的元素不再使用FlexBox布局,而采用文本 ...

  4. 从零学React Native之12 组件的生命周期

    一个React Native组件从它被加载,到最终被卸载会经历一个完整的生命周期.所谓生命周期,就是一个对象从开始生成到最后消亡所经历的状态,理解生命周期,是合理开发的关键. ES6语法和之前的ES5 ...

  5. 从零学React Native之04自定义对话框

    本篇主要介绍: 1. 自定义组件 2. Alert 对话框 自定义对话框 之前的我都是利用React Native提供的基础组件对它们进行排列组合, 其实自定义也很简单, 我们还是拿上一篇文章的例子进 ...

  6. 从零学React Native之14 网络请求

    通过HTTP或者HTTPS协议与网络侧服务器交换数据是移动应用中常见的通信方式. node-fetch是RN推荐的请求方式. React Native框架在初始化项目时, 引入了node-fetch包 ...

  7. 从零学React Native之10Text

    在React Native开发中,所有需要显示的字符串文本都需要放置在Text或者Text的子组件中.虽然在之前的文章中多次使用了Text组件,但是Text组件还是值得专门学习的, 并没有想象中的那么 ...

  8. 从零学React Native之08Image组件

    开发过程中, 几乎每个项目都会用到图片. RN就是通过Image组件显示图片.既可以加载网络图片,也可以加载本地资源图片. Image组件必须在样式中声明图片的款和高.如果没有声明,则图片将不会被呈现 ...

  9. 从零学React Native之07View

    View 组件是React Native最基本的组件.绝大部分其他React Native 组件. View组件的颜色和边框 backgroundColor 键用来指定颜色. RN 0.19版本开始, ...

随机推荐

  1. 使用Charles在iOS6上进行抓包

    抓取Web页面的网络请求很容易,Chrome和Firefox都很容易做到.iOS APP如何抓包呢?其实也很容易,我比较喜欢使用 Charles. 我用的是Mac电脑,首先建立一个热点,然后让iOS设 ...

  2. COOK50小结

    题目链接 很遗憾.看到第五题的通过人数就不敢做了.待日后补上. A题 求最长的连续子序列,使得他们满足gcd为1. 如果有相邻的两个数的gcd为1,那么整个序列的gcd值也就是1, 否则就是该序列不存 ...

  3. What every computer science major should know 每一个计算机科学专业的毕业生都应该都知道的

    Given the expansive growth in the field, it's become challenging to discern what belongs in a modern ...

  4. 文本流向 layout-flow

    作用与语法 文本流向layout-flow用来定义网页中的文本流向方式. 即排列方式,主要有两个属性,分别是horizonta (水平的) 和vertical-ideographic (垂直的). 文 ...

  5. P5562 [Celeste-B]Center of the Earth 题解

    构造 因为题目只要求两位相同,所以可以暴力枚举这两位所有的可能性,方案数为\(O(n^2)\). 但是,这么做是显然不优的,因为完全没有用到第三位. 观察题目条件:n为偶数. 就想一想能不能奇数偶数分 ...

  6. 用蒙特卡罗方法解非线性规划MATLAB

    共需要三个M文件,主程序为randlp.m randlp.m: function [sol,r1,r2]=randlp(a,b,n) %随机模拟解非线性规划 debug=1; a=0; %试验点下界 ...

  7. React高阶组件 和 Render Props

    高阶组件 本质 本质是函数,将组件作为接收参数,返回一个新的组件.HOC本身不是React API,是一种基于React组合的特而形成的设计模式. 解决的问题(作用) 一句话概括:功能的复用,减少代码 ...

  8. 使用 store 来优化 React 组件

    在使用 React 编写组件的时候,我们常常会碰到两个不同的组件之间需要共享状态情况,而通常的做法就是提升状态到父组件.但是这样做会有一个问题,就是尽管只有两个组件需要这个状态,但是因为把状态提到了父 ...

  9. umount报错解决device is busy

    umount –a   报错device is busy如图 df    -h 执行 umount -l /dev/sdk1 fuser -m -v /cache10 再查看卸载了

  10. java视频长度读取 方案参照文件

    ffmpeg库 必须http://ffmpeg.org/download.html#build-windows 第三方jar sauronsoftwarehttp://www.sauronsoftwa ...