setState()调用原理

setState()调用原理

React setState调用的原理

www.zeeklog.com  - setState()调用原理

setState具体的执行过程如下:

  1. 首先调用setState()函数:
ReactComponent.prototype.setState = function(partialState, callback){
  // updater:一个带有形参的函数,返回被更新的状态对象。它可以接收到props和state
  this.updater.enqueueSetState(this, partialState)
  if(callback){
    this.updater.enqueueCallback(this, callback, 'setState')
  }
}

enqueueSetState将新的state放进组件的状态队列里,并调用enqueueUpdate来处理将要更新的实例对象。

enqueueSetState: function (publicInstance, partialState) {
  // 根据 this 拿到对应的组件实例
  var internalInstance = getInternalInstanceReadyForUpdate(publicInstance, 'setState');
  // 这个 queue 对应的就是一个组件实例的 state 数组
  var queue = internalInstance._pendingStateQueue || (internalInstance._pendingStateQueue = []);
  queue.push(partialState);
  //  enqueueUpdate 用来处理当前的组件实例
  enqueueUpdate(internalInstance);
}

setState()最终通过enqueueUpdate更新state。

function enqueueUpdate(component) {
  ensureInjected();
  // 注意这一句是问题的关键,isBatchingUpdates标识着当前是否处于批量创建/更新组件的阶段
  if (!batchingStrategy.isBatchingUpdates) {
    // 若当前没有处于批量创建/更新组件的阶段,则立即更新组件
    batchingStrategy.batchedUpdates(enqueueUpdate, component);
    return;
  }
  // 否则,先把组件塞入 dirtyComponents 队列里,让它“再等等”
  dirtyComponents.push(component);
  if (component._updateBatchNumber == null) {
    component._updateBatchNumber = updateBatchNumber + 1;
  }
}

在enqueueUpdate中通过batchingStrategy的isBatchingUpdates属性来判断当前是否处于批量创建/更新组件的阶段。

batchingStrategy对象可以理解为“锁管理器”。这里的“锁”是指isBatchingUpdates变量。isBatchingUpdates初始值为false,表示并未进行任何批量更新操作。每当React调用batchedUpdate去执行更新动作时,会先把这个锁给锁上(置isBatchingUpdates为true),表明“现在正处于批量更新过程中”。当上锁后,更新需要更新的组件都要在队列中等待下一次批量更新。

setState()将对组件state的更新排入队列,并通知React需要使用更新后的 state重新渲染此组件及其子组件。你需要将setState()视为请求而不是立即更新state(可能为异步的!!!)。因为React会将多次的setState()放在一起一并执行,这样可以提升效率,减少页面渲染次数。

因为setState()并不总是立即更新state,可能会推迟更新。这导致在调用setState()后立即读取this.state有可能会拿到未更新之前的state。为了解决这个问题,我们可以使用componentDidUpdate或setState(updater, callback)的回调函数,保证在state更新后再执行。

总结:setState()用于更新状态,它接受两个参数,第一个参数可以传入一个对象,也可以传入一个updater函数传入的对象代表需要更新的状态及状态值。updater为一个带有形参的函数,返回被更新的状态对象,可以接收到state和props;第二个参数是一个可选的回调函数,在状态更新完后进行回调。setState()并不会立即执行状态的更新,而更像是更新状态请求。

  1. 在调用setState()后React会调用enqueueSetState()方法将需要更新的state入队。
  2. 接着调用enqueueUpdate方法里面的batchingStrategy.isBatchingUpdates属性判断当前是否处理批量更新的阶段。若处于,则将需要更新state的组件放入dirtyComponent队列中等待下一次批量更新;若不处于则立即更新组件。

Read more

深入理解 Proxy 和 Object.defineProperty

在JavaScript中,对象是一种核心的数据结构,而对对象的操作也是开发中经常遇到的任务。在这个过程中,我们经常会使用到两个重要的特性:Proxy和Object.defineProperty。这两者都允许我们在对象上进行拦截和自定义操作,但它们在实现方式、应用场景和灵活性等方面存在一些显著的区别。本文将深入比较Proxy和Object.defineProperty,包括它们的基本概念、使用示例以及适用场景,以帮助读者更好地理解和运用这两个特性。 1. Object.defineProperty 1.1 基本概念 Object.defineProperty 是 ECMAScript 5 引入的一个方法,用于直接在对象上定义新属性或修改已有属性。它的基本语法如下: javascript 代码解读复制代码Object.defineProperty(obj, prop, descriptor); 其中,obj是目标对象,prop是要定义或修改的属性名,descriptor是一个描述符对象,用于定义属性的特性。 1.2 使用示例 javascript 代码解读复制代码//

By Ne0inhk

Proxy 和 Object.defineProperty 的区别

Proxy 和 Object.defineProperty 是 JavaScript 中两个不同的特性,它们的作用也不完全相同。 Object.defineProperty 允许你在一个对象上定义一个新属性或者修改一个已有属性。通过这个方法你可以精确地定义属性的特征,比如它是否可写、可枚举、可配置等。该方法的使用场景通常是需要在一个对象上创建一个属性,然后控制这个属性的行为。 Proxy 也可以用来代理一个对象,但是相比于 Object.defineProperty,它提供了更加强大的功能。使用 Proxy 可以截获并重定义对象的基本操作,比如访问属性、赋值、函数调用等等。在这些操作被执行之前,可以通过拦截器函数对这些操作进行拦截和修改。因此,通过 Proxy,你可以完全重写一个对象的默认行为。该方法的使用场景通常是需要对一个对象的行为进行定制化,或者需要在对象上添加额外的功能。 对比 以下是 Proxy 和 Object.defineProperty 的一些区别对比: 方面ProxyObject.defineProperty语法使用 new Proxy(target,

By Ne0inhk