在前面的文章中,我們學會了如何建立 Command 來處理前端的請求。但隨著應用程式功能越來越豐富,我們常常會遇到一個問題:不同的 Command 之間需要共享資料。
想像一下,如果你的應用程式需要管理資料庫連線池、儲存使用者的登入狀態、或是快取一些常用的資料,你會怎麼做?如果每個 Command 都各自處理這些資料,不僅效率很差,還可能造成資料不一致的問題。
也許你會想:「那我直接用 static mut
全域變數不就好了嗎?」這個想法很自然,但在多執行緒環境下,這樣做其實是很危險的!可能會造成競爭條件(Race Condition)和資料損壞的問題。
對此,Tauri 提供了一個既優雅又安全的解決方案:State 機制。它讓我們可以放心地在不同 Command 之間共享資料,完全不用擔心執行緒安全的問題。
State 機制最棒的地方就是:
在此用一個簡單的計數器為例,讓不同的 Command 都能存取和修改它。
首先,我們需要定義一個結構體來存放狀態資料。為了確保執行緒安全,我們會用 Mutex
來包裝資料:
use std::sync::Mutex;
use tauri::{Builder, Manager, State};
// 定義應用程式狀態結構
#[derive(Default)]
struct AppState {
counter: i32,
}
#[tauri::command]
fn increment_counter(state: State<Mutex<AppState>>) -> i32 {
let mut app_state = state.lock().unwrap();
app_state.counter += 1;
app_state.counter
}
#[tauri::command]
fn get_counter(state: State<Mutex<AppState>>) -> i32 {
let app_state = state.lock().unwrap();
app_state.counter
}
fn main() {
Builder::default()
.setup(|app| {
app.manage(Mutex::new(AppState::default()));
Ok(())
})
.invoke_handler(tauri::generate_handler![
increment_counter,
get_counter
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
Mutex
(Mutual Exclusion,互斥鎖)就像是一個排隊機制。想像你家只有一個廁所,同一時間只能有一個人使用,其他人就要排隊等候。
在程式裡也是一樣的道理:當多個 Command 同時想要存取我們的 counter
資料時,Mutex 確保同一時間只有一個 Command 能進去「使用」,其他的就要乖乖排隊等候。這樣就不會有資料被搞亂的問題了!
fn increment_counter(state: State<Mutex<AppState>>) -> i32
你有沒有注意到,我們的 Command 函數有一個 state
參數,但我們從來沒有手動傳入過?這就是 Tauri 的魔法!
這個機制叫做「依賴注入」:
State<T>
告訴 Tauri:「嘿,我需要這個狀態資料」let mut app_state = state.lock().unwrap();
這行程式碼做了幾件事:
state.lock()
就像是「敲廁所門」,看看現在能不能進去counter
了小提醒:這裡用
unwrap()
是為了讓範例簡潔,實際專案中建議適當處理可能的錯誤情況。
app.manage(Mutex::new(AppState::default()));
這行程式碼的作用是:
AppState::default()
建立一個初始的狀態實例Mutex::new()
用 Mutex 包裝起來,確保執行緒安全app.manage()
把這個狀態註冊到 Tauri 的依賴注入系統中State<Mutex<AppState>>
參數來存取這個狀態現在讓我們看看前端要怎麼跟這些 Command 互動。其實跟之前學的差不多,就是呼叫不同的 Command 來操作共享狀態:
<template>
<div>
<h3>計數器: {{ counter }}</h3>
<button @click="increment">增加</button>
<button @click="refreshCounter">重新整理</button>
</div>
</template>
<script setup>
import { ref, onMounted } from 'vue'
import { invoke } from '@tauri-apps/api/core'
const counter = ref(0)
async function increment() {
counter.value = await invoke('increment_counter')
}
async function refreshCounter() {
counter.value = await invoke('get_counter')
}
onMounted(async () => {
await refreshCounter()
})
</script>
這個範例很簡單:
increment_counter
Commandget_counter
Command 來取得最新的計數值透過 Tauri 的 State 機制,我們輕鬆建立了一個既安全又強大的狀態管理系統。重點回顧:
有了這個基礎,你就能在 Tauri 應用程式中輕鬆處理各種複雜的狀態管理需求了!