React 19 筆記:新 api 與 pros 功能篇
提醒:此篇筆記整理了 React 19 Beta 中關於 api 與 props 的改動,但不是一份 100% 詳盡的翻譯與解說文,我只記錄了自認需要關注的內容。如果你想了解 React 19 預計要提供的所有改動,請務必閱讀官方文件。
use
可直接讀取 Promise / React context 的內容,但無法讀取在渲染時產生的 Promise(does not support promises created in render)。
讀取 Promise:
import { use } from 'react';
function Comments({ commentsPromise }) {
// `use` will suspend until the promise resolves.
const comments = use(commentsPromise);
return comments.map((comment) => <p key={comment.id}>{comment}</p>);
}
function Page({ commentsPromise }) {
// When `use` suspends in Comments,
// this Suspense boundary will be shown.
return (
<Suspense fallback={<div>Loading...</div>}>
<Comments commentsPromise={commentsPromise} />
</Suspense>
);
}
讀取 Context:
import { use } from 'react';
import ThemeContext from './ThemeContext';
function Heading({ children }) {
if (children == null) {
return null;
}
// This would not work with useContext
// because of the early return.
const theme = use(ThemeContext);
return <h1 style={{ color: theme.color }}>{children}</h1>;
}
注意事項:
- 此 api 可以根據條件決定是否被呼叫(
use
can be called conditionally),也可以在迴圈中使用 - 此 api 只能在 hook 或元件中被呼叫
- 在透過
use
讀取 Promise 內容時,需注意該 Promise 如何處理錯誤情境。會拋錯的話,可以搭配套件react-error-boundary
的ErrorBoundary
來顯示錯誤訊息。也可考慮對 Promise 加上.catch()
來應對,參考官方範例
ref
相關改動
可直接透過 props
傳遞
在 React 19 後,可直接透過 props
傳遞 ref
,不需要再搭配 forwardRef
了。且未來 forwardRef
會被標記為待移除(we will deprecate and remove forwardRef
)。
// before
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
return <input placeholder={placeholder} ref={ref} />;
});
// after
function MyInput({ placeholder, ref }) {
return <input placeholder={placeholder} ref={ref} />;
}
可執行 cleanup function
當元件要從畫面上被卸除時,React 會執行 ref 中的被回傳的 cleanup 功能。如以下範例:
<input
ref={(ref) => {
// do something when ref created
return () => {
// do something when component unmounts
};
}}
/>
<Context.Provider>
簡化為 <Context>
如標題以及以下範例所示,語法從原本的 <ThemeContext.Provider>
簡化為 <ThemeContext>
。
const ThemeContext = createContext('');
function App({ children }) {
return <ThemeContext value="dark">{children}</ThemeContext>;
}
支援文件 metadata
當 React 渲染包含 metadata 的元件時,這些 meta tag 會被提升(hoist)至 HTML 文件的 <head>
中。
function BlogPost({ post }) {
return (
<article>
<h1>{post.title}</h1>
<title>{post.title}</title>
{/* support document metadata */}
<meta name="author" content="Josh" />
<link rel="author" href="https://twitter.com/joshcstory/" />
<meta name="keywords" content={post.keywords} />
{...}
</article>
);
}
<link>
支援樣式權重排序
透過參數 precedence
可指定樣式的載入順序。比如以下範例中的樣式,在 HTML 文件中的順序從上到下會是 foo
>> baz
>> bar
:
function ComponentOne() {
return (
<Suspense fallback="loading...">
<link rel="stylesheet" href="foo" precedence="default" />
<link rel="stylesheet" href="bar" precedence="high" />
<article class="foo-class bar-class"></article>
{...}
</Suspense>
);
}
function ComponentTwo() {
return (
<div>
<p>{...}</p>
<link rel="stylesheet" href="baz" precedence="default" />
</div>
);
}
另外,即使在整個 App 多處重複載入帶有樣式表的元件,該樣式表在 HTML 文件中也只會出現一次(React will only include the stylesheet once in the document)。
<script>
支援 async
邏輯與上方透過 <link>
載入樣式類似——一個包含 <script>
的元件即使在整個 App 中出現多次,React 也只會在 HTML 中嵌入一次標籤。
支援外部資源預載
react-dom
追加數種可以預先載入資源的 api:
import { prefetchDNS, preconnect, preload, preinit } from 'react-dom';
function MyComponent() {
preinit('https://.../path/to/some/script.js', { as: 'script' }); // loads and executes this script eagerly
preload('https://.../path/to/font.woff', { as: 'font' }); // preloads this font
preload('https://.../path/to/stylesheet.css', { as: 'style' }); // preloads this stylesheet
prefetchDNS('https://...'); // when you may not actually request anything from this host
preconnect('https://...'); // when you will request something but aren't sure what
}
上方元件最終會渲染出以下結果:
<!-- the above would result in the following DOM/HTML -->
<html>
<head>
<!-- links/scripts are prioritized by their utility to early loading, not call order -->
<link rel="prefetch-dns" href="https://..." />
<link rel="preconnect" href="https://..." />
<link rel="preload" as="font" href="https://.../path/to/font.woff" />
<link rel="preload" as="style" href="https://.../path/to/stylesheet.css" />
<script async="" src="https://.../path/to/some/script.js"></script>
</head>
<body>
...
</body>
</html>
注意事項:外部資源實際渲染出來的順序是根據其「功能」而非「在元件中被呼叫的順序」決定。