MST

星途 面试题库

面试题:Vue Composition API自定义Hooks中如何处理副作用及依赖关系

假设你要创建一个自定义Hooks,用于在组件挂载时发起一个HTTP请求,并在组件卸载时取消这个请求以避免内存泄漏。请详细说明如何使用Vue Composition API来实现这个功能,包括如何处理副作用以及依赖关系,同时指出可能遇到的问题及解决方案。
48.2万 热度难度
前端开发Vue

知识考点

AI 面试

面试题答案

一键面试

实现步骤

  1. 引入必要的依赖:在Vue项目中,如果使用axios进行HTTP请求,首先要安装并引入axios。
npm install axios
  1. 创建自定义Hooks:使用Vue Composition API中的onMountedonUnmounted来处理组件的挂载和卸载。
import { onMounted, onUnmounted, ref } from 'vue';
import axios from 'axios';

export function useHttp() {
  const response = ref(null);
  const error = ref(null);
  let controller;

  const fetchData = async (url) => {
    controller = new AbortController();
    const { signal } = controller;
    try {
      const res = await axios.get(url, { signal });
      response.value = res.data;
    } catch (err) {
      if (err.name === 'AbortError') {
        // 请求被取消时的处理
        console.log('请求已取消');
      } else {
        error.value = err;
      }
    }
  };

  onMounted(() => {
    // 组件挂载时发起请求
    fetchData('your - api - url');
  });

  onUnmounted(() => {
    // 组件卸载时取消请求
    controller && controller.abort();
  });

  return { response, error };
}
  1. 在组件中使用自定义Hooks
<template>
  <div>
    <div v - if="response">
      <pre>{{ response }}</pre>
    </div>
    <div v - if="error">{{ error }}</div>
  </div>
</template>

<script setup>
import { useHttp } from './useHttp';

const { response, error } = useHttp();
</script>

处理副作用及依赖关系

  1. 副作用处理:在fetchData函数中发起HTTP请求,这是一个副作用操作。通过onMountedonUnmounted生命周期钩子来控制副作用的执行和清理。onMounted确保在组件挂载时发起请求,onUnmounted确保在组件卸载时取消请求,避免内存泄漏。
  2. 依赖关系:这里的依赖关系主要是fetchData函数中的url。如果url在组件内是动态变化的,需要注意在url变化时重新发起请求。可以通过计算属性或者watch来监听url的变化,并重新调用fetchData。例如:
import { onMounted, onUnmounted, ref, watch } from 'vue';
import axios from 'axios';

export function useHttp() {
  const response = ref(null);
  const error = ref(null);
  let controller;
  const url = ref('your - api - url');

  const fetchData = async () => {
    controller = new AbortController();
    const { signal } = controller;
    try {
      const res = await axios.get(url.value, { signal });
      response.value = res.data;
    } catch (err) {
      if (err.name === 'AbortError') {
        console.log('请求已取消');
      } else {
        error.value = err;
      }
    }
  };

  onMounted(() => {
    fetchData();
  });

  onUnmounted(() => {
    controller && controller.abort();
  });

  watch(url, () => {
    controller && controller.abort();
    fetchData();
  });

  return { response, error, url };
}

可能遇到的问题及解决方案

  1. 多次请求问题:如果在组件挂载期间,fetchData函数被多次调用(例如通过watch监听数据变化触发),可能会导致多次发起请求。解决方案是在每次发起新请求前,取消之前的请求。如上述代码中watch部分,每次url变化时,先取消之前的请求再发起新请求。
  2. 兼容性问题AbortController在一些旧浏览器中不支持。解决方案是使用polyfill,例如abortcontroller - polyfill。首先安装:
npm install abortcontroller - polyfill

然后在入口文件(如main.js)中引入:

import AbortController from 'abortcontroller - polyfill/dist/abortcontroller - polyfill';
if (!window.AbortController) {
  window.AbortController = AbortController;
}
  1. 请求结果处理:在处理复杂业务逻辑时,可能需要对不同的HTTP状态码进行不同处理。可以在catch块中进一步判断err.response.status来处理不同情况。例如:
catch (err) {
  if (err.name === 'AbortError') {
    console.log('请求已取消');
  } else if (err.response) {
    switch (err.response.status) {
      case 404:
        error.value = '资源未找到';
        break;
      case 500:
        error.value = '服务器内部错误';
        break;
      default:
        error.value = err.message;
    }
  } else {
    error.value = err.message;
  }
}