0%

Welcome to Hexo! This is your very first post. Check documentation for more info. If you get any problems when using Hexo, you can find the answer in troubleshooting or you can ask me on GitHub.

Quick Start

Create a new post

1
$ hexo new "My New Post"

More info: Writing

Run server

1
$ hexo server

More info: Server

Generate static files

1
$ hexo generate

More info: Generating

Deploy to remote sites

1
$ hexo deploy

More info: Deployment

之前曾快速的學習了React 資料的建立與傳遞方式,並寫了篇文章,最近因為六角讀書會活動也再次更深入一些的學習 React ,並將一些 React Hook 反覆使用練習。
因為目前工作主要還是以 Vue 進行開發,所以有時候會提一下兩者框架使用的相同或不同之處。

component 元件化

在 Vue 的撰寫中,也是會嘗試將頁面中的不同區塊做拆分。與 Vue 一樣,元件的的命名會以 大寫 為開頭。
透過減少重複為用意來建立元件化。


codepen-Component

多個資料,傳遞給單一元件

  • 建立兩個元件 component1 , component2
  • 建立共通元件 Board ,此元件可以各別放入兩個元件要傳入的資料(props)

codepen-共用元件

共同資料,傳遞給不同元件

codepen-共用資料

條件 render

  • 這部分在官方文件就有清楚介紹,可以依據使用條件來顯示元件資料
  • 使用條件判斷時,若不複雜,可以使用三元運算方式
    • isLoggedIn ? <UserGreeting /> : <GuestGreeting />
  • conditional-rendering

元件資料傳遞

子傳父

  • 範例將以 input 為範例
  • 此方式的資料傳遞,有點類似於 Vue 中的 v-model 資料雙向綁定
  • 使用 v-model 實現父子元件傳遞資料
  • 在 React 可以將 useState 中設訂的值綁在元件上作為傳遞
  • 在下方的圖示
  • 在父層有 value , setValue

-> 其中 setValue 方法提供給子元件,同時就會讓子元件也產生改變 value 的能力(也就是可以使用父元件的方法)

  • 要實現子傳父,就在父層掛一個 hook

經常使用 vue 或 React 等前端框架來進行專案開發,但沒有機會好好來認識下他背後的打包工具:webpack
趁著這次六角釋出的基礎 webpack 教學,順道來記錄一下。

前端壓縮打包工具

  • 從官網的圖,很明顯地就可以看到將左側複雜的檔案進行壓縮,並做項目管理
  • 在 Vue , React 的背後都有使用 webpack

    使用 webpack

  1. 安裝
    建立 webpack 需要使用到 npm 初始化
    npm init -y
    安裝之後,會產生 package.jason 檔案

  2. 安裝 webpack 以及 webpack-cli ,並存在 開發環境
    npm install webpack webpack-cli --save-dev

    • 會產生 package-lock.json => 紀錄版本詳細資訊
    • node_modules 資料夾

進入點(entry)、輸出點(output)

  • /src/index.js
  • /dist/main.js
  • 指令:"build": "webpack" => 設定 webpack 將 src 中的 index.js 檔案輸出,放到 dist 資料夾
    • 使用該指令 npm run build
      • build 之後產生 dist/main.js

entry, output 名稱修改

* 建立 `webpack.config.js` 檔案
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const path = require('path');

