<Suspense>
<Suspense>
cho phép bạn hiển thị một fallback cho đến khi các thành phần con của nó đã tải xong.
<Suspense fallback={<Loading />}>
<SomeComponent />
</Suspense>
- Tham khảo
- Cách sử dụng
- Hiển thị fallback trong khi nội dung đang tải
- Tiết lộ nội dung cùng nhau đồng thời
- Tiết lộ nội dung lồng nhau khi nó tải
- Hiển thị nội dung cũ trong khi nội dung mới đang tải
- Ngăn chặn việc ẩn nội dung đã hiển thị
- Cho biết rằng một Transition đang diễn ra
- Đặt lại ranh giới Suspense khi điều hướng
- Cung cấp fallback cho các lỗi máy chủ và nội dung chỉ dành cho máy khách
- Khắc phục sự cố
- HTML máy chủ sẽ bao gồm chỉ báo tải. Nó sẽ được thay thế bằng thành phần
Chat
trên máy khách.
Tham khảo
<Suspense>
Props
children
: Giao diện người dùng thực tế mà bạn định hiển thị. Nếuchildren
tạm ngưng trong khi hiển thị, ranh giới Suspense sẽ chuyển sang hiển thịfallback
.fallback
: Một giao diện người dùng thay thế để hiển thị thay cho giao diện người dùng thực tế nếu nó chưa tải xong. Bất kỳ nút React hợp lệ nào đều được chấp nhận, mặc dù trên thực tế, fallback là một chế độ xem giữ chỗ nhẹ, chẳng hạn như trình quay tải hoặc bộ xương. Suspense sẽ tự động chuyển sangfallback
khichildren
tạm ngưng và quay lạichildren
khi dữ liệu đã sẵn sàng. Nếufallback
tạm ngưng trong khi hiển thị, nó sẽ kích hoạt ranh giới Suspense cha gần nhất.
Lưu ý
- React không giữ lại bất kỳ trạng thái nào cho các lần hiển thị bị tạm ngưng trước khi chúng có thể gắn kết lần đầu tiên. Khi thành phần đã tải, React sẽ thử lại hiển thị cây bị tạm ngưng từ đầu.
- Nếu Suspense đang hiển thị nội dung cho cây, nhưng sau đó nó lại bị tạm ngưng, thì
fallback
sẽ được hiển thị lại trừ khi bản cập nhật gây ra nó được gây ra bởistartTransition
hoặcuseDeferredValue
. - Nếu React cần ẩn nội dung đã hiển thị vì nó bị tạm ngưng lại, nó sẽ dọn dẹp layout Effects trong cây nội dung. Khi nội dung đã sẵn sàng để hiển thị lại, React sẽ kích hoạt lại layout Effects. Điều này đảm bảo rằng Effects đo bố cục DOM không cố gắng thực hiện điều này trong khi nội dung bị ẩn.
- React bao gồm các tối ưu hóa ẩn bên dưới như Kết xuất máy chủ phát trực tuyến và Hydrat hóa có chọn lọc được tích hợp với Suspense. Đọc tổng quan về kiến trúc và xem bài nói chuyện kỹ thuật để tìm hiểu thêm.
Cách sử dụng
Hiển thị fallback trong khi nội dung đang tải
Bạn có thể bọc bất kỳ phần nào của ứng dụng của bạn bằng một ranh giới Suspense:
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
React sẽ hiển thị fallback tải của bạn cho đến khi tất cả code và dữ liệu cần thiết bởi các thành phần con đã được tải xong.
Trong ví dụ dưới đây, thành phần Albums
tạm ngưng trong khi tìm nạp danh sách album. Cho đến khi nó sẵn sàng hiển thị, React chuyển ranh giới Suspense gần nhất bên trên để hiển thị fallback — thành phần Loading
của bạn. Sau đó, khi dữ liệu được tải, React ẩn fallback Loading
và hiển thị thành phần Albums
với dữ liệu.
import { Suspense } from 'react'; import Albums from './Albums.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<Loading />}> <Albums artistId={artist.id} /> </Suspense> </> ); } function Loading() { return <h2>🌀 Loading...</h2>; }
Tiết lộ nội dung cùng nhau đồng thời
Theo mặc định, toàn bộ cây bên trong Suspense được coi là một đơn vị duy nhất. Ví dụ: ngay cả khi chỉ một trong số các component này tạm ngưng để chờ một số dữ liệu, thì tất cả chúng cùng nhau sẽ được thay thế bằng chỉ báo tải:
<Suspense fallback={<Loading />}>
<Biography />
<Panel>
<Albums />
</Panel>
</Suspense>
Sau đó, sau khi tất cả chúng đã sẵn sàng để hiển thị, chúng sẽ xuất hiện cùng nhau ngay lập tức.
Trong ví dụ dưới đây, cả Biography
và Albums
đều tìm nạp một số dữ liệu. Tuy nhiên, vì chúng được nhóm dưới một ranh giới Suspense duy nhất, các thành phần này luôn “hiện ra” cùng nhau đồng thời.
import { Suspense } from 'react'; import Albums from './Albums.js'; import Biography from './Biography.js'; import Panel from './Panel.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<Loading />}> <Biography artistId={artist.id} /> <Panel> <Albums artistId={artist.id} /> </Panel> </Suspense> </> ); } function Loading() { return <h2>🌀 Loading...</h2>; }
Các component tải dữ liệu không cần phải là con trực tiếp của ranh giới Suspense. Ví dụ: bạn có thể di chuyển Biography
và Albums
vào một component Details
mới. Điều này không thay đổi hành vi. Biography
và Albums
dùng chung ranh giới Suspense cha gần nhất, vì vậy việc hiển thị của chúng được phối hợp cùng nhau.
<Suspense fallback={<Loading />}>
<Details artistId={artist.id} />
</Suspense>
function Details({ artistId }) {
return (
<>
<Biography artistId={artistId} />
<Panel>
<Albums artistId={artistId} />
</Panel>
</>
);
}
<Suspense fallback={<Loading />}>
<Details artistId={artist.id} />
</Suspense>
function Details({ artistId }) {
return (
<>
<Biography artistId={artistId} />
<Panel>
<Albums artistId={artistId} />
</Panel>
</>
);
}
Tiết lộ nội dung lồng nhau khi nó tải
Khi một thành phần tạm ngưng, thành phần Suspense cha gần nhất sẽ hiển thị fallback. Điều này cho phép bạn lồng nhiều thành phần Suspense để tạo ra một chuỗi tải. Fallback của mỗi ranh giới Suspense sẽ được điền vào khi cấp nội dung tiếp theo có sẵn. Ví dụ: bạn có thể cung cấp cho danh sách album fallback riêng:
<Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Panel>
<Albums />
</Panel>
</Suspense>
</Suspense>
Với thay đổi này, việc hiển thị Biography
không cần phải “chờ” Albums
tải.
Trình tự sẽ là:
- Nếu
Biography
chưa tải xong,BigSpinner
sẽ được hiển thị thay cho toàn bộ vùng nội dung. - Khi
Biography
tải xong,BigSpinner
được thay thế bằng nội dung. - Nếu
Albums
chưa tải xong,AlbumsGlimmer
sẽ được hiển thị thay choAlbums
vàPanel
cha của nó. - Cuối cùng, khi
Albums
tải xong, nó sẽ thay thếAlbumsGlimmer
.
import { Suspense } from 'react'; import Albums from './Albums.js'; import Biography from './Biography.js'; import Panel from './Panel.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<BigSpinner />}> <Biography artistId={artist.id} /> <Suspense fallback={<AlbumsGlimmer />}> <Panel> <Albums artistId={artist.id} /> </Panel> </Suspense> </Suspense> </> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; } function AlbumsGlimmer() { return ( <div className="glimmer-panel"> <div className="glimmer-line" /> <div className="glimmer-line" /> <div className="glimmer-line" /> </div> ); }
Các ranh giới Suspense cho phép bạn điều phối những phần nào của giao diện người dùng của bạn sẽ luôn “hiển thị” cùng nhau đồng thời và những phần nào sẽ dần dần tiết lộ thêm nội dung theo một chuỗi các trạng thái tải. Bạn có thể thêm, di chuyển hoặc xóa các ranh giới Suspense ở bất kỳ đâu trong cây mà không ảnh hưởng đến hành vi của phần còn lại của ứng dụng của bạn.
Đừng đặt một ranh giới Suspense xung quanh mọi thành phần. Các ranh giới Suspense không nên chi tiết hơn trình tự tải mà bạn muốn người dùng trải nghiệm. Nếu bạn làm việc với một nhà thiết kế, hãy hỏi họ nơi đặt các trạng thái tải—có khả năng là họ đã đưa chúng vào wireframe thiết kế của họ.
<Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Panel>
<Albums />
</Panel>
</Suspense>
</Suspense>
Với thay đổi này, việc hiển thị Biography
không cần phải “chờ” Albums
tải.
Trình tự sẽ là:
- Nếu
Biography
chưa tải xong,BigSpinner
sẽ được hiển thị thay cho toàn bộ vùng nội dung. - Khi
Biography
tải xong,BigSpinner
được thay thế bằng nội dung. - Nếu
Albums
chưa tải xong,AlbumsGlimmer
sẽ được hiển thị thay choAlbums
vàPanel
cha của nó. - Cuối cùng, khi
Albums
tải xong, nó sẽ thay thếAlbumsGlimmer
.
import { Suspense } from 'react'; import Albums from './Albums.js'; import Biography from './Biography.js'; import Panel from './Panel.js'; export default function ArtistPage({ artist }) { return ( <> <h1>{artist.name}</h1> <Suspense fallback={<BigSpinner />}> <Biography artistId={artist.id} /> <Suspense fallback={<AlbumsGlimmer />}> <Panel> <Albums artistId={artist.id} /> </Panel> </Suspense> </Suspense> </> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; } function AlbumsGlimmer() { return ( <div className="glimmer-panel"> <div className="glimmer-line" /> <div className="glimmer-line" /> <div className="glimmer-line" /> </div> ); }
Các ranh giới Suspense cho phép bạn điều phối những phần nào của giao diện người dùng của bạn sẽ luôn “hiển thị” cùng nhau đồng thời và những phần nào sẽ dần dần tiết lộ thêm nội dung theo một chuỗi các trạng thái tải. Bạn có thể thêm, di chuyển hoặc xóa các ranh giới Suspense ở bất kỳ đâu trong cây mà không ảnh hưởng đến hành vi của phần còn lại của ứng dụng của bạn.
Đừng đặt một ranh giới Suspense xung quanh mọi thành phần. Các ranh giới Suspense không nên chi tiết hơn trình tự tải mà bạn muốn người dùng trải nghiệm. Nếu bạn làm việc với một nhà thiết kế, hãy hỏi họ nơi đặt các trạng thái tải—có khả năng là họ đã đưa chúng vào wireframe thiết kế của họ.
Hiển thị nội dung cũ trong khi nội dung mới đang tải
Trong ví dụ này, thành phần SearchResults
tạm ngưng trong khi tìm nạp kết quả tìm kiếm. Nhập "a"
, đợi kết quả và sau đó chỉnh sửa thành "ab"
. Các kết quả cho "a"
sẽ được thay thế bằng fallback tải.
import { Suspense, useState } from 'react'; import SearchResults from './SearchResults.js'; export default function App() { const [query, setQuery] = useState(''); return ( <> <label> Search albums: <input value={query} onChange={e => setQuery(e.target.value)} /> </label> <Suspense fallback={<h2>Loading...</h2>}> <SearchResults query={query} /> </Suspense> </> ); }
Một mẫu giao diện người dùng thay thế phổ biến là hoãn lại việc cập nhật danh sách và tiếp tục hiển thị các kết quả trước đó cho đến khi các kết quả mới sẵn sàng. Hook useDeferredValue
cho phép bạn chuyển một phiên bản hoãn lại của truy vấn xuống:
export default function App() {
const [query, setQuery] = useState('');
const deferredQuery = useDeferredValue(query);
return (
<>
<label>
Search albums:
<input value={query} onChange={e => setQuery(e.target.value)} />
</label>
<Suspense fallback={<h2>Loading...</h2>}>
<SearchResults query={deferredQuery} />
</Suspense>
</>
);
}
query
sẽ cập nhật ngay lập tức, vì vậy đầu vào sẽ hiển thị giá trị mới. Tuy nhiên, deferredQuery
sẽ giữ giá trị trước đó cho đến khi dữ liệu được tải, vì vậy SearchResults
sẽ hiển thị kết quả cũ trong một khoảng thời gian.
Để làm cho nó rõ ràng hơn với người dùng, bạn có thể thêm một chỉ báo trực quan khi danh sách kết quả cũ được hiển thị:
<div style={{
opacity: query !== deferredQuery ? 0.5 : 1
}}>
<SearchResults query={deferredQuery} />
</div>
Nhập "a"
trong ví dụ bên dưới, đợi kết quả tải và sau đó chỉnh sửa đầu vào thành "ab"
. Lưu ý rằng thay vì fallback của Suspense, bây giờ bạn thấy danh sách kết quả cũ bị làm mờ cho đến khi các kết quả mới được tải:
<div style={{
opacity: query !== deferredQuery ? 0.5 : 1
}}>
<SearchResults query={deferredQuery} />
</div>
Nhập "a"
trong ví dụ bên dưới, đợi kết quả tải và sau đó chỉnh sửa đầu vào thành "ab"
. Lưu ý rằng thay vì fallback của Suspense, bây giờ bạn thấy danh sách kết quả cũ bị làm mờ cho đến khi các kết quả mới được tải:
import { Suspense, useState, useDeferredValue } from 'react'; import SearchResults from './SearchResults.js'; export default function App() { const [query, setQuery] = useState(''); const deferredQuery = useDeferredValue(query); const isStale = query !== deferredQuery; return ( <> <label> Search albums: <input value={query} onChange={e => setQuery(e.target.value)} /> </label> <Suspense fallback={<h2>Loading...</h2>}> <div style={{ opacity: isStale ? 0.5 : 1 }}> <SearchResults query={deferredQuery} /> </div> </Suspense> </> ); }
Ngăn chặn việc ẩn nội dung đã hiển thị
Khi một thành phần tạm ngưng, ranh giới Suspense gần nhất sẽ chuyển sang hiển thị fallback. Điều này có thể dẫn đến trải nghiệm người dùng khó chịu nếu nó đã hiển thị một số nội dung. Hãy thử nhấn nút này:
import { Suspense, useState } from 'react'; import IndexPage from './IndexPage.js'; import ArtistPage from './ArtistPage.js'; import Layout from './Layout.js'; export default function App() { return ( <Suspense fallback={<BigSpinner />}> <Router /> </Suspense> ); } function Router() { const [page, setPage] = useState('/'); function navigate(url) { setPage(url); } let content; if (page === '/') { content = ( <IndexPage navigate={navigate} /> ); } else if (page === '/the-beatles') { content = ( <ArtistPage artist={{ id: 'the-beatles', name: 'The Beatles', }} /> ); } return ( <Layout> {content} </Layout> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; }
Khi bạn nhấn nút, thành phần Router
đã kết xuất ArtistPage
thay vì IndexPage
. Một thành phần bên trong ArtistPage
tạm ngưng, vì vậy ranh giới Suspense gần nhất bắt đầu hiển thị fallback. Ranh giới Suspense gần nhất ở gần gốc, vì vậy toàn bộ bố cục trang web đã được thay thế bằng BigSpinner
.
Để ngăn điều này, bạn có thể đánh dấu bản cập nhật trạng thái điều hướng là một Transition với startTransition
:
function Router() {
const [page, setPage] = useState('/');
function navigate(url) {
startTransition(() => {
setPage(url);
});
}
// ...
Điều này cho React biết rằng quá trình chuyển đổi trạng thái không khẩn cấp và tốt hơn là tiếp tục hiển thị trang trước thay vì ẩn bất kỳ nội dung nào đã hiển thị. Bây giờ, việc nhấp vào nút sẽ “chờ” Biography
tải:
import { Suspense, startTransition, useState } from 'react'; import IndexPage from './IndexPage.js'; import ArtistPage from './ArtistPage.js'; import Layout from './Layout.js'; export default function App() { return ( <Suspense fallback={<BigSpinner />}> <Router /> </Suspense> ); } function Router() { const [page, setPage] = useState('/'); function navigate(url) { startTransition(() => { setPage(url); }); } let content; if (page === '/') { content = ( <IndexPage navigate={navigate} /> ); } else if (page === '/the-beatles') { content = ( <ArtistPage artist={{ id: 'the-beatles', name: 'The Beatles', }} /> ); } return ( <Layout> {content} </Layout> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; }
Một Transition không đợi tất cả nội dung tải. Nó chỉ đợi đủ lâu để tránh ẩn nội dung đã hiển thị. Ví dụ: Layout
của trang web đã được hiển thị, vì vậy sẽ rất tệ nếu ẩn nó sau một spinner tải. Tuy nhiên, ranh giới Suspense
lồng nhau xung quanh Albums
là mới, vì vậy Transition không đợi nó.
Cho biết rằng một Transition đang diễn ra
Trong ví dụ trên, khi bạn nhấp vào nút, không có dấu hiệu trực quan nào cho thấy một điều hướng đang được tiến hành. Để thêm một chỉ báo, bạn có thể thay thế startTransition
bằng useTransition
, cái mà cung cấp cho bạn một giá trị boolean isPending
. Trong ví dụ dưới đây, nó được sử dụng để thay đổi kiểu tiêu đề trang web trong khi một Transition đang diễn ra:
import { Suspense, useState, useTransition } from 'react'; import IndexPage from './IndexPage.js'; import ArtistPage from './ArtistPage.js'; import Layout from './Layout.js'; export default function App() { return ( <Suspense fallback={<BigSpinner />}> <Router /> </Suspense> ); } function Router() { const [page, setPage] = useState('/'); const [isPending, startTransition] = useTransition(); function navigate(url) { startTransition(() => { setPage(url); }); } let content; if (page === '/') { content = ( <IndexPage navigate={navigate} /> ); } else if (page === '/the-beatles') { content = ( <ArtistPage artist={{ id: 'the-beatles', name: 'The Beatles', }} /> ); } return ( <Layout isPending={isPending}> {content} </Layout> ); } function BigSpinner() { return <h2>🌀 Loading...</h2>; }
Đặt lại ranh giới Suspense khi điều hướng
Trong quá trình Transition, React sẽ tránh ẩn nội dung đã hiển thị. Tuy nhiên, nếu bạn điều hướng đến một tuyến đường có các tham số khác nhau, bạn có thể muốn cho React biết đó là nội dung khác. Bạn có thể thể hiện điều này bằng một key
:
<ProfilePage key={queryParams.id} />
Hãy tưởng tượng bạn đang điều hướng trong trang hồ sơ của người dùng và một cái gì đó tạm ngưng. Nếu bản cập nhật đó được gói trong một Transition, nó sẽ không kích hoạt fallback cho nội dung đã hiển thị. Đó là hành vi mong đợi.
Tuy nhiên, bây giờ hãy tưởng tượng bạn đang điều hướng giữa hai hồ sơ người dùng khác nhau. Trong trường hợp đó, việc hiển thị fallback sẽ có ý nghĩa. Ví dụ: dòng thời gian của một người dùng là nội dung khác so với dòng thời gian của một người dùng khác. Bằng cách chỉ định một key
, bạn đảm bảo rằng React coi hồ sơ của những người dùng khác nhau là các thành phần khác nhau và đặt lại các ranh giới Suspense trong quá trình điều hướng. Các bộ định tuyến tích hợp Suspense sẽ tự động thực hiện điều này.
Cung cấp fallback cho các lỗi máy chủ và nội dung chỉ dành cho máy khách
Nếu bạn sử dụng một trong các API kết xuất máy chủ phát trực tuyến (hoặc một framework dựa trên chúng), React cũng sẽ sử dụng các ranh giới <Suspense>
của bạn để xử lý các lỗi trên máy chủ. Nếu một thành phần đưa ra lỗi trên máy chủ, React sẽ không hủy bỏ quá trình kết xuất máy chủ. Thay vào đó, nó sẽ tìm thành phần <Suspense>
gần nhất ở trên nó và bao gồm fallback của nó (chẳng hạn như một spinner) vào HTML máy chủ đã tạo. Người dùng sẽ thấy một spinner lúc đầu.
Trên máy khách, React sẽ cố gắng kết xuất lại thành phần tương tự. Nếu nó cũng gây ra lỗi trên máy khách, React sẽ đưa ra lỗi và hiển thị ranh giới lỗi gần nhất. Tuy nhiên, nếu nó không gây ra lỗi trên máy khách, React sẽ không hiển thị lỗi cho người dùng vì nội dung cuối cùng đã được hiển thị thành công.
Bạn có thể sử dụng điều này để chọn không kết xuất một số thành phần trên máy chủ. Để thực hiện việc này, hãy đưa ra một lỗi trong môi trường máy chủ và sau đó gói chúng trong một ranh giới <Suspense>
để thay thế HTML của chúng bằng các fallback:
<Suspense fallback={<Loading />}>
<Chat />
</Suspense>
function Chat() {
if (typeof window === 'undefined') {
throw Error('Chat should only render on the client.');
}
// ...
}
HTML máy chủ sẽ bao gồm chỉ báo tải. Nó sẽ được thay thế bằng thành phần Chat
trên máy khách.
Khắc phục sự cố
Làm cách nào để ngăn giao diện người dùng bị thay thế bằng fallback trong quá trình cập nhật?
Việc thay thế giao diện người dùng hiển thị bằng fallback tạo ra trải nghiệm người dùng khó chịu. Điều này có thể xảy ra khi một bản cập nhật khiến một thành phần tạm ngưng và ranh giới Suspense gần nhất đã hiển thị nội dung cho người dùng.
Để ngăn điều này xảy ra, hãy đánh dấu bản cập nhật là không khẩn cấp bằng cách sử dụng startTransition
. Trong quá trình Transition, React sẽ đợi cho đến khi đủ dữ liệu được tải để ngăn chặn fallback không mong muốn xuất hiện:
function handleNextPageClick() {
// Nếu bản cập nhật này tạm ngưng, đừng ẩn nội dung đã hiển thị
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
Điều này sẽ tránh việc ẩn nội dung hiện có. Tuy nhiên, bất kỳ ranh giới Suspense
mới được hiển thị nào vẫn sẽ hiển thị ngay lập tức các fallback để tránh chặn giao diện người dùng và cho phép người dùng xem nội dung khi nó có sẵn.
React sẽ chỉ ngăn chặn các fallback không mong muốn trong quá trình cập nhật không khẩn cấp. Nó sẽ không trì hoãn việc hiển thị nếu đó là kết quả của một bản cập nhật khẩn cấp. Bạn phải chọn tham gia bằng một API như startTransition
hoặc useDeferredValue
.
Nếu bộ định tuyến của bạn được tích hợp với Suspense, nó sẽ tự động gói các bản cập nhật của nó vào startTransition
.
function handleNextPageClick() {
// If this update suspends, don't hide the already displayed content
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
Điều này sẽ tránh việc ẩn nội dung hiện có. Tuy nhiên, bất kỳ ranh giới Suspense
mới được hiển thị nào vẫn sẽ hiển thị ngay lập tức các fallback để tránh chặn giao diện người dùng và cho phép người dùng xem nội dung khi nó có sẵn.
React sẽ chỉ ngăn chặn các fallback không mong muốn trong quá trình cập nhật không khẩn cấp. Nó sẽ không trì hoãn việc hiển thị nếu đó là kết quả của một bản cập nhật khẩn cấp. Bạn phải chọn tham gia bằng một API như startTransition
hoặc useDeferredValue
.
Nếu bộ định tuyến của bạn được tích hợp với Suspense, nó sẽ tự động gói các bản cập nhật của nó vào startTransition
.
<Suspense fallback={<Loading />}>
<Chat />
</Suspense>
function Chat() {
if (typeof window === 'undefined') {
throw Error('Chat should only render on the client.');
}
// ...
}
HTML máy chủ sẽ bao gồm chỉ báo tải. Nó sẽ được thay thế bằng thành phần Chat
trên máy khách.
function handleNextPageClick() {
// If this update suspends, don't hide the already displayed content
startTransition(() => {
setCurrentPage(currentPage + 1);
});
}
Điều này sẽ tránh việc ẩn nội dung hiện có. Tuy nhiên, bất kỳ ranh giới Suspense
mới được hiển thị nào vẫn sẽ hiển thị ngay lập tức các fallback để tránh chặn giao diện người dùng và cho phép người dùng xem nội dung khi nó có sẵn.
React sẽ chỉ ngăn chặn các fallback không mong muốn trong quá trình cập nhật không khẩn cấp. Nó sẽ không trì hoãn việc hiển thị nếu đó là kết quả của một bản cập nhật khẩn cấp. Bạn phải chọn tham gia bằng một API như startTransition
hoặc useDeferredValue
.
Nếu bộ định tuyến của bạn được tích hợp với Suspense, nó sẽ tự động gói các bản cập nhật của nó vào startTransition
.