1、JSX
1.1、引用变量
使用{var}来引用变量
1.2、属性
单个引用时,使用this.props.propertynames
多个引用时,使用...this.props
1.3、注释
使用 {}包裹
注意:
在html中,使用class作为属性名,在JSX中则使用className
对于 自包含的tag,如<img/> <br/> 在html中,/可以省略,但是在JSX中不能省略
2、状态
react状态是组件内部的可变数据存储,是 UI与逻辑的核心。
2.1 访问状态
state对象是组件的属性对象,可以通过this引用来访问。
不能在render()方法中调用setState,会导致死循环
2.2 设置初始状态
在render()方法中使用状态数据之前,必须对其进行初始化。要设置初始状态,在构造函数中使用this.state,同时之前调用 super(props)方法
2.3 更新状态
使用类方法this.setState(data,callback)来改变状态。当此方法被调用时,react将data和当前状态合并,然后调用render()方法,之后,react会调用callback.
2.4 状态 和属性
状态和属性都是类的特性,分别用this.state和this.props表示。状态和属性之间最主要的区别之一是:前者可变,后者不可变
状态和属性的另一区别是:属性从父组件传递,状态在组件内部而非父组件中定义。
2.5 无状态组件
设计目的只是渲染视图。当不需要状态时,可以使用函数替代React组件。
在无状态组件中,不能拥有状态,但可以有两个属性:propTypes和defaultProps
3、组件生命周期
3.1 事件分类
- 挂载:仅调用一次
componentWillMount()发生在挂载到DOM之前
componentDidMount()发生在挂载和渲染之后
挂载顺序为
constructor->getInitialState->getDefaultProps->componentWillMount->render->componentDidMount
- 更新:调用多次
componentWillReceiveProps(nextProps)发生在组件即将接收属性时
shouldComponentUpdate(nextProps, nextState)通过判断何时需要更新,何时不需要更新,允许对组件的渲染进行优化
compoentWillUpdate(nextProps, nextState)发生在组件将要更新之前
componentDidUpdate(prevProps,prevState)发生在组件更新完成之后
- 卸载:仅调用一次
componentWillUnmount()允许在组件卸载之前解绑所有的事件监听器或者做其他清理操作
3.2 组件
3.2.1 函数组件和class组件
函数组件定义如下
function ComponentName(props) {
return <h1>Hello, {props.name} </h1>
}
class组件定义为
class ComponentName extends React.Component {
render() {
return <h1> Hello, {this.props.name}</h1>
}
}
所有React组件都必须像纯函数一样保护它们的props不被更改
3.3 React的数据载体
包含state, props,context。state为内部状态或局部状态。props和context用于在组件间传递数据,props仅支持逐层传递,context能够跨级传递。
4、事件处理
4.1 处理DOM事件
通过定义事件处理程序来并在JSX中将它作为元素的属性值,对于事件名称属性,使用标准的W3C DOM事件名称,以驼峰规范命名。以声明函数出现时,需要使用bind(this)以便在事件处理程序 中可以引用类(React元素)的实例。如果不绑定,this会是null值。 在以下几种场景中,不应该使用bind(this)将上下文绑定到类的实例上
- 不需要通过this来引用类的实例时
- 使用旧的风格React.createClass()而不是ES6+的类风格时
- 使用箭头函数时(()=>{})
也可以在类的构造函数中为事件处理程序执行绑定
支持的 DOM事件
鼠标事件 | onClick,onContextMenu,onDoubleClick,onDrag, onDragEnd,onDragEnter,onDragExit,onDragLeave, onDrageOver,onDragStart,onDrop,onMouseDown,onMouseEnter, onMouseLeave, onMouseMove,onMouseOut,onMouseOver,onMouseUp |
键盘事件 | onKeyDown,onKeyPress,onKeyUp |
剪贴板事件 | onCopy,onCut,onPaste |
表单事件 | onChange,onInput,onSubmit |
焦点事件 | onFocus,onBlur |
触摸事件 | onTouchCancel,onTouchEnd, onTouchMove, onTouchStart |
UI事件 | onScroll |
滚轮事件 | onWheel |
选择事件 | onSelect |
图片事件 | onLoad, onError |
动画事件 | onAnimationStart, onAnimationEnd, onAnimationIteration |
过渡事件 | onTransitionEnd |
5、表单
表单属性
type | button:没有默认行为的按钮,上面显示value属性的值,默认为空 checkbox:复选框,可设为选中或未选中 color:用于指定颜色的控件;在支持的浏览器中,激活时会打开取色器 date:输入日期的控件(年、月、日,不包括时间)。在支持的浏览器激活时打开日期选择器或年月日的数字滚轮 datetime-local:输入日期和时间的控件,不包括时区。在支持的浏览器激活时打开日期选择器或年月日的数字滚轮 email:编辑邮箱地址的区域。 file:让用户选择文件的控件,使用accept属性规定控件能选择的文件类型 hidden:不显示的控件,其值仍会提交到服务器。 image:带图像的submit按钮。显示的图像由src属性规定 month:输入年和月的控件,没有时区 number:用于输入数字的控件。如果支持的话,会显示滚动按钮并提供缺省验证。 password:单行的文本区域,其值会被遮盖。 radio:单选按钮,允许在多个拥有相同name值的选项中其中一个 range:此控件用于输入不需要精确的数字。控件是一个范围组件,默认值为正中间的值,同时使用htmlattrdefmin和htmlattrdefmax来规定值的范围 reset:此按钮将表单的所有内容重置为默认值,不推荐。 search:用于搜索字符串的单行文字区域。 submit:用于提交表单的按钮 tel:用于输入 电话号码的控件。 text:默认值。单行的文本区域,输入中的换行会被自动去除 time:用于输入时间的控件,不包括时区。 url:用于输入url的控件。 week:用于输入 以年和周数组成的日期,不带时区。 |
6、扩展
6.1 默认属性
defaultProps静态属性。如果属性丢失,则会呈现默认值。设置默认属性值总是对的,因为这样做使得组件的容错性提高。
6.2 属性类型和验证
通过propTypes静态属性来实现。属性类型的这一功能不会强制改变属性值的数据类型,而是提供警告。也就是说,如果处于开发者模式,并且属性类型不匹配,则会在控制台和产品中收到警告消息;不用做任何处理来防止使用错误的类型。
所有类型都在PropTypes对象中,react的属性类型有
PropTypes.string | PropTypes.number |
PropTypes.bool | PropTypes.object |
PropTypes.array | PropTypes.func |
PropTypes.any.isRequired | PropTypes.objectOf(PropTypes.number) |
PropTypes.arrayOf(PropTypes.number) | PropTypes.node |
PropTypes.instanceOf(Message) | PropTypes.element |
PropTypes.oneOfType([PropTypes.numbere, ...]) |
定义自定义验证需要做的是创建一条返回Error实体的语句,然后在propTypes:{}中使用该语句作为属性的值。
6.3 渲染子组件
使用children属性{this.props.children}这种简单方式,可以渲染所有的子组件。
如果有多个子元素,它可以是一个数组,可以访问以下各个元素:{this.props.children[0]},{this.props.children[1]}
当只有一个元素时,this.props.children不是数组。如果使用this.props.length并且唯一的子元素不是字符串,将会导致bug产生。因为length是一个有效的字符口中属性。使用React.Children.count(this.props.children)获取子组件的准确计数。还有其它辅助方法:
React.Children.map()
React.Children.forEach()
React.Children.toArray()
6.4 高阶组件(High-Order Component)
使用displayName区分父组件与子组件
默认情况下,JSX使用类名作为实例的名称。当需要修改此名称时,有名为displayName的静态属性可用。
使用扩展运算符传递所有属性。
扩展运算符为(...)
高阶组件实现方式:代理方式(操纵props,访问ref, 抽取状态,包装组件), 继承方式(操纵props,操纵生命周期函数),以函数作为子组件
6.5 展示组件和容器组件
展示组件通常只添加DOM和样式,它们有属性,但是往往没有状态,大多数情况下,可以使用无状态组件的功能 。展示组件通常使用this.props.children作为包装器来创建子组件。
容器组件通常由HOC生成以注入数据源,它们有状态。
展示组件和容器组件都可以包含其他展示组件或容器组件,但在实践中,通常会使展示组件仅包含其他展示组件,使容器组件包含其他容器组件或展示组件。
7、Flux
8、Redux
单向数据流基础上,有三个基本原则:唯一数据源,保持状态只读,数据改变只能通过纯函数完成
8.1 异步redux
异步action构造函数的模式是在函数体内返回一个新的函数,这个新的函数可以有两个参数dispatch和getState,分别代表redux唯一的store上的成员函数dispatch和getState。
可以使用中间件redux-thunk,redux-saga,redux-effects,redux-side-effects,redux-loop, redux-observable
9、单元测试
9.1 分类
从人工操作还是写代码来操作的角度,分为手工测试和自动化测试
从是否需要考虑系统的内部设计角度 ,分为白盒测试和黑盒测试
从测试对象的级别,分为单元测试、集成测试和端到端测试
从测试验证的系统特性,分为功能测试、性能测试和压力测试。
9.2 单元测试框架
- Mocha +Chai
- Jest
Jest会自动 在当前目录 下寻找满足下列任一条件的Javascript文件作为单元测试代码来执行
- 文件名以.test.js为后缀的代码文件
- 存于__test__目录下的代码文件
一种方式,是在项目的根目录下创建一个名为test的目录,和存放功能代码的src目录并列,在test目录下建立和src对应子目录结构,每个单元测试文件都以.test.js后缀,就能够被Jest找到。这种方法是可以保持功能代码src目录的整洁,缺点就是单元测试中引用功能代码的路径会比较长。
另一种存放单元测试代码的策略是在每一个目录下创建__test__子目录,用于存放对应这个目录的单元测试。这种方法因为功能代码和测试代码放在一起,容易比对,缺点就是散布在各个目录下的__test__看起来不是很整洁。
9.3 单元测试代码组织
单元测试代码的最小单位是测试用例。在Jest框架下,每个测试用例用一个it函数代表,it函数的第一个参数是一个字符串,代表的就是测试脸名称 ,第二个参数是一个函数,包含的就是实际的测试用例过程。
测试套件由测试用例和其他测试套件构成,测试套件可以嵌套使用,测试套件和测试用例形成了下树形的组织结构 。describe函数包含与it函数一样的参数,两者主要的区别就是describe可以包含it或者另一个descibe函数调用 。
describe中有如下函数可以帮助重用代码
- beforeAll,在开始测试套件开始之前执行一次
- afterAll,在结束测试套件中所有测试用例之后执行一次。
- beforeEach,每个测试用例 在执行之前都执行一次。
- afterEach,每个测试用例在执行之后都执行一次。
参考资料:
《快速上手React编程》
《深入浅出react和redux》
《React学习手册》