react源码-setState思路设计解析

13 篇文章 0 订阅
6 篇文章 0 订阅

目录

setState总体思路:

1. 调用setState时候并没有立即执行,而是触发Updater更新,将callback函数和nextState进行先添加操作 

2.更新操作的大致思路


setState总体思路:

  1. setState执行时,会讲partialSate添加到队列pendingState中
  2. updateComponent负责遍历pendingState整合新的state
  3. forceUpdate将一周期更新控制关闭, 进行此周期新旧vnode的diff对比及实际更新操作

1. 调用setState时候并没有立即执行,而是触发Updater更新,将callback函数和nextState进行先添加操作 

setState函数逻辑

setState(newState) {
    // 每次执行事件都会自动添加canMerge,用来合并state数据,然后等函数调用执行完,将canMerge=false,进行统一更新
	if (this.canMerge) {
		this.updateQueue.push(newState)
		return 
	}
	
	// 下面是真正的更新: dom-diff, lifeCycle...
	...
}

例如:

g() {
   this.setState({
		age: 18
	})
	this.setState({
		color: 'black‘
	})
}

f() {
	this.setState({
		name: 'yank'
	})
	this.g()
}

 会被react整理标记成


g() {
   this.setState({
		age: 18
	})
	this.setState({
		color: 'black‘
	})
}

f() {
    this.canMerge = true
    
	this.setState({
		name: 'yank'
	})
	this.g()
	
	this.canMerge = false
	// 通过this.updateQueue合并出finalState
	const finalState = ...  
	// 此时canMerge 已经为false 故而走入实际更新逻辑
	this.setState(finaleState) 
}


2.更新操作的大致思路

class Updater {
    constructor(instance) {
        this.pendingCallback = []; // callback数组
        this.pendStates = []; // 待处理数组, state
        this.isPending = false; // 更新频率控制,是否进行更新操作
    }
     // 添加回调队列
    addCallback(callback) {
        // 如果是函数,就将函数推到回调函数队列中,等待执行
        if (_.isFn(callback)) {
            this.pendingCallback.push(callback);
        }
    }
    // 添加要更新的state队列
    addState(nextState) {
        if (nexState) {
            this.pendStates.push(nexState);
            // 进行此次更新
            if (!this.isPending) {
                this.emitUpdate();
            }
        }
    }
    // 更新
    emitUpdate(nextProps, nextContext) {
        // 调用getState函数
        this.getState();
        this.shouldUpdate();
    }
    // 获取更新之后的state
    getState() {
        let { instance, pendStates} = this;
        let { state, props } = instance;
        // 循环这次待更新的数据队列
        this.pendStates.forEach(item => {
            // 判断item是不是数组
            let replace = _.isArr(nextState);
            // 1.1如果是数组就对原数据进行替换
            if (replace) {state = {...nextState};}
            // 1.2如果是普通数据就对原数据进行解构更新操作
            else {state = { ...state, ...nextState};}
        })
        return state;
    }
    shouldUpdate(component,nextProps,nextState,nextContext,callback) {
        // 默认值是true
        let shouldComponentUpdate = true;
        if(component.shouldComponentUpdate) {
            shouldComponentUpdate = component.shouldComponentUpdate(nextProps,nextState,nextContext);
        }
        // 判断shouldComponentUpdate,看看是否需要更新页面
        // 不更新页面,赋值之后直接return
        if(shouldComponentUpdate===false) {
            component.props = nextProps;
            component.state = nextState;
            component.Context = nextContext || {};
            return;
        }
        // 更新页面
        let cache = component.$cache;
        cache.props = nextProps;
        cache.state = nextState;
        cache.Context = nextContext || {};
        component.forceUpdate(callback);
    }
    forceUpdate(callback) {
        // 对之前页面dom的node和vnode进行赋值;
        // 设置this.isPending = true;周期关闭
        // 调用componentWillUpdate
        // 对新的数据调用renderComponent方法生成新的vnode
        // 调用compareTwoVnode进行新旧vnode的diff对比
    }
   
}

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值