也可以在这里看:http://leozdgao.me/liao-jie-ge-reactzu-jian/
最近React,这个专注View层的库格外火热,我个人已经探索了一段时间,本来一直想写一些文字,总结下React应用开发和webpack构建工具的经验。不过懒癌复发,一直没动笔。前段时间给团队安利这个库,现在要开始用它写项目了,所以自己挖的坑要填上,就开始写一些基本的东西,就先从介绍React组件的基础开始。
从一个简单的组件开始
标题叫“一个简单的组件”,于是先来看下官方网站上一个叫做“A Simple Component”的例子来感受下:
var HelloMessage = React.createClass({
render: function() {
return <div>Hello {this.props.name}</div>
}
})
React.render(<HelloMessage name="John" />,mountNode)
好的,通过React提供的工厂方法,我们创建了一个组件,在这里,我们认为createClass 创建了一张blueprint,而通过jsx语法创建的<HelloMessage name="John" /> 则返回一个ReactElement 对象来具体地告诉React要如何渲染组件(因为除了blueprint以外还需要一些外部状态的传入),这等同于调用React.createElement(HelloMessage,{ name: 'John' },'Hello ',this.props.name) 。
之后,React就可以根据ReactElement 对象,把组件挂载到页面的某个节点上去,也就是React.render 方法在做的事情,这个方法返回一个组件的实例,同时也意味着你可以在已有项目中的一小部分尝试React。
下面来具体介绍下。
JSX
上面的例子里看着像是把HTML写在了Js里,实际上是通过一种更加清晰易读且易维护的语法JSX来创建ReactElement 对象。对React来说JSX是可选的,如果真的不喜欢也可以用React.createElement 这个api。
当然有JSX语法的js文件是不能直接在浏览器中运行的,我们可以用官方的JSXTransformer 或者是babel 来转换。
需要注意的是class 和for 这两个HTML属性,由于组件的属性实际是以对象形式传递的,比如上面的{ name: 'John' } ,另外js不允许关键字作为属性名,所以需要分别用className 和htmlFor 代替。
创建一个组件
创建组件的时候需要给React.createClass 提供一个对象,这个对象必须包含一个render 方法和若干可选的生命周期方法。
要注意的是我们需要保证render 函数是纯函数,即同样的输入始终返回相同的输出,并且执行过程中没有副作用(和DOM交互或者发Ajax请求)。但一个组件要和DOM交互或者发Ajax请求需求是很正常的,那么就要用到其他生命周期方法了。
除此之外,更重要的部分是,让一个组件可以工作除了有blueprint外,还需要组件状态。对于一个React组件来说,分为不可变状态this.props 和可变状态this.states 。
我们可以通过this.props 决定一个组件内的部分呈现内容,比如上例中我们希望呈现的名字是John,且不会改变。然而对于一个DropDownList 而言,仅在点击它时,一个下拉列表才会显示出来,那么我们认为这个下拉列表是否显示就是一个可变状态。
说到可变状态,那么要这么变?React并不希望我们直接修改this.states ,我们需要使用this.setState 的方式修改状态,因为每次调用this.setState ,render 方法都会被再次调用,同时也会调用一些相关的生命周期函数。this.setState 接受一个对象作为新状态的patch,也就是说这个对象不会覆盖现有的this.states ,而是一个类似extend的行为。
我们也可以提供一些默认状态:
getDefaultProps () {
return {
name: 'defaultName'
};
},getInitialState: function() {
return {
listShowed: false
};
},
其中getDefaultProps 仅会被调用一次,这里的意思是无论你会创建多少个ReactElement ,这个函数都只执行一次,之后的默认props 都会直接使用改函数的返回值。
这里需要提一下React提供以ES6的方式创建组件,有意思的是ES6的版本用的是React.Component ,在语意上比createClass 更加明确。getDefaultProps 和getInitialState 在ES6的版本中有些不太一样,相对与getDefaultProps ,ES6将默认属性对象作为了构造函数的一个属性,而getInitialState 则变成了在其构造器函数中给this.state 赋值,来看一个栗子:
class HelloMessage extends React.Component {
constructor (props) {
this.super(props)
this.state = { } // 初始化状态
}
render () {
return <div>Hello {this.props.name}</div>
}
}
HelloMessage.defaultProps = { name: 'defaultName' }
组件的生命周期
之前的部分一直有提到生命周期函数,下面就来介绍下:
componentWillMount 会在组件即将被挂载时调用,此时this.refs 对象为空对象。如果在该函数中使用this.setState ,那么会更新this.states 对象,而render 依然只会调用一次,相当于是可以覆盖getInitialState 返回的对象,虽然我觉得这没什么意义。
componentDidMount 是非常常用的生命周期方法,仅当组件被挂载后调用一次,这意味着可以在这个函数中进行一些DOM操作等,比如希望组件中的一个textbox可以再挂载后自动获取焦点:
componentDidMount () {
const textbox = React.findDOMNode(this.refs.text)
if (this.props.autoFocus) textbox.focus()
}
componentWillReceiveProps 在将要接受新的props 时被调用,不是说props 是不可变状态吗?情况通常是这样的,当一个父组件包含了一个子组件,子组件的一个props 的值是父组件的states 的值,那么当父组件可变状态改变时,子组件的props 也更新了,于是调用了这个函数。
componentWillReceiveProps (nextProps) {
if (this.props.disabled !== nextProps.disabled) {
// disabled这个属性改变了
}
}
这个生命周期函数componentWillReceiveProps 提供了更新states 的机会,可以调用this.setState ,也是唯一可以在组件更新周期中调用this.setState 的函数。
shouldComponentUpdate 是在更新前根据该函数的返回值决定是否进行这次更新。
shouldComponentUpdate (nextProps,nextState) {
// 比较props或者states,返回true则更新照常,返回false则取消更新,且不会调用下面的两个生命周期函数
}
考虑这种情况:父组件有子组件A和子组件B,当父组件调用this.setState 更新一个作为子组件A属性的state 时,render 方法被再次调用,此时组件A和组件B同时被更新,其实真正改变的只有组件A,但组件B也同时被要求更新了,这是没有必要的,于是shouldComponentUpdate 就显的有用了,在该函数体内比较props 或是states ,如果没有改变就取消这个更新,这对性能上算是一个提升。
但如果是复杂对象的比较就比较麻烦了,因为我们无法通过=== 来判断两个对象的键值是否都相等,于是我们就希望我们的对象是不可变的(immutable)。这里不再展开了,大家可以先自行探索,之后再写这个部分的文字,并介绍immutable.js
componentWillUpdate 在组件被更新前调用一次,可以用来做一些更新前的准备工作,举个栗子:
componentWillUpdate (nextProps,nextState) {
if (!this.props.isShowed && nextProps.isShowed) {
// 比如下拉菜单此时变的显示了,可以对此监听一些事件什么的
}
if (this.props.isShowed && !nextProps.isShowed) {
// 比如下拉菜单隐藏了,可以在这里取消事件监听
}
}
(组件更新前事情还蛮多的...)
componentDidUpdate 在组件更新完成后调用,可以考虑在这个函数中执行一些DOM操作什么的。
注意:绝对不要在componentWillUpdate 和componentDidUpdate 中调用this.setState 方法,否则将导致无限循环调用。
componentWillUnmount 会在组件即将从挂载点移去时调用,此方法专门用来『擦屁股』,比如去除即将被销毁的DOM节点的引用,或者是清除计时器,取消监听的时间等等。
好了,正文结束,这一篇介绍了React比较基础的部分,希望对大家有帮助,之后还会有一些更有针对性的部分。如文章中内容有误,还请指正。 (编辑:李大同)
【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!
|