作者:吳祐賓
前言
React 19 帶來了許多令人興奮的新功能,例如 Actions, Server Components, Asset Loading 等,可以幫助我們提升開發效率和應用程式效能。
本教學將以新手友善的方式,帶領大家快速入門 React 19,並搭配 esm.sh CDN 快速搭建開發環境,讓你立即體驗 React 最新功能!
附帶說明,本教學只會提及 Client-Side Rendering (CSR) 功能,如果這篇文章迴響不錯,會再另外推出 Server-Side Rendering (SSR) 的教學內容,敬請期待!
準備工作
要開始 React 19 開發,最快速的方式就是使用 esm.sh CDN。它讓我們無需安裝 Node.js 和 npm,就能在瀏覽器中直接使用 React 19。細節可以參閱我之前寫的:我在 React 19 新手入門:CDN + esm.sh 快速上手。
首先,建立一個 HTML 檔案 (例如 index.html),並加入以下程式碼:
<!doctype html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <title>React App with JSX React 19</title> </head> <body class="dx-viewport"> <div id="root"></div> <script type="text/babel" data-type="module"> import React from "https://esm.sh/react@19" import ReactDOMClient from "https://esm.sh/react-dom@19/client" function App(){ return <> <h1>Hello, React 19 with ESM.sh</h1> </> } const root = ReactDOMClient.createRoot(document.getElementById('root')) root.render(<App />) </script> </body> </html>
這個簡單的 HTML 檔案就建立了一個 React 19 開發環境。使用 Babel stand-alone,用來啟動 JSX 即時編譯的能力。
使用 babel 優點是開發習慣移轉到 Build Tool 環境 (Vite, Webpack, Next.js 等) 十分方便,缺點則是所有 class 都必須寫在同一個 html 檔裡。
我還是習慣使用 CDN 做教學範例。現在,你可以直接用瀏覽器打開 index.html,看到 "Hello, React 19 with ESM.sh!" 的訊息,就代表成功了!
React 19 新功能巡禮
接下來,我們將逐一介紹 React 19 的重點新功能,讓你快速掌握 React 最新技術。
Actions:簡化資料流程與狀態管理
在 React 18 之前,處理表單提交或資料更新時,我們需要手動管理 loading 狀態和錯誤處理。
React 19 引入了 Actions (useTranstition),可以更簡潔地處理表單的非同步操作。
簡單的說,React 19 Actions 比較接近資料庫的交易概念,我們拿官方的 18/19 的程式碼來比較,並附上我修改後的程式碼。
<!doctype html> <html> <head> <meta charset="UTF-8" /> <meta http-equiv="X-UA-Compatible" content="IE=edge" /> <meta name="viewport" content="width=device-width, initial-scale=1.0" /> <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script> <title>React App with JSX React 19</title> </head> <body class="dx-viewport"> <div id="root"></div> <script type="text/babel" data-type="module"> import React, {useState, useTransition} from "https://esm.sh/react@19" import ReactDOMClient from "https://esm.sh/react-dom@19/client" // Using pending state from Actions function UpdateName({}) { const [name, setName] = useState(""); const [error, setError] = useState(null); const [isPending, startTransition] = useTransition(); async function updateName(name) { // 模擬異步操作,例如 API 呼叫 return new Promise((resolve) => { setTimeout(() => { if (!name) { resolve("Name cannot be empty."); // 模擬錯誤情況 } else if (name.length > 20) { resolve("Name is too long."); // 模擬另一個錯誤情況 } else { // 在此處添加更新名稱的實際邏輯,例如 API 呼叫 console.log("Name updated to:", name); // 模擬成功情況 resolve(null); // 成功時返回 null 表示沒有錯誤 } }, 1000); // 模擬 1 秒的延遲 }); } const handleSubmit = () => { startTransition(async () => { const error = await updateName(name); if (error) { setError(error); return; } setError("Ok!"); }) }; return ( <div> <input value={name} onChange={(event) => setName(event.target.value)} /> <button onClick={handleSubmit} disabled={isPending}> Update </button> {error && <p>{error}</p>} </div> ); } function App(){ return <> <h1>Hello, React 19 with ESM.sh</h1> <UpdateName /> </> } const root = ReactDOMClient.createRoot(document.getElementById('root')) root.render(<App />) </script> </body> </html>
使用 form 和 useActionState,使程式更簡單
前面的例子是使用 Button 直接送出 request 進行狀態切換。React 19 對 form 也加入了一些 Action。修改後程式碼如下。可以看到 useActionState 內可以自動切換狀態,並且和錯誤機制配合的冾到好處。
<!doctype html>
<html>
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<title>React App with JSX React 19</title>
</head>
<body class="dx-viewport">
<div id="root"></div>
<script type="text/babel" data-type="module">
import React, {useState, useActionState} from "https://esm.sh/react@19"
import ReactDOMClient from "https://esm.sh/react-dom@19/client"
async function updateName(name) {
// 模擬異步操作,例如 API 呼叫
return new Promise((resolve) => {
setTimeout(() => {
if (!name) {
resolve("Name cannot be empty."); // 模擬錯誤情況
} else if (name.length > 20) {
resolve("Name is too long."); // 模擬另一個錯誤情況
}
else {
// 在此處添加更新名稱的實際邏輯,例如 API 呼叫
console.log("Name updated to:", name); // 模擬成功情況
resolve(null); // 成功時返回 null 表示沒有錯誤
}
}, 1000); // 模擬 1 秒的延遲
});
}
// Using <form> Actions and useActionState
function ChangeName({ name, setName }) {
const [error, submitAction, isPending] = useActionState(
async (previousState, formData) => {
const error = await updateName(formData.get("name"));
if (error) {
return error;
}
return null;
},
null,
);
return (
<form action={submitAction}>
<input type="text" name="name" />
<button type="submit" disabled={isPending}>Update</button>
{error && <p>{error}</p>}
</form>
);
}
function App(){
return <>
<h1>Hello, React 19 with ESM.sh</h1>
<ChangeName />
</>
}
const root = ReactDOMClient.createRoot(document.getElementById('root'))
root.render(<App />)
</script>
</body>
</html>
New API: use - 讓 Async Function 回傳 Promise 更融入 React 世界
在 React 19 之前,我們在 Component 裡處理 Async Function 的回傳值時,通常需要 useState, useEffect 搭配 async/await 才能比較好的處理 loading, error, data 狀態。
這在 fetch 資料庫經常會希望有但都要自己來刻的功能。
React 19 引入了 use 這個新的 Hook,讓你在 React Component 裡可以直接 "await" Promise,讓 Async Function 的回傳值可以更自然的融入 React 的世界。
我們來看一個簡單的例子。
// New API: use function fetchData() { console.log('Fetching data...'); return new Promise(resolve => { setTimeout(() => { console.log('Data fetched!'); resolve({ message: "Data from Async Function!" }); }, 1500); // 模擬 1.5 秒的 API 延遲 }); } function DataDisplay() { // 直接 use(Promise) const data = use(fetchData()); return ( <div> <p>Data Display:</p> {data ? <p>{data.message}</p> : <p>Loading data...</p>} </div> ); }
在 DataDisplay 這個 Component 裡,我們定義了一個 fetchData 的 Async Function,這個 Function 模擬了一個 API 呼叫,會在 1.5 秒後 resolve 一個包含 message 的 Object。
重點在 DataDisplay Component 裡,我們可以直接使用 use(fetchData()),use Hook 會處理 fetchData() 回傳的 Promise
Pending 狀態: 在 Promise resolve 之前,Component 會進入 Pending 狀態 (Suspense),你可以看到畫面上顯示 "Loading data..."。
成功狀態: 當 Promise resolve 後,use(fetchData()) 會回傳 Promise 的 resolve 值,也就是 { message: "Data from Async Function!" },Component 重新 render,畫面就會顯示 "Data from Async Function!"。
use 的優點:
- 更簡潔的 Async Function 處理: 不需要再手動管理 loading 狀態,程式碼更簡潔易讀。
- 提升開發體驗: 讓 Async Function 更自然的融入 React Component 的開發流程。
- 搭配 Suspense: 可以和 Suspense Component 搭配使用,讓 Loading 體驗更流暢。
Ref as a prop - Function Component 也可以直接接收 Ref 了!
在 React 19 之前,Function Component 如果需要接收 Ref,必須要透過 forwardRef 這個 API 包裝才能使用。
// React 18 寫法
const MyInput = React.forwardRef((props, ref) => {
return <input placeholder={props.placeholder} ref={ref} />;
})
// React 19 寫法 - Function Component 直接接收 ref prop
function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
React 18 寫法對於 Function Component 來說,多了一層 forwardRef 的包裝,語法上比較囉嗦一點,也讓 Function Component 的程式碼看起來比較複雜。
React 19 簡化了 Function Component Ref 的使用方式。現在,Function Component 可以像 Class Component 一樣,直接接收 ref 這個 Prop 了!
未來 forwardRef 也將棄用,請盡早學會 ref as a prop。
實際案例會像這樣:
// Ref as a prop
function MyInput({placeholder, ref}) {
return <input placeholder={placeholder} ref={ref} />
}
function RefInputComponent() {
const inputRef = useRef(null);
useEffect(() => {
if (inputRef.current) {
console.log('Input Ref:', inputRef.current);
}
}, []);
return (
<div>
<p>Ref as a prop:</p>
<MyInput placeholder="Enter text" ref={inputRef} />
</div>
);
}
總結
好的,React 19 這次更新真的太棒啦!一口氣帶來了 Actions, use Hook, ref as a prop 這些超實用的新功能,每一個都打中開發者的痛點,讓開發 React 應用程式變得更輕鬆、更高效。
總結一下 React 19 這些必學新功能:
- Actions: 告別複雜的表單狀態管理!useTransition 和 useActionState 就像是神隊友,幫你優雅地處理非同步操作, loading 狀態、錯誤處理都變得超簡單,程式碼也更簡潔易讀,真的就像資料庫交易一樣方便!
- use Hook: Async Function 的救星!以前在 Component 裡處理 Promise,總是要 useState, useEffect 寫一堆,現在有了 use,直接 await 就搞定,程式碼瞬間清爽!資料載入 loading 狀態也自動處理,開發體驗直接起飛!
- ref as a prop: Function Component 的 Ref 也太方便了吧!再也不用 forwardRef 包裝了,直接像 Class Component 一樣接收 ref prop 就行,語法更直覺,程式碼也更簡潔,而且聽說 forwardRef 以後要被棄用,這個一定要學起來!
React 19 這些新功能,不只是錦上添花,更是實實在在地提升了開發效率和體驗。無論你是 React 新手還是老手,都非常建議趕快升級到 React 19,體驗這些新功能帶來的魅力!
看完這篇入門教學,是不是覺得 React 19 其實也沒那麼難?趕快動手試試看,用 esm.sh CDN 快速搭建你的 React 19 開發環境
一起擁抱 React 新時代吧! 相信你會愛上 React 19 的!
See also