<读书笔记>《React:引领未来的用户界面开发框架》
《React:引领未来的用户界面开发框架》(GitHub 附demo版)
1.Component的创建与复合
1.1 React简介
背景介绍,全书概览
1.本质上是一个状态机,它以精简的模型管理复杂的随着时间而变化的状态。
2.它不是model-view-controller,它是mvc中的v(view),用来渲染视图。
3.React运用虚拟的dom实现了一个强大的渲染系统。
4.(1)React就像高性能3d游戏引擎,以渲染函数为基础。这些函数读入当前的状态,将其转换为目标页面上的一个虚拟表现。只要react被告知状态有变化,它就会重新运行这些函数,计算页面的一个新的虚拟表现,接着自动化把结果转换成必要的dom更新来反应新的表现。
(2)乍一看,这种方式应该比通常的javascript方案(按需更新每一个元素要慢),但react确实是这么做的:它是用了非常高效的算法,计算出虚拟页面当前版本和新版间的差异,基于这些差异对dom进行必要的最少更新。
5.所以说react赢就赢在了:
- 最小化了重绘,
- 并避免了不必要的dom操作,
这两点都是公认的性能瓶颈。
6.react的虚拟表示差异算法,不但能够把这些问题的影响降到最低。 ,还能简化应用的维护成本。当用户输入或者有其他更新导致状态改变时,我们只要简单的通知react状态改变了,它就能自动化地处理剩下的事情。我们无须深入到详细的过程之中。
7.react在整个应用中只使用单个事件处理器,并且会把所有的事件委托到这个处理器上。这一点也提升了react的性能。因为如果有很多时间处理器也会导致性能问题。
1.2 jsx
1.2.1 什么是jsx?
jsx提供了一种在javascript中便携声明式的xml的方法:javascript xml
- 使用jsx之前:
React.DOM.h1({className: 'question'}, 'Question');
React.createElement('h1', {className: 'question'}, 'Question');
- 使用jsx之后:
<h1 className="question">Queations</h1>;
- 在react中使用jsx的好处:
- 允许使用熟悉的语法来定义html元素树
- 提供更佳语义化且易懂的标签
- 程序结构更容易被直观化
- 抽象了react element的创建过程
- 可以随时掌控html标签以及生成这些标签的代码
- 是原生的javascript
1.2.2 非dom属性值
-
key
- 通过给组件设置一个独一无二的键,并确保它在一个渲染周期中保持一致,使得react能够更智能地决定应该重用一个组件,还是销毁并重新创建一个组件,进而提升渲染性能。
-
ref
-
ref允许父组件在render方法之外保持对子组件的一个引用
-
在jsx中,你可以通过在属性中设置期望的引用名来定义一个引用。
render: function () { return <div> <input ref="myInput" .../> </div>; }
-
接着就可以在组件中的任何地方使用this.refs.myInput获取这个引用了(不是真实的dom,是react在需要时用来创建dom的一个描述对象。若要访问真实的节点,则可以使用:this.refs.myInput.getDOMNodes() )
- dangerouslySetInnerHTML(随时可能发生变化)
1.2.3 事件
在jsx中,捕获一个事件就像给组件的方法设置一个属性一样简单。
handleClick: function (event) {...},
render: function ) {
return <div onClick={this.handleClick}>...</div>
}
⚠️:react自动绑定了组件所有方法的作用域,因此你永远都不需要手动绑定。
1.2.4 注释
jsx的本质就是javascript,所以可以在标签内添加原生的js注释。
注释可以用以下2种形式添加:
- 1.当做一个元素的子节点
- 2.内联在元素的属性中
1.作为子节点:
<!-- 子节点形式的注释只需要简单地包裹在花括号内即可,并且可以跨多行。-->
<div>
{
/* 这是注释内容 */
}
<input type="text" name="" value="" placeholder="">
</div>
2.作为内联属性
// 内联的注释可以有两种形式。首先,可以使用多行注释:
<div>
<input
/*
这是多行注释内容!
*/
type="text" placeholder="address" />
</div>
// 其次也可以使用单行注释
<div>
<input
type="text" // 这是单行注释
placeholder="address" />
</div>
1.2.5 样式(简单的驼峰属性命名即可)
var styles = {
borderColor: "#888",
borderThinkness: "1px"
};
React.renderComponent(<div style={styles}>...</div>, node);
1.2.6 特殊属性
- htmlFor (for)
- 由于jsx会转换为js,所以有些关键词我们不能用,比如这个。
<label htmlFor="for-text" ...>
- className (class)
<div className={classes} ...>
1.2.7 没有jsx的react
所有的jsx标签最后都会被转换为原生的javascript。因此jsx对于react来说并不是必需的。然而,jsx确实减少了一部分复杂性。如果你不打算在react中使用jsx,那么在react中创建元素时需要知道以下三点:
- 1.定义组件类
- 2.创建一个为组件类产生实例的工厂
- 3.使用工厂来创建ReactElement实例
创建React元素
page 20,21
significant!
1.3 组件的生命周期
第二章提到过,一个组件就是一个状态机,对于特定的输入,它总会返回一致的输出。
React为每个组件提供了生命周期钩子函数去响应不同的时刻:
- 1.实例化(创建时)
- 2.活动期(存在期)
- 3.销毁时(被销毁)
1.3.1 生命周期方法
react组件以简洁的生命周期api来单单提供你所需要的方法(而不是所有方法)。
接下来为我们以调用顺序来看看每个方法!!!
1.3.2 实例化(区别于初次创建后的创建调用)
一个实例初次被创建所调用的生命周期方法和其他各个后续实例被创建时所调用的方法略有不同。
所以:当你首次使用一个组件类时,有如下调用顺序:
- getDefaultProps
- getInitialState
- componentWillMount
- render
- componentDidMount
而该组件类的所有后续应用,将会如下:
- getDefaultProps
- componentWillMount
- render
- componentDidMount
⚠️区别在于后续的不必执行:getInitialState函数,其余函数如常。(有待进一步理解)
1.3.3 存在期
随着应用状态的改变,组件逐渐受到影响,则调用如下:
- componentWillReceiveProps
- shouldComponentUpdate
- componentWillUpdate
- render
- componentDidUpdate
1.3.3 销毁&清理期
最后,组件被使用完后,componentWillUnmount方法将会被调用,目的是给这个实例提供清理自身的机会。
接下来,应该具体的理解 p24~30的内容(各个时期的各个函数的具体运作)。这里不过多阐述以增加篇幅,只理清思路即可。
我认为这段内容,应该是react的第一块关键内容,乃设计之精心之处,应多多揣摩,烂熟于胸。
1.3.4 总结
组件不会独立存在,随着父组件将props推送给它们的子组件,以及子组件渲染它们自身的子组件时,你必需谨慎地考虑数据是如何流经整个应用的,后面了解数据流。
1.4 数据流
1.由于react的数据流向是单向的(其父节点传递到子节点),
2.因此组件是简单且易于把握的(它们只需要从父节点获取props渲染即可)
3.假如顶层组件的某个prop改变了,
react会递归地向下遍历整个组件树,
重新渲染所有使用这个属性的组件。
4.react组件内部还具有自己的状态,这些状态只能在组件内修改。
react组件本身很简单,你可以把它们看成是一个函数,它接受props和state作为参数,返回一个虚拟的dom表现。
接下来,我们就详细的学习一下:
- props是什么
- state是什么
- 什么时候用props以及什么时候用state
1.4.1 Props = properties
1.用途:可以把任意类型的数据传递给组件
- 2种方式设置props
- 挂载组件时:
<ListSurveys surveys={surveys}/>
- 调用组件实例的setProps方法:
listSurveys.setProps({ surveys: survey });
- ⚠️使用条件是:在子组件上或组件树外
- ps:勿调用this.setProps或者修改this.props(一个组件绝对不可以修改自己的props)
- 有需要请使用state!!!
- 挂载组件时:
2.???(在哪里) props还可以用来添加事件处理程序:
var SaveButton = React.createClass({
render: function() {
return (
<a className='button save' onClike={this.handleClick}>Save</a>
),
handleClick: function() {
// ...
}
}
});
谁是props?
1.4.2 PropTypes
1.用途:通过定义一个配置对象,来验证props的方式
2.此函数是一种极好的描述组件API方式(.isRequired)
1.4.3 getDefaultProps
1.用途:设置属性的默认值(针对那些非必需属性)
2.⚠️此函数react.createClass调用时被调用,而不是组件实例化时
返回值被保存起来(所以不能在此函数中使用任何特定的实力数据)
1.4.4 State
1.每个react组件都会有自己的state,state与props的区别在于:state只存在于组件的内部
2.state可以用来确定一个元素的视图状态。
3.查看使用state来确定元素的视图状态实例(github)
1.4.5 总结
-
放在state和props的各是哪些部分?
- state中应存那些简单的组件正常工作时的必须要的数据。(布尔值,输入框值等)
- 不要尝试把props复制到state中,要尽可能把props当作数据源
-
本章的主要知识:
- 使用了props在整个组件树中传递数据和配置
- 避免在组件内部修改this.props或调用this.setProps,请把props当作是只读的
- 使用props来做事件处理器(下一章会细节化),与子组件通信
- 使用state存储简单的视图状态,比如下拉框是否可见这样的状态
- 使用this.setState来设置状态,而不要使用this.state直接修改状态
1.5 事件处理
展示页面+js响应事件=用户界面整体设计
1.5.1 绑定事件处理器
react处理的事件本质和原生js一样(包括命名)
react的事件处理器简化为了一种:
jsx版
<button className="btn btn-save" onClick={this.handleSave}>Save</button>
js版
React.DOM.button({className: "btn btn-save", onClick: this.handleSaveClicked}, "Save");
⚠️虽然这份代码在写法上类似于普遍不推荐的:
⚠️react对各类事件类型提供良好的支持,具体支持列在这里
- html内联事件处理程序(最不妥的事件处理程序写法),但其实在底层实现上并没有使用html的onClick属性。
- react只是用这种写法来绑定事件处理器。
- 其内部则按照需要高效地维护着事件处理器。
1.5.2 事件和状态
解决组件随着用户输入而改变的问题,经过特定组件渲染后,绑定的事件处理器方法负责处理行为。
1.5.3 根据状态进行渲染
1.5.4 更新状态
1.5.5 事件对象
1.5.6 总结
1.6 组件的复合
1.7 mixin
mixin是react提供的另外一种在多个react组件中共享功能的方式
mixin将组件拆为更小,更易维护的部分的方式。