1.组件的生命周期
实例化:
实例初次被创建,首次渲染时所调用的生命周期方法与其他各个后续实例被创建时所调用的方法略有不同。
在首次使用一个组件类时,下面方法依次调用顺序:
--getDefaultProps
组件类的该方法只会被调用一次
任何复杂的值(如对象和数组),都会在所有实例中共享而不是复制或克隆
--getInitialState
每个实例都会且仅会调用一次该方法,初始化每个实例的state;
与getDefaultProps不同:每个实例创建都会调用一次改方法,在Initial法里已经可以调用到this.props
--componentWillMount
该方法会在完成首次渲染之前被调用,是在render方法调用前修改组件state的最后一次机会
--render
在这里创建一个虚拟DOM,用来表示组件的输出。
对于一个组件来说,这是唯一一个必须的方法。
render需要满足以下几点:
--只能通过this.state和this.props访问数据;
--可以返回null, false或任何react组件;
--只能出现一个顶级组件(不能返回一组元素);
--必须纯净,即不能改变组件的状态或者修改DOM的输出。
render方法返回的结果不是真正的DOM,而是一个虚拟的表现,React随后会把他和真正的DOM(即内存中的DOM)做对比,来判断是否有必要做出修改。
--componentDidMount
render方法成功被调用并真正的DOM已经被渲染之后,可以在componentDidMount内部通过this.getDOMNode()方法访问到它。
可以用来访问原始DOM的生命周期钩子函数;
当React运行在服务端时,该方法不会被调用。
对于该组件的所有后续应用,下面方法依次调用:
--getInitialState
--componentWillMount
--render
--componentDidMount
存在期:
此时,组件已经渲染好,并且用户可以与他进行交互。
随着用户的操作,组件或者整个应用的state逐渐受到影响,下面方法被依次调用:
--componentWillReceiveProps
任意时刻,组件的props都可以通过父辈组件来更改。出现这种情况时,该方法会被调用,将获得更改props对象及更新state的机会。
--shouldComponentUpdate (一般不使用)
通过调用该方法在组件渲染时进行精确优化,即性能调优。
若确定某个组件或者它的任何子组件不需要渲染新的props或者state,则该方法会返回false(在首次渲染期间或调用forceUpdate()之后,这个方法不会被调用)。返回false是在告诉React要跳过调用render方法,以及位于render前后的钩子函数:componentWillUpdate和componentDidUpdate。
React插件提供PureRenderMixin方法进行性能调优。若组件纯净,对于相同的props和state,它总会渲染出一样的DOM,那么这个mixin会自动调用shouldComponentUpdate 方法来比较props和state,如果比较结果一致则返回false。
--componentWillUpdate
和componentWillMount 方法类似,组件会在接收到新的props或state进行渲染之前调用该方法。
注意:不可以在该方法中更新state或props。而应借助componentWillReceiveProps 方法在运行时进行更新state。
--render
--componentDidUpdate
和componentDidMount 方法类似,改方法给了我们更新已经渲染好的DOM的机会。
销毁/清理期:
当组件被使用完成后,componentWillUnmount方法将会被调用,目的是给这个实例提供清理自身的机会。
该方法会将在componentDidMount方法添加的所有任务都在该方法中撤销。
反模式:
即把计算后的值赋给state。
在getInitialState方法中,尝试通过this.props来创建state的做法是一种反模式。
2.数据流
Props:
props是properties的缩写,他可以把任意类型的数据传递给组件。
可以在挂载组件的时候(1)或通过调用组件实例的setProps方法(2)设置它的props:
eg1:
var surveys = [{title: 'Superheroes'}]; <ListSurveys surveys={surveys}/>
eg2:
var surveys = [{title: 'Superheroes'}];
var listSurveys = React.render(
<ListSurveys/>,
document.querySelector('body')
);
listSurveys.setProps({ surveys: surveys});
只能在组件(eg1)或者在组件树外(eg2)通过调用setProps。不能调用this.setProps或者直接修改this.props,若真的需要,请使用state。一个组件不能修改自己的props。
PropTypes:
通过在组件中定义一个配置对象,React提供了一种验证props的方式:
var SurveyTableRow = React.ceateClass({
propTypes: {
survey: React.PropTypes.shape({
id: React.PropTypes.number.isRequired
}).isRequired,
onClick: React.PropTypes.func
}
});
组件初始化时,如果传递的属性和propTypes不匹配,则会打印一个console.warn日志。如果是可选的配置,则可去掉.isRequired。
getDefaultProps:
设置非必须属性的默认值。
var SurveyTable = React.createClass({
getDefaultProps: function () {
return {
surveys: []
};
}
});
getDefaultProps并不是在组件实例化时被调用的,而是在React.createClass调用时就被调用了,返回值会被缓存起来。所以不能在getDefaultProps中使用任何特定的实例数据。
State:
每个React组件都有自己的state,state与props的区别在于前者只存在于组件的内部。
state可以通过setState来修改,也可以通过getInitialState方法提供一组默认值。只要setState被调用,render就会被调用。如果render函数返回值有变化,虚拟DOM就会更新,真实的DOM也会被更新,最终用户就会在浏览器中看到变化。
不能直接修改this.state,永远记得要通过this.setState方法修改。
state和props:
-- state中不保存计算出的值,值保存最简单的数据,即组件正常工作时的必要数据;
-- 不要尝试将props复制到state中。尽可能把props当做数据源使用;
-- 使用props在整个组件树中传递数据和配置;
-- 避免在组件内部修改this.props或调用this.setProps,请把props当做是只读的;
-- 使用props来做事件处理器,与子件通信;
-- 使用state存储简单的视图状态,比如下拉框是否可见;
-- 使用this.setState来设置状态,而不是this.state直接修改状态。
3.事件处理
从用户输入到更新用户界面:
-- 在React组件上绑定事件处理器;
-- 在事件处理器当中更新组件内部状态。组件状态的更新会触发重绘;
-- 实现组件的render函数用来渲染this.state的数据。
React对各种事件类型提供支持,具体支持类型:https://reactjs.org/docs/events.html
其中绝大部分事件不需要额外处理就能工作,但是触控事件需要通过调用:React.initializeTouchEvents(true)手动启动。
下面例子中的onChange就是一个时间处理
4.组件的复合
在传统HTML中,元素师构成页面的基础单元。但在React中,React组件是构成页面的基础单元。React组件可以看成混入了JavaScript表达能力的HTML元素。实际上写React代码主要就是构建组件。
本质上,一个组件就是一个JavaScript函数,它接受属性props和状态state作为参数,并输出渲染好的HTML。组件一般被用来呈现和表达应用的某部分数据,因此React可以理解为HTML的扩展。
当把表单渲染到屏幕上后,还没有赋予组件获取用户的修改能力,子组件还没有能力和它的父组件通信。
子组件和父组件通信的最简单方式是通过使用属性props。父组件需要通过属性传入一个回调函数,子组件在需要时进行回调。
eg:这里handleChanged是回调函数
var AnswerRadioInput = React.createClass({
mixins: [PropsMethodMixin],
propTypes: {
id: React.PropTypes.string,
name: React.PropTypes.string.isRequired,
label: React.PropTypes.string.isRequired,
value: React.PropTypes.string.isRequired,
checked: React.PropTypes.bool
},
getDefaultProps: function () {
return {
id: uniqueId('radio-'),
checked: false
};
},
getInitialState: function () {
return {
checked: !!this.props.checked
};
},
componentWillReceiveProps: function (nextProps) {
if(nextProps.checked !== undefined) {
this.setState({
checked: nextProps.checked
});
}
},
handleChanged: function (e) {
var checked = e.target.checked;
this.setState({checked: checked});
if(checked) {
this.callMethodOnProps('onChanged', this.props.value);
}
},
render: function () {
return (
<div className="radio">
<label>
<input type="radio"
name={this.props.name}
id={this.props.id}
value={this.props.value}
checked={this.state.checked}
onChange={this.handleChanged} />
{this.props.label}
</label>
</div>
);
}
});
复合组件只是React提供的用于定制和特殊化组件的方式之一。React的mixin提供了另一种途径,帮助我们可以在多组件之间共享的方法。
5.mixin
mixin解决代码重复,同时能让组件保持专注于自身的业务逻辑。mixin允许我们使用强大的抽象功能。
几种用法:
-- 一个监听事件并修改state的mixin(如:flux store mixin)
-- 一个上传mixin,它负责处理XHR上传请求,同时将状态以及上传的进度同步到state
-- 渲染层mixin,简化在</body>之前渲染子元素的过程(如渲染模态对话框)
Mixins有点类似AOP。所谓的mixins就是将组件里的方法抽出来。实际上Mixins里的this是指向组件的,使用了Mixins以后,组件也可以调用Mixins里的方法。
Mixins里也可以编写组件生命周期的方法,需要注意的是:Mixins里的方法并不会覆盖组件的生命周期方法,会在先于组件生命周期方法执行。
组件也可以使用多个Mixin,数组引入的顺序,决定了Mxins里生命周期方法的执行顺序。
除了生命周期方法可以重复以外,其他的方法都不可以重复,否则会报错。
eg:
var AMixin = {
componentWillMount: function () {
console.log('AMixin Will Mount');
}
};
var BMixin = {
componentWillMount: function () {
console.log('BMixin Will Mount');
}
};
var Component = React.createClass({
mixins: [AMixin,BMixin],
componentWillMount: function () {
console.log('Component Will Mount');
},
render: function () {
return (
<div>Component</div>
)
}
});
控制台打印:
$ AMixin Will Mount
$ BMixin Will Mount
$ Component Will Mount
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。