diff --git a/src/content/reference/react/useSyncExternalStore.md b/src/content/reference/react/useSyncExternalStore.md index ebaf0987b..d2476844f 100644 --- a/src/content/reference/react/useSyncExternalStore.md +++ b/src/content/reference/react/useSyncExternalStore.md @@ -4,7 +4,7 @@ title: useSyncExternalStore -`useSyncExternalStore` is a React Hook that lets you subscribe to an external store. +`useSyncExternalStore` là một React Hook cho phép bạn đăng ký vào một external store. ```js const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?) @@ -16,11 +16,11 @@ const snapshot = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot? --- -## Reference {/*reference*/} +## Tham khảo {/*reference*/} ### `useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot?)` {/*usesyncexternalstore*/} -Call `useSyncExternalStore` at the top level of your component to read a value from an external data store. +Gọi `useSyncExternalStore` ở cấp cao nhất của component của bạn để đọc một giá trị từ một cửa hàng dữ liệu bên ngoài. ```js import { useSyncExternalStore } from 'react'; @@ -32,36 +32,36 @@ function TodosApp() { } ``` -It returns the snapshot of the data in the store. You need to pass two functions as arguments: +Nó trả về ảnh chụp(snapshot) của dữ liệu trong store. Bạn cần truyền hai hàm làm đối số: -1. The `subscribe` function should subscribe to the store and return a function that unsubscribes. -2. The `getSnapshot` function should read a snapshot of the data from the store. +1. Hàm `subscribe` nên đăng ký vào store và trả về một hàm có chức năng hủy đăng ký. +2. Hàm `getSnapshot` nên đọc một ảnh chụp(snapshot) dữ liệu từ cửa hàng. -[See more examples below.](#usage) +[Xem thêm các ví dụ phía dưới.](#usage) -#### Parameters {/*parameters*/} +#### Các tham số(Parameters) {/*parameters*/} -* `subscribe`: A function that takes a single `callback` argument and subscribes it to the store. When the store changes, it should invoke the provided `callback`. This will cause the component to re-render. The `subscribe` function should return a function that cleans up the subscription. +* `subscribe`: Một hàm nhận một đối số `callback` duy nhất và đăng ký nó với store. Khi store thay đổi, nó nên gọi hàm `callback` được cung cấp. Điều này sẽ khiến cho component được render lại. Hàm `subscribe` nên trả về một hàm dùng để dọn dẹp đăng ký(subscription). -* `getSnapshot`: A function that returns a snapshot of the data in the store that's needed by the component. While the store has not changed, repeated calls to `getSnapshot` must return the same value. If the store changes and the returned value is different (as compared by [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), React re-renders the component. +* `getSnapshot`: Một hàm trả về ảnh chụp(snapshot) của dữ liệu trong store mà component cần. Trong khi store không thay đổi, các lời gọi lại tới `getSnapshot` phải trả về cùng một giá trị. Nếu store thay đổi và giá trị trả về khác nhau (được so sánh bởi [`Object.is`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is)), React sẽ render lại component. -* **optional** `getServerSnapshot`: A function that returns the initial snapshot of the data in the store. It will be used only during server rendering and during hydration of server-rendered content on the client. The server snapshot must be the same between the client and the server, and is usually serialized and passed from the server to the client. If you omit this argument, rendering the component on the server will throw an error. +* **tùy chọn** `getServerSnapshot`: Một hàm trả về ảnh chụp(snapshot) ban đầu của dữ liệu trong store. Nó chỉ được sử dụng trong quá trình render phía server và trong quá trình hydrate hóa nội dung được được render bởi server trên client. Ảnh chụp(snapshot) ở server phải giống nhau giữa client và server, và thường được tuần tự hóa và truyền từ server đến client. Nếu bạn bỏ qua đối số này, việc render component phía server sẽ báo lỗi. -#### Returns {/*returns*/} +#### Trả về {/*returns*/} -The current snapshot of the store which you can use in your rendering logic. +Ảnh chụp(snapshot) dữ liệu hiện tại của store mà bạn có thể sử dụng trong logic render của mình. -#### Caveats {/*caveats*/} +#### Cảnh báo {/*caveats*/} -* The store snapshot returned by `getSnapshot` must be immutable. If the underlying store has mutable data, return a new immutable snapshot if the data has changed. Otherwise, return a cached last snapshot. +* Ảnh chụp(snapshot) của store trả về bởi `getSnapshot` phải là bất biến(immutable). Nếu dữ liệu trong store cơ bản là mutable, trả về một snapshot mới không thể thay đổi(immutable) nếu dữ liệu đã thay đổi. Nếu không, trả về một bản chụp đã được lưu vào bộ nhớ cache. -* If a different `subscribe` function is passed during a re-render, React will re-subscribe to the store using the newly passed `subscribe` function. You can prevent this by declaring `subscribe` outside the component. +* Nếu một hàm `subscribe` khác được truyền vào lúc re-render, React sẽ đăng ký lại với store hàm `subscribe` mới được truyền vào. Bạn có thể ngăn chặn điều này bằng cách khai báp hàm `subscribe` bên ngoài component. -* If the store is mutated during a [non-blocking transition update](/reference/react/useTransition), React will fall back to performing that update as blocking. Specifically, for every transition update, React will call `getSnapshot` a second time just before applying changes to the DOM. If it returns a different value than when it was called originally, React will restart the update from scratch, this time applying it as a blocking update, to ensure that every component on screen is reflecting the same version of the store. +* Nếu store bị thay đổi trong [non-blocking transition update](/reference/react/useTransition), React sẽ chuyển sang thực hiện cập nhật đó như một cập nhật chặn. Cụ thể, cho mỗi transition update, React sẽ gọi `getSnapshot` một lần nữa trước khi áp dụng các thay đổi vào DOM. Nếu nó trả về một giá trị khác so với khi nó được gọi ban đầu, React sẽ khởi động lại việc cập nhật từ đầu, lần này áp dụng nó như một cập nhật chặn, để đảm bảo rằng mọi thành phần trên màn hình đều phản ánh cùng một phiên bản của store. -* It's not recommended to _suspend_ a render based on a store value returned by `useSyncExternalStore`. The reason is that mutations to the external store cannot be marked as [non-blocking transition updates](/reference/react/useTransition), so they will trigger the nearest [`Suspense` fallback](/reference/react/Suspense), replacing already-rendered content on screen with a loading spinner, which typically makes a poor UX. +* Không nên _suspend_ một render dựa trên giá trị của store được trả về bởi `useSyncExternalStore`. Lý do là các thay đổi với cửa hàng bên ngoài(external store) không được đánh dấu là [non-blocking transition updates](/reference/react/useTransition), vì vậy chúng sẽ kích hoạt [`Suspense` fallback](/reference/react/Suspense) gần nhất, thay thế nội dung đã được render trên màn hình bằng một loading spinner, điều này thường tạo ra một trả nghiệm người dùng không tốt. - For example, the following are discouraged: + Ví dụ, những điều sau đây không được khuyến khích: ```js const LazyProductDetailPage = lazy(() => import('./ProductDetailPage.js')); @@ -69,26 +69,26 @@ The current snapshot of the store which you can use in your rendering logic. function ShoppingApp() { const selectedProductId = useSyncExternalStore(...); - // ❌ Calling `use` with a Promise dependent on `selectedProductId` + // ❌ Gọi `use` với một Promise phụ thuộc vào `selectedProductId` const data = use(fetchItem(selectedProductId)) - // ❌ Conditionally rendering a lazy component based on `selectedProductId` + // ❌ Render theo điều kiện một lazy component dựa vào `selectedProductId` return selectedProductId != null ? : ; } ``` --- -## Usage {/*usage*/} +## Cách sử dụng {/*usage*/} -### Subscribing to an external store {/*subscribing-to-an-external-store*/} +### Đăng ký vào một cửa hàng bên ngoài {/*subscribing-to-an-external-store*/} -Most of your React components will only read data from their [props,](/learn/passing-props-to-a-component) [state,](/reference/react/useState) and [context.](/reference/react/useContext) However, sometimes a component needs to read some data from some store outside of React that changes over time. This includes: +Hầu hết các React component của bạn chỉ đọc dữ liệu từ [props,](/learn/passing-props-to-a-component) [state,](/reference/react/useState) và [context.](/reference/react/useContext) Tuy nhiên, đôi khi một thành phần cần đọc một số dữ liệu từ một cửa hàng bên ngoài React mà thay đổi theo thời gian. Điều này bao gồm: -* Third-party state management libraries that hold state outside of React. -* Browser APIs that expose a mutable value and events to subscribe to its changes. +* Các thư viện quản lý trạng thái bên thứ ba lưu trữ tráng thái bên ngoài của React. +* Các API của trình duyệt(Browser APIs) cung cấp một giá trị có thể thay đổi và các sự kiện để đăng ký theo dõi sự thay đổi của nó. -Call `useSyncExternalStore` at the top level of your component to read a value from an external data store. +Gọi `useSyncExternalStore` ở cấp độ cao nhất của component để đọc một giá trị từ một kho dữ liệu bên ngoài(external store). ```js [[1, 5, "todosStore.subscribe"], [2, 5, "todosStore.getSnapshot"], [3, 5, "todos", 0]] import { useSyncExternalStore } from 'react'; @@ -100,14 +100,14 @@ function TodosApp() { } ``` -It returns the snapshot of the data in the store. You need to pass two functions as arguments: +Nó trả về snapshot của dữ liệu trong store. Bạn cần truyền vào hai hàm làm đối số: -1. The `subscribe` function should subscribe to the store and return a function that unsubscribes. -2. The `getSnapshot` function should read a snapshot of the data from the store. +1. Hàm `subscribe` nên đăng ký(subscribe) với cửa hàng và trả về một hàm để hủy đăng ký(unsubscribes). +2. Hàm `getSnapshot` nên đọc một ảnh chụp nhanh(snapshot) của dữ liệu từ store. -React will use these functions to keep your component subscribed to the store and re-render it on changes. +React sẽ sử dụng các hàm này để giữ cho component của bạn được đăng ký với store và re-render nó khi có thay đổi. -For example, in the sandbox below, `todosStore` is implemented as an external store that stores data outside of React. The `TodosApp` component connects to that external store with the `useSyncExternalStore` Hook. +Ví dụ, trong sandbox bên dưới, `todosStore` được triển khai như một external store chứa dữ liệu bên ngoài React. `TodosApp` component kết nối với external store bằng Hook `useSyncExternalStore`. @@ -169,17 +169,17 @@ function emitChange() { -When possible, we recommend using built-in React state with [`useState`](/reference/react/useState) and [`useReducer`](/reference/react/useReducer) instead. The `useSyncExternalStore` API is mostly useful if you need to integrate with existing non-React code. +Khi có thể, chúng tôi khuyến nghị bạn sử dụng trạng thái được xây dựng sẵn trong React với [`useState`](/reference/react/useState) and [`useReducer`](/reference/react/useReducer) thay thế. API `useSyncExternalStore` chủ yếu hữu ích nếu bạn cần tích hợp với mã không phải React hiện có . --- -### Subscribing to a browser API {/*subscribing-to-a-browser-api*/} +### Đăng ký với một API trình duyệt {/*subscribing-to-a-browser-api*/} -Another reason to add `useSyncExternalStore` is when you want to subscribe to some value exposed by the browser that changes over time. For example, suppose that you want your component to display whether the network connection is active. The browser exposes this information via a property called [`navigator.onLine`.](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) +Một lý do khác để bạn thêm `useSyncExternalStore` là khi bạn muốn đăng ký theo dõi một giá trị nào đó được trình duyệt cung cấp và thay đổi theo thời gian. Ví dụ, giả sử bạn muốn component của mình hiển thị liệu kết nối mạng có đang hoạt động không. Trình duyệt cung cấp thông tin này thông qua một thuộc tính có tên là [`navigator.onLine`.](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) -This value can change without React's knowledge, so you should read it with `useSyncExternalStore`. +Giá trị này có thể thay đổi mà React biết, vì vật bạn nên đọc nó với `useSyncExternalStore`. ```js import { useSyncExternalStore } from 'react'; @@ -190,7 +190,7 @@ function ChatIndicator() { } ``` -To implement the `getSnapshot` function, read the current value from the browser API: +Để triển khai hàm `getSnapshot`, đọc giá trị hiện tại từ API trình duyệt: ```js function getSnapshot() { @@ -198,7 +198,7 @@ function getSnapshot() { } ``` -Next, you need to implement the `subscribe` function. For example, when `navigator.onLine` changes, the browser fires the [`online`](https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event) and [`offline`](https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event) events on the `window` object. You need to subscribe the `callback` argument to the corresponding events, and then return a function that cleans up the subscriptions: +Tiếp theo, bạn cần triển khai hàm `subscribe`. Ví dụ, khi `navigator.onLine` thay đổi, trình duyệt sẽ kích hoạt các sự kiện [`online`](https://developer.mozilla.org/en-US/docs/Web/API/Window/online_event) and [`offline`](https://developer.mozilla.org/en-US/docs/Web/API/Window/offline_event) trên đối tượng `window`. Bạn cần đăng ký đối số `callback` vào các sự kiện tương ứng, và sau đó trả về một hàm để dọn dẹp các đăng ký: ```js function subscribe(callback) { @@ -211,7 +211,7 @@ function subscribe(callback) { } ``` -Now React knows how to read the value from the external `navigator.onLine` API and how to subscribe to its changes. Disconnect your device from the network and notice that the component re-renders in response: +Bây giờ React biết các đọc giá trị từ API `navigator.onLine` bên ngoài và cách đăng ký theo dõi dự thay đổi của nó. Ngắt kết nối thiết bị của bạn khỏi mạng và lưu ý răng component sẽ được render phải hồi lại: @@ -241,11 +241,11 @@ function subscribe(callback) { --- -### Extracting the logic to a custom Hook {/*extracting-the-logic-to-a-custom-hook*/} +### Tách logic ra thành một custom Hook {/*extracting-the-logic-to-a-custom-hook*/} -Usually you won't write `useSyncExternalStore` directly in your components. Instead, you'll typically call it from your own custom Hook. This lets you use the same external store from different components. +Thông thường bạn sẽ không trực tiếp viết `useSyncExternalStore` trong các component của bạn. Thay vào đó, bạn sẽ gọi nó từ custom Hook của mình. Điều này sẽ cho phép bạn sử dụng cùng một external store từ các component khác nhau. -For example, this custom `useOnlineStatus` Hook tracks whether the network is online: +Ví dụ, custom `useOnlineStatus` Hook này theo dõi mạng có đang online hay không: ```js {3,6} import { useSyncExternalStore } from 'react'; @@ -264,7 +264,7 @@ function subscribe(callback) { } ``` -Now different components can call `useOnlineStatus` without repeating the underlying implementation: +Giờ đây, các component có thể gọi `useOnlineStatus` mà không cần lặp lại các cài đặt cơ bản: @@ -326,14 +326,14 @@ function subscribe(callback) { --- -### Adding support for server rendering {/*adding-support-for-server-rendering*/} +### Thêm hỗ trợ cho việc render phía server {/*adding-support-for-server-rendering*/} -If your React app uses [server rendering,](/reference/react-dom/server) your React components will also run outside the browser environment to generate the initial HTML. This creates a few challenges when connecting to an external store: +Nếu ứng dụng React của bạn sử dụng kỹ thuật [server rendering,](/reference/react-dom/server) các React components của bạn cũng sẽ được thực thi bên ngoài môi trường trình duyệt để tạo HTML ban đầu. Điều này tạo ra một vài thác thức khi kết nối với một external store: -- If you're connecting to a browser-only API, it won't work because it does not exist on the server. -- If you're connecting to a third-party data store, you'll need its data to match between the server and client. +- Nếu bạn đang kết nối với một API chỉ dùng cho trình duyệt, nó sẽ không hoạt động bởi ví nó không tồn tại trên server. +- Nếu bạn đang kết nối với một external store của bên thứ ba, bạn sẽ cần dữ liệu cảu nó phải khớp giữa server và client. -To solve these issues, pass a `getServerSnapshot` function as the third argument to `useSyncExternalStore`: +Để giải quyết những vấn đề này, truyền một hảm `getServerSnapshot` là một đối số thứ ba cho `useSyncExternalStore`: ```js {4,12-14} import { useSyncExternalStore } from 'react'; @@ -356,60 +356,60 @@ function subscribe(callback) { } ``` -The `getServerSnapshot` function is similar to `getSnapshot`, but it runs only in two situations: +Hàm `getServerSnapshot` tương tự như hàm `getSnapshot`, nhưng nó chỉ chạy trong hai tình huống: -- It runs on the server when generating the HTML. -- It runs on the client during [hydration](/reference/react-dom/client/hydrateRoot), i.e. when React takes the server HTML and makes it interactive. +- Nó chạy trên server khi tạo HTML. +- Nó chạy trên client trong quá trình [hydration](/reference/react-dom/client/hydrateRoot), tức là khi React nhận HTML từ server và làm cho nó trở nên tương tác. -This lets you provide the initial snapshot value which will be used before the app becomes interactive. If there is no meaningful initial value for the server rendering, omit this argument to [force rendering on the client.](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) +Điều này cho phép bạn cung cấp giá trị snapshot ban đầu sẽ được sử dụng trước khi ứng dụng trở nên tương tác. Nếu không có giá trị bàn đầu có ý nghĩa cho việc render trên server, hãy bua đối số này để [force rendering on the client.](/reference/react/Suspense#providing-a-fallback-for-server-errors-and-client-only-content) -Make sure that `getServerSnapshot` returns the same exact data on the initial client render as it returned on the server. For example, if `getServerSnapshot` returned some prepopulated store content on the server, you need to transfer this content to the client. One way to do this is to emit a `