React初学及内部原理

React常见的问题

一、React的渲染机制-------Reconciliation过程(协调)

React采用的虚拟DOM(即VDOM),每次属性(props)和状态(state)发生变化的时候,render函数返回不同的元素树,React会检测当前返回的元素树和上次渲染的元素树之间的差异,然后针对差异的地方进行更新操作,最后渲染为真实的DOM,这就是整个Reconciliation过程,其核心就是进行新旧DOM树对比的diff算法。

二、如何对渲染进行优化

为了获取更好的性能,利用shouldComponentUpdate这个生命周期函数,减少diff的过程,默认的shouldComponentUpdate会在props或state发生改变时返回true,表示组件会重新渲染,从而调用render函数,进行新旧DOM树的diff对比。但是我们可以在这个生命周期函数里做一些判断,然后返回一个布尔值,并且返回true表示即将更新当前组件,false则不更新当前组件。我们可以通过shouldComponentUpdate控制是否发生VDOM树的diff过程。

三、diff 算法的实现细节

img

设计思路

设计的思想,其实就是从一棵树参照另一棵树进行更新,但是如果利用循环递归的方式对每一个节点进行比较,那么节点一多,对CPU性能的要求就很高,所以它进行了“偷工减料”,并没有老老实实的对比每一个节点。

diff算法进行比较有一套自己的方法论

1.永远只比较同层节点,不会垮层级比较节点。

2.不同的两个节点产生不同的树。这也就是上面总结的类型不相同的情况,把原来的节点以及他的后代全部干掉,替换成新的。

3.通过key的值指定哪些元素是相同的。

执行规则(diff的流程)

  • 1、元素类型相同时

    • 都是DOM节点
    <div className="old" title="老节点" />
    <div className="new" title="新节点" />
    

    通过比对这两个元素,React知道需要修改DOM元素上的className属性和title属性,处理完该节点之后,React继续对子节点进行递归。

    • 都是组件元素

    组件实例保持不变,更新props。值得注意的是,这时候调用组件实例的componentWillReceiveProps () 方法。然后通过 shouldComponentUpdate 返回值决定是否调用 render 方法。处理完该节点以后,依然继续对子节点进行递归。

  • 2、元素类型不相同时

在进行diff操作时如果节点的类型不相同,React的的做法非常简单粗暴,直接将原VDOM树上该节点以及该节点下所有的后代节点,全部删除,然后替换为新 VDOM 树上同一位置的节点,当然这个节点的后代节点也全都跟着过来了。剩余步骤同上。

特殊情况讨论:遍历子元素列表

  • 引入key值

首先,我们往列表末尾插入一个元素:

<ul>
	<li>1</li>
	<li>2</li>
</ul>

插入后为:

<ul>
	<li>1</li>
	<li>2</li>
	<li>3</li>
</ul>

React会先匹配两个对应的树,最后插入第三个元素,没有任何问题,如果在头部插入,如下:

<ul>
	<li>3</li>
	<li>1</li>
	<li>2</li>
</ul>

这样的话元素需要更新3个,这样的效率非常的低,于是React引入了key值得概念

<ul>
	<li key="first">1</li>
	<li key="second">2</li>
</ul>

这时再在头部插入新元素后变为:

<ul>
	<li key="third">3</li>
	<li key="first">1</li>
	<li key="second">2</li>
</ul>

现在React通过Key得知1,2原来是存在的,现在只是换了位置,因次不需要更新这个节点,只需要移动位置即可,大大提升效率。

补充问题:key值的选取原理

不需要全局唯一,但是必须列表中保持唯一。

最好不用数组元素的下标作为key值,数组下标值不稳定,修改顺序会修改当前 key,diff效率就有可能骤然下降。

四、React JSX原理

用 JavaScript 对象来表现一个 DOM 元素的结构JavaScript 写起来太长了,结构看起来又不清晰,用 HTML 的方式写起来就方便很多了。

于是 React.js 就把 JavaScript 的语法扩展了一下,让 JavaScript 语言能够支持这种直接
在 JavaScript 代码里面编写类似 HTML 标签结构的语法,
这样写起来就方便很多了。编译的过程会把类似 HTML 的 JSX 结构转换成 JavaScript 的对象结构。
React.createElement 会构建一个 JavaScript 对象来描述你 HTML 结构的信息,包括标签名、属性、还有子元素等,
jsx实际上就是一种javascript对象,他经过react语法的构造,还有编译转化,最后得到dom元素,可以插到页面中:
所谓的 JSX 其实就是 JavaScript 对象,所以使用 React 和 JSX 的时候一定要经过编译的过程:
JSX —使用react构造组件,bable进行编译—> JavaScript对象 — ReactDOM.render()—>DOM元素 —>插入页面

五、react中Context 的使用

Context是通过组件树提供了一个传递数据的方法,从而避免了在每一个层级手动的传递 props 属性。
React.createContext(defaultValue):创建一个上下文的容器(组件), defaultValue 可以设置共享的默认数据,这个容器会提供 Provider 和 Consumer
Provider:在需要传递数据的地方用其包裹,属性 value 中提供什么,它就能向后代树传递什么。如果没有 Provider ,后代树只能获取到defaultValue
Consumer:在需要获取值的地方用 Consumer 包裹,就能通过this.context 取得值。
函数组件使用hook方法 useContext 获取context

  • 优点:减少代码层层传递的复杂度
  • 缺点:因为依赖祖先组件的传值,子组件的复用性降低了

六、React组件的生命周期

—、 初始化阶段:

Constructor初始化状态

componentWillMount:组件即将被装载、渲染到页面上

render:组件在这里生成虚拟的DOM节点

componentDidMount:组件真正在被装载之后

二、 运行中状态:

componentWillReceiveProps:组件将要接收到属性的时候调用

shouldComponentUpdate:组件接受到新属性或者新状态的时候(可以返回false,接收数据后不更新,阻止render调用,后面的函数不会被继续执行了)

componentWillUpdate:组件即将更新不能修改属性和状态

render:组件重新描绘

componentDidUpdate:组件已经更新

三、 销毁阶段:

componentWillUnmount:组件即将销毁

七、redux 的工作流程(流程图)

流程图
简明来说,首先创建一个store分别管理相应的reducer,在组件内部派发action之后,看是否需要中间件进行处理,如果是ajax等异步操作,可以放入thunk或者saga等中间件,进行处理之后然后传到reducer之中,如果组件里面需要数据,可以通过connect高阶组件或者getState()获取reducer里面的数据。

八:redux-thunk、redux-saga 使用

redux是相当于一个仓库,配合react使用时能够成为一种状态管理工具,但是redux本身的特性规定其在派发信息时只能派发同步并且是扁平化的内容,这样在redux中若想实现异步操作就会有很大的局限性,中间件等同于一个仓库管理员的身份,每次想去仓库中取货,必须经过管理员去取钥匙,redux-thunk,redux-saga是两个常用的中间件,通过中间件能够增强redux本身的功能,redux-thunk中能够处理函数,其内部机制就是识别派发的参数类型,若是函数则直接调用,若是对象直接进行派发的操作,redux-saga则在内部封装了一些方法能够拦截派发的请求,到内部执行异步操作后,再去处理数据。

redux-thunk直接函数,较为直接,但是由于派发内容可以是扁平的对象,也可以是函数,所以不易于维护。

redux-saga仍旧派发扁平对象,符合redux派发规则,但是实现的逻辑较为复杂,其实就是在内部封装了处理异步的行为。

持续更新。。。。。。。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值