对react的研究20200724
Posted zhouyideboke
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了对react的研究20200724相关的知识,希望对你有一定的参考价值。
setState
class组件的特点,就是拥有特殊状态并且可以通过setState更新状态并重新渲染视图,是React中最重要的api。
1. setState为什么是异步
// 批量
this.setState({ counter: this.state.counter + 1 });
this.setState({ counter: this.state.counter + 2 });
console.log("counter", this.state);
//数组传递,覆盖原来的state
this.setState([{ counter: 100, msg: "omg" }], () => {
console.log("clickHandle", this.state);
});
//回调
this.setState({ counter: this.state.counter + 1 },()=>{});
this.setState(nextState => {
console.log("next", nextState);
});
// 异步
this.setState({ counter: this.state.counter + 1 });
console.log("counter", this.state);//0
// 不异步
setTimeout(()=>{
setState({foo: ‘bar‘})
},1000)
// 原?事件
dom.addEventListener(‘click‘,()=>{
setState({foo: ‘bar‘})
})
setState并没有直接操作去渲染,?是执?了?个异步的updater队列 我们
使??个类来专?管理,./kkreact/Component.js
export let updateQueue = {
updaters: [],
isPending: false,
add(updater) {
_.addItem(this.updaters, updater)
},
batchUpdate() {
if (this.isPending) {
return
}
this.isPending = true
/*
each updater.update may add new updater to updateQueue
clear them with a loop
event bubbles from bottom-level to top-level
reverse the updater order can merge some props and
state and reduce the refresh times
see Updater.update method below to know why
*/
let { updaters } = this
let updater
while (updater = updaters.pop()) {
updater.updateComponent()
}
this.isPending = false
}
}
function Updater(instance) {
this.instance = instance
this.pendingStates = []
this.pendingCallbacks = []
this.isPending = false
this.nextProps = this.nextContext = null
this.clearCallbacks = this.clearCallbacks.bind(this)
}
Updater.prototype = {
emitUpdate(nextProps, nextContext) {
this.nextProps = nextProps
this.nextContext = nextContext
// receive nextProps!! should update immediately
nextProps || !updateQueue.isPending
? this.updateComponent()
: updateQueue.add(this)
},
updateComponent() {
let { instance, pendingStates, nextProps, nextContext }
= this
if (nextProps || pendingStates.length > 0) {
nextProps = nextProps || instance.props
nextContext = nextContext || instance.context
this.nextProps = this.nextContext = null
// merge the nextProps and nextState and update by
one time
shouldUpdate(instance, nextProps, this.getState(),
nextContext, this.clearCallbacks)
}
},
addState(nextState) {
if (nextState) {
_.addItem(this.pendingStates, nextState)
if (!this.isPending) {
this.emitUpdate()
}
}
},
replaceState(nextState) {
let { pendingStates } = this
pendingStates.pop()
// push special params to point out should replace
state
_.addItem(pendingStates, [nextState])
},
getState() {
let { instance, pendingStates } = this
let { state, props } = instance
if (pendingStates.length) {
state = _.extend({}, state)
pendingStates.forEach(nextState => {
let isReplace = _.isArr(nextState)
if (isReplace) {
nextState = nextState[0]
}
if (_.isFn(nextState)) {
nextState = nextState.call(instance, state,
props)
}
// replace state
if (isReplace) {
state = _.extend({}, nextState)
} else {
_.extend(state, nextState)
}
})
pendingStates.length = 0
}
return state
},
clearCallbacks() {
let { pendingCallbacks, instance } = this
if (pendingCallbacks.length > 0) {
this.pendingCallbacks = []
pendingCallbacks.forEach(callback =>
callback.call(instance))
}
},
addCallback(callback) {
if (_.isFn(callback)) {
_.addItem(this.pendingCallbacks, callback)
}
}
}
2. 为什么 setState只有在React合成事件和?命周期数中是异步的,在原
?事件和setTimeout、setInterval、addEventListener中都是同步
的?
原?事件绑定不会通过合成事件的?式处理,?然也不会进?更新事务的
处理流程。setTimeout也?样,在setTimeout回调执?时已经完成了原更
新组件流程,也不会再进?异步更新流程,其结果?然就是是同步的了。
setState总结:
1. setState()执?时,updater会将partialState添加到它维护的
pendingStates中,等到
2. updateComponent负责合并pendingStates中所有state变成?个state
3. forceUpdate执?新旧vdom?对-diffff以及实际更新操作
虚拟dom
常?问题:react virtual dom是什么?说?下diffff算法?
what?? javascript 对象表示 DOM 信息和结构,当状态变更的时候,重
新渲染这个 JavaScript 的对象结构。这个 JavaScript 对象称为virtual
dom;
why?DOM操作很慢,轻微的操作都可能导致??重新排版,?常耗性
能。相对于DOM对象,js对象处理起来更快,?且更简单。通过diffff算法对
?新旧vdom之间的差异,可以批量的、最?化的执?dom操作,从?提
?性能。
where?react中?JSX语法描述视图,通过babel-loader转译后它们变为
React.createElement(...)形式,该函数将?成vdom来描述真实dom。将来
如果状态变化,vdom将作出相应变化,再通过diffff算法对?新?vdom区
别从?做出最终dom操作。
how?
diff算法
算法复杂度O(n)
diffff 策略
1. 同级?较,Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略
不计。
2. 拥有不同类的两个组件将会?成不同的树形结构。
例如:div->p, CompA->CompB
3. 开发者可以通过 key prop
diff过程
?对两个虚拟dom时会有三种操作:删除、替换和更新
删除:newVnode不存在时
替换:vnode和newVnode类型不同或key不同时
更新:有相同类型和key但vnode和newVnode不同时
export function compareTwoVnodes(vnode, newVnode, node,
parentContext) {
let newNode = node
if (newVnode == null) {
// remove
destroyVnode(vnode, node)
node.parentNode.removeChild(node)
} else if (vnode.type !== newVnode.type || vnode.key
!== newVnode.key) {开课吧web全栈工程师
// replace
destroyVnode(vnode, node)
newNode = initVnode(newVnode, parentContext)
node.parentNode.replaceChild(newNode, node)
} else if (vnode !== newVnode || parentContext) {
// same type and same key -> update
newNode = updateVnode(vnode, newVnode, node,
parentContext)
}
return newNode
}
更新操作
根据组件类型执?不同更新操作
function updateVnode(vnode, newVnode, node, parentContext)
{
let { vtype } = vnode
//更新class类型组件
if (vtype === VCOMPONENT) {
return updateVcomponent(vnode, newVnode, node,
parentContext)
}
//更新函数类型组件
if (vtype === VSTATELESS) {
return updateVstateless(vnode, newVnode, node,
parentContext)
}
// ignore VCOMMENT and other vtypes
if (vtype !== VELEMENT) {
return node
}
// 更新元素开课吧web全栈工程师
let oldhtml = vnode.props[HTML_KEY] &&
vnode.props[HTML_KEY].__html
if (oldHtml != null) {
// 设置了innerHTML时先更新当前元素在初始化innerHTML
updateVelem(vnode, newVnode, node, parentContext)
initVchildren(newVnode, node, parentContext)
} else {
// 正常更新:先更新?元素,在更新当前元素
updateVChildren(vnode, newVnode, node,
parentContext)
updateVelem(vnode, newVnode, node, parentContext)
}
return node
}
patch过程
虚拟dom?对最终要转换为对应patch操作
属性更新
function updateVelem(velem, newVelem, node) {
let isCustomComponent = velem.type.indexOf(‘-‘) >= 0 ||
velem.props.is != null
_.patchProps(node, velem.props, newVelem.props,
isCustomComponent)
return node
}
?元素更新
function updateVChildren(vnode, newVnode, node,
parentContext) {
// 更新children,产出三个patch数组
let patches = {
removes: [],
updates: [],
creates: [],
}
diffVchildren(patches, vnode, newVnode, node,
parentContext)
_.flatEach(patches.removes, applyDestroy)
_.flatEach(patches.updates, applyUpdate)
_.flatEach(patches.creates, applyCreate)
}
import React, { useState, useEffect } from ‘react‘
function FunComp(props) {
const [data, setData] = useState(‘initialState‘)
function handleChange(e) {
setData(e.target.value)
}
useEffect(() => {
subscribeToSomething()
return () => {
unSubscribeToSomething()
}
})
return (
<input value={data} onChange={handleChange}
)
}
function FunctionalComponent () {
const [state1, setState1] = useState(1)
const [state2, setState2] = useState(2)
const [state3, setState3] = useState(3)
}
Fibter
1. 为什么需要fifiber
对于?型项?,组件树会很?,这个时候递归遍历的成本就会很?,会
造成主线程被持续占?,结果就是主线程上的布局、动画等周期性任务
就?法?即得到处理,造成视觉上的卡顿,影响?户体验。
2. 任务分解的意义
解决上?的问题
3. 增量渲染(把渲染任务拆分成块,匀到多帧)
4. 更新时能够暂停,终?,复?渲染任务
5. 给不同类型的更新赋予优先级
6. 并发??新的基础能?
以上是关于对react的研究20200724的主要内容,如果未能解决你的问题,请参考以下文章