此篇文章,仅仅是个人的随笔知识点,欢迎指导
1. react
1.1. 无状态函数:只传入props和context两个参数,它不存在state
1.2. react数据是自定向下单向流动的,通过props,当调用setstate方法时最大的表现行为就是该组件会尝试重新渲染。props本身时不可变的,子组件的props一定来自于默认属性或者通过父组件传递而来
1.3. react.children
实现动态子组件可以使用 react.children.map(this.props.children,(child)=> {return react.cloneElement(child,{xxxxxx})})用声明式编程的方式来渲染数据
1.4. react的合成事件仅仅支持事件冒泡机制,并没有实行事件捕获
阻止事件传播在react中可以使用e.preventDefault(),在react中也时支持使用js原生事件的,但是最好不要原生和合成事件混合使用
1.5. 受控组件:每当表单状态发生变化时,都会被写入到组件的state中。表单的数据来源于组件的state,并且通过props传入,这也是单向数据诙谐到组件的state中完成的双向绑定
1.6. 非受控组件:它的值不受props或者state控制,通过为其添加的ref来访问渲染后的底层dom元素
1.7. 跨组件通信
1.7.1. 通过context:可以减少逐层传递,React App的组件是树状结构,一层一层延伸,父子组件是一对多的线性依赖。随意的使用Context其实会破坏这种依赖关系,导致组件之间一些不必要的额外依赖,降低组件的复用性,进而可能会影响到App的可维护性。
1.7.2. 父子组件:props
1.7.3. 没有嵌套关系的组件通信:eventEmitter
1.8. 高阶组件
实现方法:1.属性代理 2. 反向继承
1.9. pureRender
组件中最澄减的性能优化方法
pureComponent和component区别
1.9.1. pureComponent :主要用来提升性能通过props和state的浅对比来实现shouldComponentUpdate
1.9.2. component: 不会比较当前和下一个状态的props和state,所以每当shouldComponentUpdate被调用的时候默认会全部渲染
2. react源码
2.1. virtualDom
在virtuDom中节点被称为reactNode分为三部分reactElement,reactFragment,reactText,其中reactElement可以被分为reactComponentElement和reactDomElement
在react>15.0版本中去掉了data-reactid属性(data-reactid:作为DOM节点的唯一标识而存在的字符串)
当react在创建组件的时候,会首先调用instantiateReactComponent这是初始化组件的入口函数,它通过node类型来区分不同组件的入口。
2.2. 自定义组件
mountComponent本质上是递归渲染内容的所以compontentDidMount中父组件在子组件之后执行,而在componentWillMount中父组件在子组件之前执行
unmountComponent负责管理生命周期的ComponentWillUnmount,会重置所有相关参数,如果此时调用setstate不会触发render,因为所有更新队列和更新状态都会被重置为null/false
2.3. 注意:禁止在shouldComponentUpdate和ComponentWillUpdate中调用setstate,这样会造成循环调用,直至耗光浏览器内存崩溃
只有在render和ComponentDidUpdate中才能获取到最新的state
react利用状态队列机制实现setstate的异步更新,避免重复更新state
setstate通过一个队列机制实现state更新,当执行setstate时,会将需要更新的state合并放入状态队列,而不是立刻渲染
setstate调用栈 ---> this.setstate(newVal) ----> newVal 存入pending队列 --->调用enqueueUpdate ---> 是否处于批量更新模式 ---> (1.Y:将组件保存在dirtyCompontents. 2.N:遍历dirtyComponents调用UpdateComponent更新pending state/props)
2.4. 无状态组件
没有state,没有生命周期,只是简单的接受props渲染成DOM结构
2.5. 事务机制(Transaction)
用wraaper把方法包裹起来,然后每个wrapper中都提供一个initalize和close方法,当需要使用事务调用 一个方法,会使用事务机制提供的perform方法,将需要执行的方法传入,就会按顺序执行wrapper.initalize和wrapper.close。事务还支持多个事务的嵌套,当执行方法被多个wrapper包裹时, 事务会先按顺序执行所有的initalize --> anymethod --> 所有的closed
核心原理:定义一个原型,里面有一个存放wrapper的抽象接口,会由继承于这个原型的子类覆盖。由子类定义其真正要执行的方法前后执行的所有东西
参考https://blog.csdn.net/handsomexiaominge/article/details/86183735
2.6. diff算法
react分别对tree diff, component diff ,element diff 进行了优化
2.6.1. tree diff
对tree进行分层比较,两棵树只会对同一层的节点进行比较,如果出现DOM节点跨层级的移动操作,只会进行创建和删除操作
2.6.2. component diff
如果是同一类型的组件,按照按照原策略方法继续比较virtualDom tree
如果不是,则将该组件判断为 dirtycomponent从而替换整个组件下的所有节点
对于同一类型的组件,有可能其virtualDom没有任何变化,可以通过shouldComponentUpdate来控制其是否重新渲染
2.6.3. element diff
当节点处于同一层级时,diff提供了三种节点操作分别是insert_markup(插入), move_existing(移动),remove_node(删除)
对同一层级的同组子节点,添加唯一的key进行,可以大大优化节点之间的操作,通过判断(child_mountIndex < lastIndex)则进行节点移动操作,否则不执行该操作,只有当访问的节点比lastIndex小时,才需要进行移动操作
参考[https://segmentfault.com/a/1190000010686582]
2.7. react path
将tree diff 计算出来的DOM差异队列更新到真实的DOM节点上
实现:主要通过遍历差异队列。在遍历差异队列时通过更新类型进行相对应的操作,包括新节点的插入已有节点的移动和删除
网友评论