关于为什么监听effect时开启immediate第一次会返回undefined

HugoKwong / 2024-08-28 / 原文

说白了就是源码这样写的,这里再科普下WatchEffect

WatchEffect和Watch不同之处:

  1. 进入页面马上就回调用一下
  2. 有许多变体,WatchEffectSync等,都是WatchEffectOption下面的属性flush?: 'pre' | 'post' | 'sync';

当然可以帮你理解 watchEffect 的用法和场景。

场景描述

你提到的场景涉及到一个页码组件,用户可以点击页码来请求数据。如果用户快速点击多个页码,会导致多个异步请求并且可能出现数据错乱的问题。

问题分析

  1. 请求错乱:如果用户快速点击,从1到5连续请求,最终显示的内容可能不是用户想要的最后一页(例如第5页),而是第1页的响应最先返回,导致页面显示不准确。

  2. 带宽浪费:快速点击导致的多次请求,前几次的请求可能是用户并不关心的,造成了不必要的带宽浪费。

解决方案

为了处理这些问题,watchEffect 提供了一个 onInvalidate 的回调函数,可以用来取消之前的异步请求。

使用 watchEffect

下面是如何使用 watchEffectonInvalidate 的示例代码:

import { ref, watchEffect } from 'vue';

const currentPage = ref(1);

watchEffect(onInvalidate => {
  const token = performAsyncOperation(currentPage.value);

  // 注册失效回调
  onInvalidate(() => {
    // 取消之前的请求
    token.cancel();
  });
});

function performAsyncOperation(page) {
  // 这里是你异步请求的逻辑
  const controller = new AbortController();
  const signal = controller.signal;

  fetch(`/api/data?page=${page}`, { signal })
    .then(response => response.json())
    .then(data => {
      // 处理数据
    });

  return {
    cancel: () => controller.abort() // 取消请求
  };
}

解释

  • watchEffect:当 currentPage 变化时,它会重新执行传入的函数。
  • onInvalidate:每次 watchEffect 被重新执行时,都会调用这个回调来清理之前的请求。
  • token.cancel():通过调用这个方法来取消之前的请求,避免了不必要的带宽浪费和数据错乱。

总结

使用 watchEffectonInvalidate 可以有效地管理异步请求,确保只有最新的请求被处理,避免了由于快速点击导致的请求错乱和资源浪费。这种方式使得你的组件更加高效和响应迅速。