module.exports = {
//預設路徑位置
entry: './src/index.js',
output: {
//輸出位置名稱(filename),檔案位置
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
};

//path.resolve(__dirname, 'dist')
// dirname當前資料夾路徑
//path.resolve 將相對路徑改為絕對路徑

讓每次產生的 bundle 名稱不一樣

  • 搭配 plugin 來使用 HtmlWebpackPlugin

NPM script , 自訂指令

  • 用 node 執行一段 JS ,位置為同層下的 hello.js
  • npm run hello
  • 網站上線\部署或開發,可能都需要下不同指令來進行管理

mode 切換

  • 不同模式下,會因程式內容而輸出不同內容
  • production 上線版模式, 輸出的 bundle 檔案會較為精簡
    • 會壓縮優化,將程式碼壓成一行
    • 不容易除錯與理解

CSS loader

  • 幫助 webpack 載入 css
  • npm install --save-dev css-loader
  • CSS loader
  • webpack.config.js
  • 別忘了 在載入點加入 ·import css from './all.css'
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
const path = require('path');

module.exports = {
//預設路徑位置
entry: './src/index.js',
output: {
//輸出位置名稱(filename),檔案位置
path: path.resolve(__dirname, 'dist'),
filename: 'bundle.js',
},
module: {
rules: [
{
test: /\.css$/i, //只要副檔名為 .css 就會使用以下
use: ["style-loader", "css-loader"],
},
],
},
};

載入 webpack 測試伺服器

1
2
3
4
5
6
7
8
9
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
//contentBase: path.join(__dirname, 'dist'),
},
compress: true,
port: 9000,
open: true //可以即時更新
},
  • 最後,指令調整,如此就可以開始進行編譯

  • webpack 也可以載入 node_module 下的東西

  • 用 dist 下的檔案來部署

    webpack.config.js 檔案

  • 注意

  • mode: 設定development 或是 production

  • entry 進入點在哪

  • output 輸出去哪

  • module -> rule 下 會放 scss-loader , babel-loader 等規則

  • plugins: webpack 主要是讀檔案,但透過 plugins ,如建立新的 html檔案, MiniCssExtractPlugin:將 css 從 js 抽離出來

  • devtool: ‘source-map’ => 協助檔案 debug

關於 Webpack,它是什麼?能夠做什麼?為什麼?怎麼做?— freeCodeCamp 的筆記
Webpack 是什麼?模組打包工具的用途及基本 Webpack 教學

props, state 的應用

  • props 傳入參數的部分
  • state 讓組建本身有狀態

製作 計數器

  • props
  • 製作,讓計數器的數字變化,可以同步變化到 button 上的數字
    • 在父層 App.vue 做一個內容的傳送
    • 在 子元件,要自訂一個變數,作為接收父層從來的資料
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
import "./styles.css";

type BtnProps = {
btnNum: number;
};

const Btn: React.FC<BtnProps> = ({ btnNum }) => {
return (
<button>
add 1<span>目前總數:{btnNum}</span>
</button>
);
};

export default function App() {
const num = 0;
return (
<div className="App">
<h1>Counter: {num}</h1>

<Btn btnNum={num} />
</div>
);
}


進階,希望透過點擊 button 同步更改數值

  • 讓 render (react 渲染機制),可以在變數被變動的時候順便觸發渲染機制

    • 改變變數 -> 觸發渲染

      使用 state 達成上述目的

    對組建本身引入 state 機制

  • 用 state 來做變數宣告,只要 state 變數有做變動都會觸發渲染機制

    • 當變數有涉及於頁面上的更新,就會需要使用 state
  • Hook 本身多是 use 開頭

  • useState() 是一個 function

用陣列解構來取的 return 的值

    1. 當前的值
    1. 再回傳一個 function : 用來設定/變動 第一個數值
      const [num2, setNum2] = useState(999)

example-1

實現 父層數值變化,子組件隨之變化

  • 應該將主要的更新動作都放置父組件
  • 將放在父組件的事件,透過 props 方式傳給子組件,並將該變數放到按鈕的點擊事件上

example-2

剛學習 vue 的時候,對 slot 完全一竅不通,不了解要如何挖空多元件,來放入資料,更是不知道他能使用的時機是什麼時候,種種因素,讓我從官方文件找些範例釐清,也找了些文章閱讀加深記憶,順手也紀錄在部落格上~

