前段时间学习了有关React框架,做了一份笔记,记录并分享一下。以便后续方便查找和使用。
PS:这份笔记只是记录了本人在学习过程中,认为React中比较重要的点进行了记录,详细的知识点还需要深入去探讨研究
***欢迎指出错误或不当的地方***
创建React组件的三种方法
①React.createClass,方法传入的参数是一个对象
②ES6 Class,常用的创建方式React.createClass({ getDefaultProps(){ //初始化props return {}; }, getInitialState(){ //初始化state return {}; }, render(){ return (
Hello World!) } })
class XXX extends React.Component{
static propType = {};//props的类型检查
static defaultProps = {};//默认的props
constructor(props){
//构造函数,state初始在这里设置
super(props);
this.state = {};
}
//生命周期方法
//...
//render
render(){
//render里不能调用this.setState
//有逻辑判断的例外
return (
Hello World!
)
}
}
③无状态函数,可以传入props和context,无state,无生命周期,但propTypes和defaultProps可以通过静态方法设置
function XXX(props){
return (
Hello World
)
}
XXX.propTypes = {};
XXX.defaultProps = {};
构建时:getDefaultProps(第一次构建该组件时)、getInitialState、componentWillMount、render、componentDidMount
更新时(props和state修改时):componentWillReceiveProps(props改变时才有这个)、shouldComponentUpdate、componentWillUpdate、render、componentDidUpdate
卸载时:componentWillUnmount
注意:生命周期方法中,只有componentWillMount、componentDidMount、componentDidUpdate、componentWillReceiveProps才能调用this.setState,其余的会造成调用循环,导致浏览器崩溃
从React v15.5开始,React.PropTypes助手函数已经被弃用,建议使用prop-types库来定义类型
import PropTypes from 'prop-types';
//PropTypes
//类型包括array/bool/func/number/object/string/symbol
//以及node/element/instanceOf()/one of(['',''])/oneOfType([])/arrayOf()/objectOf()/shape()
具体可以去prop-types库或者propTypes类型检查
state
props:有一个内置的prop——children
ReactDOM功能是将组件渲染到真实DOM上。API有findDOMNode、unmountCpmponentAtNode、render。
还有个unstable_renderSubtreeIntoContainer方法可以了解一下
组件被调用时,会新建一个该组件的实例,refs就会指向这个实例。
如果放在原生DOM中,就会返回DOM节点;如果放在React组件中,就返回该组件的实例
支持回调函数以及字符串两个格式。
①回调函数
//挂载到实例的myInput属性上
ref={(ref) => this.myInput = ref}/>
②字符串
//声明
ref='myInput' />
//调用,并获取对应的DOM
const myInput = this.refs.myInput;
const inputDOM = ReactDOM.findDOMNode(myInput);
事件委派:并不会把所有事件绑定到真实节点,而是绑定到结构的最外层,再用一个事件监听器,维持一个映射来保存所有组件的事件监听和处理函数。
在使用ES6 Class或者纯函数创建组件时,需要手动绑定this。
①bind
handleClick(e,arg){
//...
}
render(){
return
}
②构造器内声明
constructor(props){
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick(e){
//...可以调用this.setState
}
③箭头函数
handleClick(){
//...
};
render(){
return
}
注意:React合成事件最好不要与原生事件混用。阻止React事件冒泡的行为只能用于合成事件系统,无法阻止原生事件冒泡;相反,原生事件的阻止冒泡行为,可以阻止React合成事件的传播。
React事件与原生事件比较
①事件传播和阻止事件传播
React仅支持事件冒泡(IE9以下不支持事件捕获)
阻止原生事件传播:e.stopPropagation();或者e.cancelBubble= true;(IE9以下)
React阻止事件传播:e.stopPropagation();
②事件类型
React合成事件的类型是原生事件的一个子集
③绑定方式
原生的JS绑定有三种:
//绑定在DOM对象上
ele.click = function(){}
//addEventListener或者attachEvent
ele.addEventListener('click',function(){},false);
ele.attachEvent('click',function(){})
//绑定在DOM节点上
React绑定事件:
④事件对象
原生事件在低版本需要用window.event来获取事件对象,React则直接得到一个合成事件对象
可以用classname库或者CSS Modules
父→子:通过props传递子组件需要的信息。
子→父:通过回调函数;自定义事件机制。
跨级组件(有嵌套关系的跨级):推荐使用高阶组件来实现。(也可以用context来实现,不推荐,因为层次复杂时,无法知道centext从哪里传来)
没有嵌套关系的组件:借用NodeJS的Events模块
import { EventEmitter } from 'events';
注意,在组件完成挂载后在订阅事件,卸载时取消事件订阅;
概念:接受一个组件作为输入,输出一个新的组件。
好处:使代码复用性、逻辑性、抽象特性提高,可以劫持render方法,也可以控制props和state
实现方式:
①属性代理
const MyContainer = (WrappedComponent) =>
class extends Component {
render(){
const newProps = {
text : 'higher-order component'
}
return < WrappedComponent {…this.props} {…newProps}/>
}
}
生命周期方法:挂载(componentDidMount)从内到外执行,卸载(componentWillUnmount)从外到内执行
特性:①控制props②通过refs使用引用③抽象state(关于容器组件和UI组件)④使用其他元素包裹WrappedComponent:既可以加样式、也可以实现布局
②反向继承
const MyContainer = (WrappedComponent) =>
class extends WrappedComponent {
render(){
return super.render();
}
}
特点:①渲染劫持②控制state
①纯函数。特点:相同输入总是返回相同输出;没有副作用;无额外状态依赖
②PureRender。
③Immutable Data
是一旦创建就不能再修改的数据。(结构共享:若树一个节点变化,只修改这个节点和受影响的父节点,其他节点共享)
优点:
1) 降低可变带来的复杂度,数据难被回溯
2) 节省内存
3) 撤销/重做,复制/黏贴甚至时间旅行做起来很简单
4) 并发安全
5) 符合函数式编程
④key prop:标记动态子组件,在Virtual DOM作diff时有优化效果
⑤react-addons-perf
setState通过队列机制实现state更新。调用后,不会立即更新state,而是合并state后放入状态队列,队列机制进行批量更新。注意循环调用风险;更多细节可以去了解一下源码。
Virtual DOM的节点称为ReactNode,有三种类型ReactElement、ReactFragment和ReactText
ReactElement又分为ReactComponentElement和ReactDOMElement
diff算法
三个优化策略:
① web UI中DOM节点跨级移动操作少,忽略不计
Virtual DOM只会对同级的DOM节点进行比较,即同个父节点下的所有子节点。
② 拥有相同类的两个逐渐会生成相似的树形结构,不同类生成不同的树形结构
③ 对于同一层级的一组子组件,他们可以通过唯一id进行区分(就是动态子组件的key)
component diff
比较策略:
① 同一类型,按照原策略继续比较Virtual DOM;
② 如果不是同一类型,替换整个组件下所有的子节点;
③ 通过shouldComponentUpdate来判断是否需要进行diff
element diff
同一层级时,提供插入、移动、删除3个操作
(具体的操作策略待补充)
将tree diff比较计算出来的结果,更新到界面上的一个操作。