组件、元素、生命周期
React组件和元素两个概念容易混淆。React元素是一个普通得javascript对象,这个对象通过DOM节点或React组件描述界面是什么样子的。JSX语法就是用来创建React元素的。
React组件是一个class或函数,它接收一些属性作为输入,返回一个React元素。React组件是由若干React元素组件而成的。
组件从被创建到被销毁的过程称为组件的生命周期。通常,组件的生命周期可以分为三个阶段:挂载阶段、更新阶段、卸载阶段。
挂载阶段:这个阶段组件被创建,执行初始化,并被挂载到DOM中,完成组件的第一次渲染。依次调用的生命周期方法有:constructor,componentWillMount,render,componentDidMount.
constructor,必须在这个方法中首先调用super(props)才能保证props被传入组件中。constructor通常用于初始化组件的state以及绑定事件处理方法等工作。
componentWillMount这个方法在组件被挂载到DOM前调用,且只会被调用一次。
render这是定义组件时唯一必要的方法。在这个方法中,根据组件的props和state返回一个React元素,用于描述组件的UI,通常React元素使用JSX语法定义。
componentDidMount在组件被挂载到DOM后调用,且只会被调用一次。这个时候已经可以获取到DOM解构,因此依赖DOM节点的操作可以放到这个方法中。在这个方法中调用this.setState会引起组件的重新渲染。
更新阶段
组件被挂载到DOM后,组件的props或state可以引起组件更新。无论props是否改变,父组件render方法每一次调用,都会导致组件更新。state引起的组件更新,是通过调用this.setState修改组件state来触发的。组件更新阶段,依次调用的生命周期方法:componentWillReceiveProps,shouldComponentUpdate,componenetWillUpdate,render,componentDidUpdate.
componentWillReceiveProps这个方法只在props引起的组件更新过程中,才会被调用。state引用的组件更新并不会触发该方法的执行。
shouldComponentUpdate这个方法决定组件是否继续执行更新过程。
componentWillUpdate这个方法在组件render调用前执行,可以作为组件更新发生前执行某些工作得地方,一般也很少用到。
componentWillUnmount这个方法在组件被卸载前调用,可以在这里执行一些清理工作。
只有类组件才具有生命周期方法,函数组件是没有生命周期方法的,因此不要在函数组件中使用声明周期方法。
列表和keys
不推荐使用索引作为key,因为一旦列表中的数据发生重排,数据的索引也会发生变化,不利于React的渲染优化。虽然列表元素的key不能重复,但这个唯一性仅限于在当前列表中,而不是全局唯一。
事件处理
在React中,事件的命名采用驼峰命名方式,而不是DOM元素中得小写字母命名方式。
处理事件的响应函数要以对象的形式赋值给事件属性,而不是DOM中得字符串形式。
React中得事件是合成事件,并不是原生的DOM事件。在DOM事件中,可以通过处理函数返回false来阻止事件的默认行为,但在React事件中,必须显式地调用事件对象的preventDefault方法来阻止事件的默认行为。
在React组件中处理事件最容易出错的地方是事件处理函数中this的指向问题。React事件处理函数的写法主要有三种方式,不同的写法解决this指向问题的方式也不同。
1,使用箭头函数。直接在React元素中采用箭头函数定义事件的处理函数。可以把逻辑封装成组件的一个方法,然后在箭头函数中调用这个方法。直接在render方法中为元素事件定义事件处理函数,最大得问题是,每次render调用时,都会重新创建一个新的事件处理函数,带来额外的性能开销,组件所处层级越低,这种开销越大,因为任何一个上层组件的变化都可能会触发这个组件的render方法。当然,在大多数情况下,这点性能损失是可以不必在意的。
2,使用组件方法,直接将组件的方法复制给元素的事件属性,同时在类得构造函数中,将这个方法的this绑定到当前对象。这种方式的好处是每次render不会重新创建一个回调函数,没有额外的性能损失。但在构造函数中,为事件处理函数绑定this,尤其是存在多个事件处理函数需要绑定时,这种模板式得代码还是会显得繁琐。
3,使用ES7的property initializers会自动为class中定义的方法绑定this。这种方式既不需要在构造函数中手动绑定this,也不需要担心组件重复渲染导致的函数重复创建问题。官方脚手架是支持的,也可以引用babel的transform-class-properties插件获取这个特性支持。
handleClick= (event) =>{ ///xxxx } <button onClick={this.handleClick}>click</button>
如果一个表单元素的值是由React来管理的,那么它就是一个受控组件。