使用時機:

  • 使用同一個 元件 , 但只有內文不同。
  • 有時候資料是靜態,不常變動,甚至需要大量重複。這情況不必要使用 props。
  1. 共用樣式
    官網的範例可以看到,讓按鈕的文字可以彈性的變化。

  2. named slot(具名插槽)

  • 建立一個元件,其中含有多個slot區塊
    範例連結
  1. Scoped slots(作用域插槽)
  • 把子元件的資料取出來,給父層使用
  • 不同於前面 slot 的使用,是由父層輸入資料呈現於頁面
    範例

資料來源:
vuejs
不只懂 Vue 語法:什麼是 slot?請示範 slot 的用法?
用範例理解 Vue.js #18:Slot

近期購買了布魯斯的 TypeScript 的課程,除了學到型別之外,還接觸到 WebSocket 的使用,所以就來簡單紀錄下 WebSocket 是什麼,在專案內可以實現什麼功能。

WebSocket是一種網路傳輸協定,讓前端與後端溝通除非有一方斷開連接,否則會一直保持聯繫

情境說明

  1. 使用者上下線狀態:可以延遲幾秒鐘,可以使用 setInterval 做出輪循
  • 設定每幾秒發出請求,更新狀態
  • 使用 HTTP 協議的請求:GET\POST 等方式,做出Request\Response
  1. 聊天室:會希望聊天訊息是即時更新,若採用上面的方式,為了使訊息更新及時會從每幾秒改為每幾毫秒,這樣的方式會造成短時間內不斷發出請求,造成消耗後端資源
  • 指建立一次連結,可以與後端持續保持聯係

聊天室的實際運用

  • 將在 node.js 建立 websocket 的服務,讓前端連線到node.js的服務
  • socket.io => 包裝 websocket 協議的 node.js 的工具包
    • 當使用 node.js 做開發,就可以透過 socket.io 提供的功能實現

安裝 socket.io

  • socket.io-clinet : 在前端的部分要使用 clinet 安裝包
    npm i -D socket.io socket.io-clinet

後端

  • 將 socket.io 引入 node.js 的 server 端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
import devServer from "@/server/dev";
import prodServer from "@/server/prod";
import express from "express";
import { Server } from "socket.io"
import http from "http" //也可以引入http模組

const port = 3000;
const app = express();
//透過 http 將 server 建立起來
const server = http.createServer(app)
const io = new Server(server)
const userService = new UserService

//監聽
server.listen(port, () => {
console.log(`The application is running on port ${port}.`);
});

1
2
3
4
5
6
//建立起連接時,發出訊息
//當有用戶連接到connection 就會有回呼函式
io.on('connection',(socket)=>{
//發出訊息
socket.emit('join', 'Welcom')
})

如何在前端使用,與後端建立連線?

  • 到前端的入口檔案
1
2
3
4
5
6
7
8
9
10
//將 socket.io 的包引入前端程式這邊
import { io } from "socket.io-client";

//1. 建立連接到 node server
const clientIo = io();


clientIo.on('join',(msg)=>{
console.log('msg',msg)
})

toRef

  • 將…變成 ref
    從 reactive 物件抽出包裝成一個 ref 的值,與原本物件 是連接的,所以修改時,原本的值也會跟著變動。
  • 只能處理一個屬性,須告知要輸入的屬性\物件
  • 注意: 更改原始物件內的值,所響應會跟著變動

在 prop 的應用

  • 來自的 props 是 物件資料,可以使用toRef
    1
    2
    3
    4
    5
    6
    7
    8
    9
    props: {
    apiUser: {
    required: true,
    type: Object
    }
    },
    setup(props) {
    const userCopy = toRef(props, 'apiUser')
    }
  • 範例二
1
2
3
4
5
6
7
8
9
10
<template>

<h2>姓名: {{person.name}}</h2>
<h2>年齡: {{person.age}}</h2>
<h2>職業描述: {{person.job.front.dec}}</h2>
<button @click='person.name += ~'>修改姓名</button>
<button @click='person.age ++ '>增加年齡</button>

</template>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<script>
import {reactive} from 'vue';

export default {
name: 'Demo',
setup(){
const person = reactive({
name: 'Eva',
age: 25,
job:{
front:{
dec:'前端工程師'
}
}
})

return{
person
}
}
}
</script>
  • 要將以上的模板寫的更容易
