---
# System prepended metadata

title: "\U0001F3C5 Day 17 - ref、reactive"
tags: [TypeScript 直播班-2025]

---

# 🏅 Day 17 - ref、reactive

本日開始會帶入一些和 Vue 結合的一些小練習，讓同學可以對如何將 TypeScript 導入到實際的開發上更有把握~
延續昨日的每日任務內容，一樣會使用六角的 TodoList API 進行練習！

1. API 網址：https://todolist-api.hexschool.io/
2. API 文件：https://todolist-api.hexschool.io/doc/

## ref

Vue 當中的 `ref` 方法是 Composition API 中的核心功能之一，可以用來建立可互動的參考對象或存取 DOM 元素。透過 `ref()` 來包裝基本型別可以讓資料在變動時自動觸發畫面更新，並且能夠透過 `.value` 讀取或修改內容。
至於 `ref` 和 TypeScript 的互相搭配則可以用下面幾種不同的方式來表示：

```tsx
// 對於基本型別的 ref，可以透過 Generic 的方式來將型別給帶入到裡面
const name = ref<string>("")
// 不過像上面的例子有初始值給定的狀況下，也可以省略型別的指定 (類似型別推斷的效果)
const amount = ref(0)

// 一般來說比較必要帶入型別的情況會是對於陣列或是 DOM 元素的 ref
const numArr = ref<number[]>([])
const addressInput = ref<HTMLInputElement | null>(null)
```

## reactive

而另一種 `reactive` 方法則主要常用於建立物件，在其中的屬性值產生變動時自動觸發畫面更新，適合處理結構化資料，例如表單或狀態物件等。它與 `ref` 的差異在於 `reactive` 可以直接操作物件當中的屬性屬性，不需要再透過 `.value` 來存取內容。
在 TypeScript 的搭配上，則可以直接利用類似型別註釋的方式來為 `reactive` 加上型別定義：

```tsx
type UserInfo = {
    name: string;
    email: string;
    age: number;
}

const userInfo: UserInfo = reactive({
    name: "",
    email: "",
    age: 0
})
```

## 實作時間！

經過昨天將通用的 API 請求方法設計完成並套用到 TodoList API 後，接下來就可以將設計好的方法在實際的元件裡面來使用了！本日主要會圍繞在使用者相關的功能來進行練習，包含註冊、登入和顯示登入狀態 (nickname) 的實作。
下方為參考的簡易 template 範例，在練習時可以直接複製到專案當中來使用，或是也可以自行設計版面的呈現方式~

```html
<template>
  <section>
    <!-- TODO：註冊區塊 -->
    <div>
      <h2>註冊帳號</h2>
      <form class="form">
        <div>
          <label for="email">Email: </label>
          <input type="email" id="register-email" name="email" required />
        </div>
        <div>
          <label for="password">Password: </label>
          <input type="password" id="register-password" name="password" required />
        </div>
        <div>
          <label for="nickname">Nickname: </label>
          <input type="text" id="nickname" name="nickname" required />
        </div>
        <button type="submit">註冊</button>
      </form>
    </div>
    <!-- TODO：登入區塊 -->
    <div>
      <h2>登入帳號</h2>
      <form class="form">
        <div>
          <label for="email">Email: </label>
          <input type="email" id="login-email" name="email" required />
        </div>
        <div>
          <label for="password">Password: </label>
          <input type="password" id="login-password" name="password" required />
        </div>
        <button type="submit">登入</button>
      </form>
    </div>
    <!-- TODO：顯示登入狀態 -->
    <h2>{{ username ? "Hello " + username : "未登入" }}</h2>
  </section>
</template>
```

請實作該元件的 `<script>`，並且適當的調整 template 內容 (通常是在互動欄位中加入綁定函式等設定)，透過串接 API 來完成使用者註冊、登入以及狀態的顯示。
另外一點需要注意的是，在引入 TypeScript 時，需要在 Vue 檔案中的 `script` 標籤內加入 `lang="ts"`

```javascript
<script setup lang="ts">
const username = ref("")

// TODO: 可以利用 ref 或 reactive 來處理表單資料的控制，
// 並串接到 TodoList API 來實現註冊、登入的功能
// ...
</script>
```

<!-- 參考範例：
type SignupRequest = {
  email: string;
  password: string;
  nickname: string;
};

type SigninRequest = Omit<SignupRequest, "nickname">;

const signupData: SignupRequest = reactive({
  email: '',
  password: '',
  nickname: '',
});

const signinData: SigninRequest = reactive({
  email: '',
  password: '',
});

// 此處需將 signupData 和 signinData 的值綁定到表單的欄位中，例如：
// <input v-model="signupData.email" type="email" id="register-email" name="email" required />

const submitRegister = async () => {
  const response = await register(signupData);
  console.log(response);
};

const submitLogin = async () => {
  const response = await login(signinData);
  console.log(response);
  localStorage.setItem('token', response.token);
  username.value = response.nickname;
};
-->