SoFunction
Updated on 2025-04-11

Detailed introduction to page update after Vue data changes

First, the rendering function of the file will be passed by listening to the file changes:

(/*! ./?vue&type=template&id=472cff63&scoped=true& */ "./?vue&type=template&id=472cff63&scoped=true&", __WEBPACK_OUTDATED_DEPENDENCIES__ => { /* harmony import */ _App_vue_vue_type_template_id_472cff63_scoped_true___WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./?vue&type=template&id=472cff63&scoped=true& */ "./?vue&type=template&id=472cff63&scoped=true&");
(function () {
      ('472cff63', {
        render: _App_vue_vue_type_template_id_472cff63_scoped_true___WEBPACK_IMPORTED_MODULE_0__.render,
        staticRenderFns: _App_vue_vue_type_template_id_472cff63_scoped_true___WEBPACK_IMPORTED_MODULE_0__.staticRenderFns
      })
    })(__WEBPACK_OUTDATED_DEPENDENCIES__); })

Then execute the rerender method and only the key part of the code is posted:

  = 
     = 
    ().forEach(function (instance) {
      instance.$ = 
      instance.$ = 
      // reset static trees
      // pre 2.5, all static trees are cached together on the instance
      if (instance._staticTrees) {
        instance._staticTrees = []
      }
      // 2.5.0
      if (()) {
         = []
      }
      // 2.5.3
      if ((instance.$)) {
        instance.$ = []
      }
      // post 2.5.4: v-once trees are cached on instance._staticTrees.
      // Pure static trees are cached on the staticRenderFns array
      // (both already reset above)
      // 2.6: temporarily mark rendered scoped slots as unstable so that
      // child components can be forced to update
      var restore = patchScopedSlots(instance)
      instance.$forceUpdate()
      instance.$nextTick(restore)
    })

First, the current VueComponent Options and the rendering function in the instance will be replaced with the latest, and then the forceUpdate method on the instance will be executed:

.$forceUpdate = function () {
          var vm = this;
          if (vm._watcher) {
              vm._watcher.update();
          }
      };

This method is to execute the update method of the watcher instance:

 = function () {
          /* istanbul ignore else */
          if () {
               = true;
          }
          else if () {
              ();
          }
          else {
              queueWatcher(this);
          }
      };
function queueWatcher(watcher) {
      var id = ;
      if (has[id] != null) {
          return;
      }
      if (watcher ===  && ) {
          return;
      }
      has[id] = true;
      if (!flushing) {
          (watcher);
      }
      else {
          // if already flushing, splice the watcher based on its id
          // if already past its id, it will be run next immediately.
          var i =  - 1;
          while (i > index$1 && queue[i].id > ) {
              i--;
          }
          (i + 1, 0, watcher);
      }
      // queue the flush
      if (!waiting) {
          waiting = true;
          if (!) {
              flushSchedulerQueue();
              return;
          }
          nextTick(flushSchedulerQueue);
      }
  }

Focus on queueWatcher(this), put the latest watcher into the queue queue and pass the flushSchedulerQueue function to nextTick.

function nextTick(cb, ctx) {
      var _resolve;
      (function () {
          if (cb) {
              try {
                  (ctx);
              }
              catch (e) {
                  handleError(e, ctx, 'nextTick');
              }
          }
          else if (_resolve) {
              _resolve(ctx);
          }
      });
      if (!pending) {
          pending = true;
          timerFunc();
      }
      // $flow-disable-line
      if (!cb && typeof Promise !== 'undefined') {
          return new Promise(function (resolve) {
              _resolve = resolve;
          });
      }
  }

Put a function that executes a callback in callbacks. And execute timerFunc():

timerFunc = function () {
          p_1.then(flushCallbacks);
          // In problematic UIWebViews,  doesn't completely break, but
          // it can get stuck in a weird state where callbacks are pushed into the
          // microtask queue but the queue isn't being flushed, until the browser
          // needs to do some other work, . handle a timer. Therefore we can
          // "force" the microtask queue to be flushed by adding an empty timer.
          if (isIOS)
              setTimeout(noop);
      };

This method executes flushCallbacks asynchronously:

function flushCallbacks() {
      pending = false;
      var copies = (0);
       = 0;
      for (var i = 0; i < ; i++) {
          copies[i]();
      }
  }

Start executing the callback function. The function we put in for the first time:

function flushSchedulerQueue() {
      currentFlushTimestamp = getNow();
      flushing = true;
      var watcher, id;
      // Sort queue before flush.
      // This ensures that:
      // 1. Components are updated from parent to child. (because parent is always
      //    created before the child)
      // 2. A component's user watchers are run before its render watcher (because
      //    user watchers are created before the render watcher)
      // 3. If a component is destroyed during a parent component's watcher run,
      //    its watchers can be skipped.
      (sortCompareFn);
      // do not cache length because more watchers might be pushed
      // as we run existing watchers
      for (index$1 = 0; index$1 < ; index$1++) {
          watcher = queue[index$1];
          if () {
              ();
          }
          id = ;
          has[id] = null;
          ();
          // in dev build, check and stop circular updates.
          if (has[id] != null) {
              circular[id] = (circular[id] || 0) + 1;
              if (circular[id] > MAX_UPDATE_COUNT) {
                  warn$2('You may have an infinite update loop ' +
                      (
                          ? "in watcher with expression \"".concat(, "\"")
                          : "in a component render function."), );
                  break;
              }
          }
      }
      // keep copies of post queues before resetting state
      var activatedQueue = ();
      var updatedQueue = ();
      resetSchedulerState();
      // call component updated and activated hooks
      callActivatedHooks(activatedQueue);
      callUpdatedHooks(updatedQueue);
      // devtool hook
      /* istanbul ignore if */
      if (devtools && ) {
          ('flush');
      }
  }

First trigger(), which is the hook beforeUpdate. Then execute the() method:

 = function () {
          if () {
              var value = ();
              if (value !==  ||
                  // Deep watchers and watchers on Object/Arrays should fire even
                  // when the value is the same, because the value may
                  // have mutated.
                  isObject(value) ||
                  ) {
                  // set new value
                  var oldValue = ;
                   = value;
                  if () {
                      var info = "callback for watcher \"".concat(, "\"");
                      invokeWithErrorHandling(, , [value, oldValue], , info);
                  }
                  else {
                      (, value, oldValue);
                  }
              }
          }
      };

This method, the method will re-execute the render method to generate vnode, and then call the update method to update the node:

updateComponent = function () {
              vm._update(vm._render(), hydrating);
          };

Summarize:

1. Get the latest render and staticRenderFns of the listening file and assign it to the current VueComponent and the current vm instance.

2. Use $forceUpdate to add the current vm's watcher and in the queue, and finally execute the flushSchedulerQueue asynchronously. This function traverses the queue's run method of the watcher, which will execute the _update method of the vm instance to complete the update.

This is the article about the detailed introduction to the page update after Vue data changes. For more relevant Vue page update content, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!