1
2
3
4
5
6
7
8
9
10
<template>

<h2>姓名: {{name}}</h2>
<h2>年齡: {{age}}</h2>
<h2>職業描述: {{dec}}</h2>
<button @click='name += ~'>修改姓名</button>
<button @click='age ++ '>增加年齡</button>

</template>

1
2
3
4
5
6
//就是返回普通的物件內容
return{
name: person.name,
age: person.age,
dec: person.job.front.dec
}
  • 但此方式要注意,字串模板會無法響應更新的問題

  • 使用 toRef 來達到響應

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
<script>
import {reactive,toRef} from 'vue';

export default {
name: 'Demo',
setup(){
const person = reactive({
name: 'Eva',
age: 25,
job:{
front:{
dec:'前端工程師'
}
}
})

//單一轉換
const name2 = toRefs(person,'name')

return{
name: toRef(person,'name'),
age: toRef(person,'age'),
dec: toRef(person.job.front,'dec')
}
}
}
</script>

toRefs

toRefs用來把響應式物件轉換成普通物件,把物件中的每一個屬性,包裹成ref物件
* toRefs就是toRef的升級版,只是toRefs是把響應式物件進行轉換

延續上方,toRefs

  • 可以批量處理,一個物件裡的屬性
    • 只會將第一層展開,所以以下在 job 的內層
1
2
3
4
5
6
7
8
9
10
<template>

<h2>姓名: {{name}}</h2>
<h2>年齡: {{age}}</h2>
<h2>職業描述: {{job.front.dec}}</h2>
<button @click='name += ~'>修改姓名</button>
<button @click='age ++ '>增加年齡</button>

</template>

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
<script>
import {reactive,toRefs} from 'vue';

export default {
name: 'Demo',
setup(){
const person = reactive({
name: 'Eva',
age: 25,
job:{
front:{
dec:'前端工程師'
}
}
})

//可以批量處理,所以只需要傳入個物件,
const new = toRefs(person)
console.log(new)

//在物件中再放toRefs(person) ,會變成物件包物件,所以要展開
return{
...toRefs(person)
// name: toRef(person,'name'),
// age: toRef(person,'age'),
// dec: toRef(person.job.front,'dec')
}
}
}
</script>

從開始學習前端之後,大多的學習資源都是來自線上課程、youtube 影片為主,鮮少透過閱讀書籍來學習相關知識,但自從進入公司之後,因為公司內有些程式書籍能夠借閱,先是從 JavaScript 大全開始,一開始閱讀起來真的滿痛苦,不知道該如何消化內容,直接順著讀過去又怕忘記,但目前還是順順的讀到了第8章~後來,找到的方式就是在筆記軟體上做些註記,工作上遇到相關的再回過頭看一次,加入筆記。

而在此次,發現 TypeScript 即便已經看過介紹型別、基本使用基礎的影片後,仍然覺得不太足夠,所以就開始翻閱書籍 「讓 TypeScript 成為你全端開發的 ACE」,文中介紹滿多之前沒有注意到觀念、也有帶到不少 JavaScript 的觀念來呼應。所以本篇,多是來自於書中資訊,透過整理呈現。

註記 Annotation V.S. 斷言 Assertion

  • 型別註記:指在告訴 TS 編譯器:「任何被註記到的變數、函式的參數等,都必須遵照被註記過後的變數型別」。
  • 所以編譯器會隨時隨地的監測該變數有沒有出現型別衝突的可能—關鍵字為遵照。
  • 而,斷言型別則是無視 TS 編譯器分析整個程式碼的型別推論過程,果斷的告訴 TS 編譯器:「被斷言過後的表達式之運算結果就是某某型別」—關鍵意象是「覆蓋」該表達式的型別推論結果。

註記與斷言

  • 帶有冒號的相關語法
