# Vue3教程 - 16 Hooks

我们先实现一个简单的功能,然后抛出问题。

实现一个简单的功能:

  • 点击按钮,让 count 值+1 ;
  • 点击按钮,发起网络请求,每次请求接口随机获取一段名言。(网络请求后面再讲,这里先简单使用)。

# 16.1 编写简单的功能

首先安装 axios 用来发送网络请求:

# 使用npm
npm install axios

# 或者使用yarn
yarn add axios
1
2
3
4
5

为了方便,我直接在 App.vue 中编写组件内容如下,也可以在子组件中实现:

在下面面的代码中,每次点击 count++ 按钮,count++,每次点击 获取名言 按钮,获取名言,并添加到列表中展示。

<template>
  <div>{{ count }}</div>
  <div>
    <button @click="plus">count++</button>
  </div>
  <br/>
  
  <div>
    <div>
      <button @click="getQuote">获取名言</button>
    </div>
    <ul>
      <li v-for="(quote, index) in quoteList" :key="index">
        {{ quote }}
      </li>
    </ul>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import { reactive, ref } from 'vue'
import axios from 'axios';

let count = ref(0);
let quoteList: string[] = reactive([]);

function plus() {
  count.value++;
}

function getQuote() {
  axios.get('https://api.quotable.io/random').then(
    (response) => {
      // 确保 response.data.content 存在并且是字符串  
      if (typeof response.data.content === 'string') {
        quoteList.push(response.data.content);
      } else {
        console.error('Invalid quote content');
      }
    },
    (error) => {
      alert('获取名言出错');
    }
  )
}
</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

显示效果:

在前面介绍说 Vue3 使用组合式 API ,将同一个功能的数据和逻辑放到一起,但是在前面并没有体现,在上面的代码中,可以看到所有的功能都混合到一起了。

下面就介绍 Hooks,实现各个功能的拆分和封装,体验组合式 API。

# 16.2 Hooks使用

# 1 封装代码到单独的TS文件

可以在 src 下新建 hooks 文件夹,在其中创建单独的 .js.ts 文件,将功能拆分到单独的文件中。

但是需要注意:文件名需要以 use 作为前缀


创建 src/hooks/useCount.ts ,内容如下:

将 Count 相关的逻辑挪到这个文件中。

import { ref, onMounted } from "vue";

export default function () {
  let count = ref(0);

  function plus() {
    count.value++;
  }

  // 可以添加生命周期函数
  onMounted(() => {
    plus();
  });

  // 导出
  return {count, plus};
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

在 hooks 中,导出一个函数,将之前的代码逻辑迁移到这个函数中,然后最后导出一个对象,包含变量和方法。

在函数中,还可以添加生命周期函数、监听器等模块。


创建 src/hooks/useQuote.ts ,内容如下:

将 Quote 相关的逻辑挪到这个文件中。

import { reactive, onMounted } from "vue";
import axios from "axios";

export default function () {
  let quoteList: string[] = reactive([]);

  function getQuote() {
    axios.get("https://api.quotable.io/random").then(
      (response) => {
        // 确保 response.data.content 存在并且是字符串
        if (typeof response.data.content === "string") {
          quoteList.push(response.data.content);
        } else {
          console.error("Invalid quote content");
        }
      },
      (error) => {
        alert("获取名言出错");
      }
    );
  }

  // 可以添加生命周期函数
  onMounted(() => {
    getQuote(); // 上来就获取一个
  });

  return { quoteList, getQuote };
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

现在已经将各个逻辑功能拆分成独立的单元了。

# 2 在组件中引入并使用

在组件中引入上面的 hooks。

<template>
  <div>{{ count }}</div>
  <div>
    <button @click="plus">count++</button>
  </div>
  <br/>

  <div>
    <div>
      <button @click="getQuote">获取名言</button>
    </div>
    <ul>
      <li v-for="(quote, index) in quoteList" :key="index">
        {{ quote }}
      </li>
    </ul>
  </div>
</template>

<!-- setup -->
<script lang="ts" setup>
import useCount from './hooks/useCount';
import useQuote from './hooks/useQuote';

// 调用函数并解构
const {count, plus} = useCount();
const {quoteList, getQuote} = useQuote();

</script>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

引入上面拆分的单元,然后调用函数,返回结果包含变量和函数,对返回的结果进行解构,就可以直接使用了。


通过 Hooks 将功能进行独立的封装,提高了代码的复用性、可维护性和清晰度。