zoukankan      html  css  js  c++  java
  • 对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. 并发⽅⾯新的基础能⼒
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
     
  • 相关阅读:
    栈的应用之银行叫号系统模拟
    栈的应用之括号匹配
    栈的应用之数制转换
    线性结构 一元多项式的乘法与加法运算
    Checkpoints codeforces 709B
    寒冰王座 hdu 1248(背包)
    单链表头插法、尾插法(26个字母为例)
    两个有序单链表的合并
    Number Sequence HDU 1711(KMP)
    完成运算
  • 原文地址:https://www.cnblogs.com/zhouyideboke/p/13371653.html
Copyright © 2011-2022 走看看