1
2
let randomNumber:number = Math.random();
const subscribed:boolean = true;
  • 如果遇到函式,參數(Argument)部分除了可以有類似註記方式標明輸入的參數型別外,在參數宣告結尾也可以註記該函式輸出之型別。
1
2
3
function isPositive(input: number):boolean{
return input > 0
}
  • 但JS裡,宣告函式的方法有很多種,其中一個是將函式最為值指派到變數。
1
2
3
const isPositive:(input:number) => boolean = function(input){
return input > 0
}
  • 以上,也能把變數指派的函式,改成ES6箭頭函式
    • 指派運算子(Assignment Operator ,就是指程式裡的等號)左方是函式的型別註記表示法,右方則是普通函式宣告
1
const isPositive:(input:number) => boolean = input => input >0;
  • 採用邊宣告函式、邊註記型別的方式定義函式
1
2
3
const isPositive = function (input:number):boolean{
return input>0
}
1
2
const isPositive =  (input:number):boolean =>  input>0

型別斷言語法

  • 斷言(Assertion)的語法很簡單,看到有使用關鍵字 as 或者 <T>(...) 的格式就是斷言的用法。
  • 通常會使用斷言的情境,程式沒辦法推論某表達式的確切運算結果之型別,我們才會用選擇使出斷言來處理這種情境。
  • 程式沒辦法推論?
    • 使用第三方的資源(Third-party resources),如使用外來JSON API 獲得的內容之型別格式、讀取檔案轉成 JSON 物件的結果、使用套件提供的功能、呼叫會回傳未知結果的函式。
1
const aNumber = returnsUnknow() as number;

或是這樣:

1
const aNumber = <number>(returnsUnkonw());
  • 請注意:斷言的語法部分,沒有人斷言在變數的名稱宣告部分—也就是是說,如果你這樣寫是錯的:
1
const aNumber as number = returnsUnknow(); //這是錯誤的
  • 概念有點像,決斷地告訴程式,某表達式的運算結果之型別。
  • 變數本身不是被運算,而是被指派某個東西,而斷言應該是斷在被指派的值或表達式的運算結果上。

複雜一點

  • 函式宣告表達式有可以被斷言(畢竟函式作為表達式也會被當成值)
1
const isPositive =(input => input > 0) as (input: number) => boolean

或者是:

1
const isPositive = <(input: number) => boolean>(input => input >0);
  • 上面斷言的寫法效果跟之前示範過基礎註記手法:
1
const isPositive :(input: number) => boolean = input => input >0;

或者是

1
const isPositive =(input: number):boolean => input >0;

說下,敘述式與表達式的定義與差別

  1. 敘述式:程式運行的流程,例如:JS 裡的判斷敘述式(if…else)以及迴圈敘述式(for 或者是 while 迴圈)。
  2. 表達式代表的則是程式碼運算的流程,並且會將運算結果回傳。其中兩者最關鍵差異為:敘述式不會回傳值,表達式則會。
  • 以下為常見的表達式範例:
1
2
3
4
5
6
7
8
9
10
 //運算表達式 Arithmetic expression
1+2*3 ; //回傳解果為7
//邏輯表達式 Logical Expression
true && (something === null || myAge < 18) //回傳結果為 true 或 false

//函式(或方法的呼叫) Function / Method Invocation Expression
Math.pow(2,10) //回傳結果為 1024

//三元運算子 Ternary Operator
myAge < 18 ? 'Youngster' : 'Adult'; //回傳結果為 'Youngster' 因為 myAge < 18

而敘述式:

1
2
3
4
5
6
7
8
9
10
11
12
13
if(/*expression 1*/){
//若 expression1 為 true 則執行

}else if(/*expression 2*/){
//若 expression2 為 true 則執行
} else{
//若 expression1、expression2 都不為 true 則執行此
}

//迴圈敘述式 Looping Statement
while (/*expression */){
//若 expression 為 true, 則重複執行直到 expression 為 false 時跳脫
}
  • 按照上面敘述式的定義 — 由於敘述式是在敘述運行流程,而不會回傳值,所以你才不會在 JavaScript 裡面看到這樣的寫法:
