Tauri与React的第一个程序
# React 第一个程序
src\App.tsx
文件如下(默认生成的代码),下面详细讲解这个文件。这段代码是一个使用 React 框架和 Tauri 构建的桌面应用的简单前端界面。
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";
function App() {
const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState("");
async function greet() {
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
setGreetMsg(await invoke("greet", { name }));
}
return (
<main className="container">
<h1>Welcome to Tauri + React</h1>
<div className="row">
<a href="https://vite.dev" target="_blank">
<img src="/vite.svg" className="logo vite" alt="Vite logo" />
</a>
<a href="https://tauri.app" target="_blank">
<img src="/tauri.svg" className="logo tauri" alt="Tauri logo" />
</a>
<a href="https://react.dev" target="_blank">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<p>Click on the Tauri, Vite, and React logos to learn more.</p>
<form
className="row"
onSubmit={(e) => {
e.preventDefault();
greet();
}}
>
<input
id="greet-input"
onChange={(e) => setName(e.currentTarget.value)}
placeholder="Enter a name..."
/>
<button type="submit">Greet</button>
</form>
<p>{greetMsg}</p>
</main>
);
}
export default App;
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
48
49
50
51
52
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
48
49
50
51
52
下面我们来逐行分解解释:
# 1. 导入 (Imports)
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import { invoke } from "@tauri-apps/api/core";
import "./App.css";
1
2
3
4
2
3
4
import { useState } from "react";
- 这是从 React 库中导入一个名为
useState
的 "Hook"。Hook 是让你在函数组件里“钩入” React 特性和状态的函数。useState
用于在组件中添加和管理组件的内部状态。
- 这是从 React 库中导入一个名为
import reactLogo from "./assets/react.svg";
- 这行代码导入了位于
./assets/
目录下的react.svg
图片文件。在代码中,reactLogo
将会是一个指向这个图片路径的变量,可以用于在<img>
标签中显示图片。
- 这行代码导入了位于
import { invoke } from "@tauri-apps/api/core";
- 这是 Tauri 框架的核心部分。
invoke
函数是从 Tauri 的 JavaScript API 中导入的。它的作用是调用你在 Rust 后端代码中定义的命令 (command)。这是实现前端和后端通信的关键。
- 这是 Tauri 框架的核心部分。
import "./App.css";
- 这行代码导入了组件的 CSS 样式文件,用于美化界面的外观。
# 2. 组件定义 (Component Definition)
function App() {
// ... 组件内部逻辑和 JSX ...
}
export default App;
1
2
3
4
5
2
3
4
5
function App() { ... }
- 这定义了一个名为
App
的函数式组件。在 React 中,组件是构成用户界面的独立且可复用的代码块。这个App
组件是整个应用的主组件。
- 这定义了一个名为
export default App;
- 这行代码将
App
组件导出,使其可以在其他文件中被导入和使用(通常是在main.jsx
或index.js
中)。
- 这行代码将
# 3. 状态管理 (State Management)
const [greetMsg, setGreetMsg] = useState("");
const [name, setName] = useState("");
1
2
2
- 这里使用了我们之前导入的
useState
Hook 来创建两个状态变量:const [greetMsg, setGreetMsg] = useState("");
:greetMsg
是一个状态变量,用于存储从后端返回的问候消息。它的初始值被设为一个空字符串""
。setGreetMsg
是一个函数,用来更新greetMsg
的值。当这个函数被调用时,React 会重新渲染组件以显示更新后的消息。
const [name, setName] = useState("");
:name
是另一个状态变量,用于存储用户在输入框中输入的名字。它的初始值也是一个空字符串。setName
是用来更新name
值的函数。
# 4. 与后端通信的函数 (Function for Backend Communication)
async function greet() {
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
setGreetMsg(await invoke("greet", { name }));
}
1
2
3
4
2
3
4
async function greet() { ... }
- 这里定义了一个名为
greet
的异步函数。使用async
关键字是因为它内部调用了invoke
,而invoke
是一个返回 Promise 的异步操作。
- 这里定义了一个名为
setGreetMsg(await invoke("greet", { name }));
- 这是整个应用的核心交互逻辑。
invoke("greet", { name })
:这行代码调用了 Tauri 的invoke
函数。- 第一个参数
"greet"
是你在 Rust 后端定义的命令的名称。 - 第二个参数
{ name }
是一个对象,它包含了要传递给后端命令的参数。在这里,它把当前name
状态变量的值传递给了后端。
- 第一个参数
await
:关键字等待invoke
函数完成并返回结果(也就是 Rust 后端greet
命令的返回值)。setGreetMsg(...)
:一旦从后端获取到返回的问候消息,就使用setGreetMsg
函数来更新greetMsg
状态,从而在界面上显示出来。
# 5. 界面渲染 (UI Rendering with JSX)
return (
<main className="container">
{/* ... JSX 内容 ... */}
</main>
);
1
2
3
4
5
2
3
4
5
return (...)
return
语句内部的内容是 JSX (JavaScript XML),它描述了组件的 UI 结构。它看起来很像 HTML。
<main className="container">
- 这是组件的根元素。
<h1>Welcome to Tauri + React</h1>
- 一个一级标题。
- Logos and Links:
<div className="row"> <a href="https://vite.dev" target="_blank"> <img src="/vite.svg" className="logo vite" alt="Vite logo" /> </a> // ... Tauri and React logos </div>
1
2
3
4
5
6- 这部分显示了 Vite、Tauri 和 React 的 Logo,并为它们添加了指向各自官网的链接。
- 表单 (Form):
<form className="row" onSubmit={(e) => { e.preventDefault(); greet(); }} > <input id="greet-input" onChange={(e) => setName(e.currentTarget.value)} placeholder="Enter a name..." /> <button type="submit">Greet</button> </form>
1
2
3
4
5
6
7
8
9
10
11
12
13
14onSubmit={(e) => { ... }}
:当表单被提交时(通过点击按钮或按回车),这个函数会被调用。e.preventDefault();
:阻止表单提交的默认行为(即刷新页面)。greet();
:调用我们前面定义的greet
函数,来向后端发送请求。
<input ... />
:一个输入框。onChange={(e) => setName(e.currentTarget.value)}
:这是一个非常重要的部分。每当输入框的内容发生改变时,它会调用setName
函数,用输入框的当前值来更新name
状态。这实现了输入框和name
状态的绑定。placeholder="Enter a name..."
:输入框中的提示文字。
<button type="submit">Greet</button>
:一个提交按钮。
- 显示问候消息 (Displaying the Greeting Message):
<p>{greetMsg}</p>
1- 这个
<p>
标签用来显示greetMsg
状态变量的内容。最初它是空的,当greet
函数成功从后端获取消息并调用setGreetMsg
更新状态后,新的问候语就会显示在这里。
- 这个
# 总结
这个 App
组件的工作流程如下:
- 渲染界面:显示标题、三个 Logo、一个带输入框和按钮的表单,以及一个用于显示消息的空段落。
- 用户输入:用户在输入框中输入自己的名字。每次输入都会触发
onChange
事件,调用setName
来更新name
状态。 - 提交表单:用户点击 "Greet" 按钮或者按回车键提交表单。
- 调用后端:表单的
onSubmit
事件被触发,它会调用greet
函数。 - 与 Rust 通信:
greet
函数使用 Tauri 的invoke
API 调用 Rust 后端中名为"greet"
的命令,并将当前name
状态作为参数传递过去。 - 接收和更新:
greet
函数等待后端处理并返回一个字符串(例如 "Hello, [name]!")。 - 显示结果:
greet
函数用返回的字符串调用setGreetMsg
,更新greetMsg
状态。React 检测到状态变化,自动重新渲染界面,将新的问候消息显示在<p>
标签中。
# Rust 第一个程序
这是一个典型的 src-tauri/src/lib.rs
或 src-tauri/src/main.rs
文件,是 Tauri 应用的 Rust 入口点。
这段 Rust 代码是 Tauri 应用的后端部分,它与我们之前分析的前端 React 代码协同工作。
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
2
3
4
5
6
7
8
9
10
11
12
13
14
15
我们来逐段解析:
# 1. greet
函数 (The greet
Command)
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
#[tauri::command]
fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
1
2
3
4
5
2
3
4
5
#[tauri::command]
- 这是一个 Rust 的 "属性宏 (attribute macro)"。它告诉 Tauri 编译器,下面的
greet
函数是一个“命令 (Command)”。. - Tauri 会自动生成必要的“粘合代码”,使得这个 Rust 函数可以从 JavaScript 前端通过
invoke
函数来调用。
- 这是一个 Rust 的 "属性宏 (attribute macro)"。它告诉 Tauri 编译器,下面的
fn greet(name: &str) -> String
- 这定义了一个名为
greet
的公共函数。 name: &str
:这个函数接受一个名为name
的参数,它的类型是&str
(一个字符串切片),这是 Rust 中处理字符串的常见高效方式。前端通过invoke("greet", { name: "..." })
传过来的name
值会在这里被接收。-> String
:这个函数会返回一个String
类型的值。这个返回值将被序列化并通过invoke
的 Promise 解析,最终传递回 JavaScript 前端。
- 这定义了一个名为
format!("Hello, {}! You've been greeted from Rust!", name)
- 这是 Rust 的一个内置宏,用于创建格式化的字符串。
- 它会将第一个参数(格式化字符串)中的
{}
占位符替换为后面参数(这里是name
变量)的值。 - 所以,如果前端传来 "React",这个函数就会构造并返回字符串
"Hello, React! You've been greeted from Rust!"
。
简而言之,greet
函数就是前端 React 代码中 invoke("greet", { name })
调用的具体实现。
# 2. run
函数 (The Application Entry Point)
#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.invoke_handler(tauri::generate_handler![greet])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
#[cfg_attr(mobile, tauri::mobile_entry_point)]
- 这是一个条件编译属性。它的意思是:如果编译目标是
mobile
(移动端),那么就应用#[tauri::mobile_entry_point]
这个属性宏。 - 这对于构建跨桌面和移动端的 Tauri 应用至关重要,它为移动平台指定了正确的入口点。
- 这是一个条件编译属性。它的意思是:如果编译目标是
pub fn run()
- 这是应用程序的主入口函数。当你的 Tauri 应用启动时,这个
run
函数会被执行。
- 这是应用程序的主入口函数。当你的 Tauri 应用启动时,这个
tauri::Builder::default()
- 这会创建一个 Tauri 应用的构建器(Builder)实例。 构建器模式允许你用链式调用的方式来配置和初始化你的应用程序。
.plugin(tauri_plugin_opener::init())
- 这行代码注册并初始化了一个名为
tauri-plugin-opener
的插件。 - 这个插件的功能是允许你的应用打开外部链接或系统文件管理器中的文件。 比如,当你在前端点击 Vite 或 Tauri 的 Logo 链接时,就是这个插件在起作用,它会调用系统的默认浏览器来打开该网页。
- 这行代码注册并初始化了一个名为
.invoke_handler(tauri::generate_handler![greet])
- 这是将前端和后端命令连接起来的关键步骤。
invoke_handler
方法用于注册所有你希望从 JavaScript 调用的 Rust 命令。tauri::generate_handler![greet]
是一个宏,它会接收一个或多个你用#[tauri::command]
标记的函数(这里是greet
),并为它们生成一个统一的处理器。 这个处理器会根据前端传来的命令名称(字符串 "greet")来调用相应的 Rust 函数。
.run(tauri::generate_context!())
.run()
是构建器链上的最后一步,它会最终构建并运行应用程序。tauri::generate_context!()
是另一个宏,它会在编译时读取tauri.conf.json
配置文件,并生成一个包含所有应用配置的上下文(Context)对象。 这个上下文对象包含了窗口标题、标识符等所有应用的元数据。
.expect("error while running tauri application")
.run()
方法会返回一个Result
类型。在 Rust 中,Result
表示一个操作可能成功也可能失败。.expect()
是处理Result
的一种简单方式。如果run()
成功,它什么也不做。如果run()
返回一个错误(Error),程序就会 "panic"(恐慌,即崩溃),并显示这里的错误信息。这在开发中很常见,但在生产应用中通常会用更优雅的方式处理错误。
# 代码整体流程
- 当用户执行编译好的 Tauri 应用时,
run
函数被调用。 tauri::Builder
开始构建应用。opener
插件被注册,使得应用具备了打开外部链接的能力。greet
命令通过invoke_handler
被注册,Tauri 知道了有一个名为 "greet" 的命令可以从前端调用。- 应用配置从
tauri.conf.json
文件中加载。 .run()
启动了应用,创建了窗口,并加载了前端的 React 代码。- 此时,应用处于运行状态,等待前端的交互。当用户在 React 界面中输入名字并点击 "Greet" 按钮时,前端的
invoke("greet", ...)
被触发,Tauri 的核心接收到这个调用请求,并将其路由到我们刚刚注册的 Rustgreet
函数,最终将执行结果返回给前端。
上次更新: 2025/08/19, 08:47:47