1
2
3
4
5
6
// JS 並有提供這寫法
const status = if(Age <18 ){
return 'Young'
}else{
return 'Adult'
}
  • 注意:敘述式不一定是多行式(或區塊式)地呈現的最佳案例:變數宣告的指派敘述式(Variable Declaration Assignment Statement)
    1
    2
    //變數宣告的 指派敘述式
    const foo =123;
  • 請問上面指派式會回傳什麼結果 =>數字 123 或 udefined。正解為 udefined
    • 指派式的回傳結果為 undefined
  • 所以可以歸納出,javaScript 的變數宣告的指派式屬於敘述式,非表達式。

表達式什麼時候會以非單行的程式碼,也就是區塊的方式?

  • 立即呼叫函式表達式(IIFE)
1
2
3
4
const status = (funcrion(myAge){
if (myAge <18){ return 'Young'}
return 'Adult'
})(16) //假設填入參數為16,呼叫該函式的結果回傳 'Young'
  • 當可以分清楚表達式與敘述式差別後,回歸型別斷言
  • 斷言的基礎語法
    • 斷言的語法只能用在表達式上,因為表達式具備回傳值,敘述式則沒有
    • 因此,可以「斷言該表達式所運算結果之代表型別」

寫法如下:

1
2
3
<expression> as T assertion

<T assertion >(<expression>)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//運算表達式
(foo+bar*baz) as number;

// 邏輯表達式
(isPositive(num) && idEven(num)) as boolean;

//function
Math.pow(2, 10) as number

//
(myAge <18 ? 'Young' : 'Adult') as string;

//IIFE
(funcrion(myAge){
if (myAge <18){ return 'Young'}
return 'Adult'
})(16) as number

//只要是表達式,就算在其他敘述式、表達式內也能使用
somefunction(foo as number , bar as string) as boolean

換種寫法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<number>(foo+bar*baz);

// 邏輯表達式
<boolean> (isPositive(num) && idEven(num)) ;

//function
<number> Math.pow(2, 10) ;

//
<string>(myAge <18 ? 'Young' : 'Adult') ;

//IIFE
<number>(
funcrion(myAge){
if (myAge <18){ return 'Young'}
return 'Adult'
})(16)
);
//只要是表達式,就算在其他敘述式、表達式內也能使用
<boolean>somefunction(foo as number , bar as string)

以上針對註記 Annotation V.S. 斷言 Assertion 做個簡單整理~

最近遇到將表單資料存到後端的方式,過去一直以為是將資料整理為物件方式存取即可,後來發現使用FormData來建立物件傳送檔案即可!

  • FormData 是一個表單格式,利用它將資料轉成表單的格式,並且以表單的形式回傳給後端

建立 FormData 物件

  • 最直接方式,先取得form的資料
1
2
3
4
5
6
7
8
// 根據表單元素取得表單資料
var form = document.querySelector('form');
var formData = new FormData(form);

// 可以用 append 把欄位灌進去表單中
var formData = new FormData(); // 一開始表單的資料是空的
formData.append('username', Chris); // 增加欄位
formData.append('image', file); // 檔案也可以透過 append 放進來

以下介紹幾個基礎的使用方式:

  • formData.append(name, value) : 加入有 name 和 value 的表單資料(name:表單標籤的名稱,value: input 輸入的值)
  • formData.append(name, blob, fileName) : 加入字段,就像它是 <input type="file">,第三個參數 fileName 設置檔案名
  • formData.delete(name) : 移除帶有 name 的字段,
  • formData.get(name) : 取得帶有 name 的值,
  • formData.has(name) : 如果帶有給定 name 的字段,返回 true,否則返回 false。

使用axios 傳遞資料

1
2
3
4
5
6
7
8
9
var formData = new FormData();
//宣告要取得的值
var title = form.name
formData.append("formTitle", title);
axios.post('upload_file', formData, {
headers: {
'Content-Type': 'multipart/form-data'
}
})

補充 vue+Typescript 宣告型別

  • 以 stack overflow 內的資料為例:
    • 可以使用 ref來取得DOM元素,並宣告該變數為HTMLFormElement
      1
      2
      3
      4
      5
      6
      <el-form
      class="m-auto"
      ref="formRef"
      :model="form"
      :rules="rules"
      >
      1
      const formRef = ref<HTMLFormElement>();
  • 另是使用 element-UI 的表單,也可以使用
    import { ElForm } from "element-ui";

如何使用jQuery AJAX submit 傳送form表單方法
JavaScript / jQuery 前端開發入門實戰
JavaScript Info-formData
stackoverflow

useAsyncData

1
2
3
4
5
6
7
8
9
10
const {
data: Ref<DataT>,
pending: Ref<boolean>,
refresh: (force?: boolean) => Promise<void>,
error?: any
} = useAsyncData(
key: string,
fn: () => Object,
options?: { lazy: boolean, server: boolean }
)
  • 頁面、組件中都可以使用useAsyncData 取得資料
  • Key :寫一個唯一的id
    請求資料的函式
  • 使用 useAsyncData 會回傳物件
    data : 返回的資料
    pedding : 指出資料是否被取得
    refresh : 是否要刷新資料

    Option 介紹

  • Lazy 延遲載入,直到數據獲取時,才顯示於頁面
  • 默認會是 false
  • Server 頁面是在server端要載入,就可以設定為true
  • Pick 從回傳的資料中,選擇要使用的key值

useAsyncData撰寫方式的範例

  • 本地建立資料夾
    • server/api/count.ts
1
2
3
4
5
let counter = 0
export default () => {
counter++
return JSON.stringify(counter)
}
  • app.vue,使用 useAsyncData
1
2
3
4
5
6
7
<script setup>
const { data } = await useAsyncData('count', () => $fetch('/api/count'))
</script>
<template>
Page visits: {{ data }}
</template>

useFetch

  • 頁面、組件中可以使用useFetch獲取任意URL資源
  • useFetch包裝 了useAsyncData 和 $fetch
  • 會根據 URL 自動生成 Key,也會去推斷API 的類型a
    1
    2
    3
    4
    5
    6
    const {
    data: Ref<DataT>,
    pending: Ref<boolean>,
    refresh: (force?: boolean) => Promise<void>,
    error?: any
    } = useFetch(url: string, options?)
1
2
3
4
5
6
7
<script setup>
const { data } = await useFetch('/api/count')
</script>

<template>
Page visits: {{ data.count }}
</template>

補充:其他2個類似方式

  • useLazyAsyncData : 方法等於useAsyncData,僅設置了lazy選項為true
  • useLazyFetch : 方法等於useFetch,僅設置了lazy選項為true

實作範例:

  • /api/mountains/everest
    • API 會產生的物件資料
1
2
3
4
5
6
7
8
9
10
11
{
"title": "Mount Everest",
"description": "Mount Everest is Earth's highest mountain above sea level, located in the Mahalangur Himal sub-range of the Himalayas. The China–Nepal border runs across its summit point",
"height": "8,848 m",
"countries": [
"China",
"Nepal"
],
"continent": "Asia",
"image": "https://upload.wikimedia.org/wikipedia/commons/thumb/f/f6/Everest_kalapatthar.jpg/600px-Everest_kalapatthar.jpg"
}

Nuxt 3 為了提高效率會在取得資料後,緩存在當前頁面的payload
官方建議:如果只打算在組件中使用到 title 和 description ,你可以使用關鍵的屬性運用即可
選項中加入 pick,裡面的值就是取得資料中的key值

1
2
3
4
5
6
7
8
<script setup>
const { data: mountain } = await useFetch('/api/mountains/everest', { pick: ['title', 'description'] })
</script>

<template>
<h1>{{ mountain.title }}</h1>
<p>{{ mountain.description }}</p>
</template>

參考資料