- Pick a color:{' '}
+ Chọn một màu:{' '}
setColor(e.target.value)}>
lightcoral
midnightblue
@@ -407,31 +406,29 @@ export default function App() {
-This example illustrates that **a component may receive different props over time.** Props are not always static! Here, the `time` prop changes every second, and the `color` prop changes when you select another color. Props reflect a component's data at any point in time, rather than only in the beginning.
+Ví dụ này minh họa rằng **một component có thể nhận các props khác nhau theo thời gian.** Props không phải lúc nào cũng tĩnh! Ở đây, prop `time` thay đổi mỗi giây và prop `color` thay đổi khi bạn chọn một màu khác. Props phản ánh dữ liệu của một component tại bất kỳ thời điểm nào, thay vì chỉ trong lúc ban đầu.
-However, props are [immutable](https://en.wikipedia.org/wiki/Immutable_object)—a term from computer science meaning "unchangeable". When a component needs to change its props (for example, in response to a user interaction or new data), it will have to "ask" its parent component to pass it _different props_—a new object! Its old props will then be cast aside, and eventually the JavaScript engine will reclaim the memory taken by them.
+Tuy nhiên, props là [bất biến](https://en.wikipedia.org/wiki/Immutable_object)—một thuật ngữ từ khoa học máy tính có nghĩa là "không thể thay đổi". Khi một component cần thay đổi các props của nó (ví dụ: để đáp ứng tương tác của người dùng hoặc dữ liệu mới), nó sẽ phải "yêu cầu" component cha của nó truyền cho nó _các props khác nhau_—một đối tượng mới! Các props cũ của nó sau đó sẽ bị loại bỏ và cuối cùng công cụ JavaScript sẽ thu hồi bộ nhớ mà chúng chiếm giữ.
-**Don't try to "change props".** When you need to respond to the user input (like changing the selected color), you will need to "set state", which you can learn about in [State: A Component's Memory.](/learn/state-a-components-memory)
+**Đừng cố gắng "thay đổi props".** Khi bạn cần phản hồi đầu vào của người dùng (như thay đổi màu đã chọn), bạn sẽ cần "đặt state", bạn có thể tìm hiểu về điều đó trong [State: Bộ nhớ của Component.](/learn/state-a-components-memory)
-* To pass props, add them to the JSX, just like you would with HTML attributes.
-* To read props, use the `function Avatar({ person, size })` destructuring syntax.
-* You can specify a default value like `size = 100`, which is used for missing and `undefined` props.
-* You can forward all props with ` ` JSX spread syntax, but don't overuse it!
-* Nested JSX like ` ` will appear as `Card` component's `children` prop.
-* Props are read-only snapshots in time: every render receives a new version of props.
-* You can't change props. When you need interactivity, you'll need to set state.
+* Để truyền props, hãy thêm chúng vào JSX, giống như bạn làm với các thuộc tính HTML.
+* Để đọc props, hãy sử dụng cú pháp destructuring `function Avatar({ person, size })`.
+* Bạn có thể chỉ định một giá trị mặc định như `size = 100`, được sử dụng cho các props bị thiếu và `undefined`.
+* Bạn có thể chuyển tiếp tất cả các props bằng cú pháp spread JSX ` `, nhưng đừng lạm dụng nó!
+* JSX lồng nhau như ` ` sẽ xuất hiện dưới dạng prop `children` của component `Card`.
+* Props là các ảnh chụp chỉ đọc tại một thời điểm: mỗi lần hiển thị nhận được một phiên bản props mới.
+* Bạn không thể thay đổi props. Khi bạn cần tương tác, bạn sẽ cần đặt state.
-
-
-#### Extract a component {/*extract-a-component*/}
+#### Trích xuất một component {/*extract-a-component*/}
-This `Gallery` component contains some very similar markup for two profiles. Extract a `Profile` component out of it to reduce the duplication. You'll need to choose what props to pass to it.
+Component `Gallery` này chứa một số đánh dấu rất giống nhau cho hai profile. Hãy trích xuất một component `Profile` ra khỏi nó để giảm sự trùng lặp. Bạn sẽ cần chọn những props nào để truyền cho nó.
@@ -523,16 +520,15 @@ li { margin: 5px; }
-
-Start by extracting the markup for one of the scientists. Then find the pieces that don't match it in the second example, and make them configurable by props.
+Bắt đầu bằng cách trích xuất đánh dấu cho một trong những nhà khoa học. Sau đó, tìm những phần không khớp với nó trong ví dụ thứ hai và làm cho chúng có thể định cấu hình bằng các đạo cụ.
-In this solution, the `Profile` component accepts multiple props: `imageId` (a string), `name` (a string), `profession` (a string), `awards` (an array of strings), `discovery` (a string), and `imageSize` (a number).
+Trong giải pháp này, thành phần `Profile` chấp nhận nhiều đạo cụ: `imageId` (một chuỗi), `name` (một chuỗi), `profession` (một chuỗi), `awards` (một mảng các chuỗi), `discovery` (một chuỗi) và `imageSize` (một số).
-Note that the `imageSize` prop has a default value, which is why we don't pass it to the component.
+Lưu ý rằng đạo cụ `imageSize` có một giá trị mặc định, đó là lý do tại sao chúng ta không chuyển nó cho thành phần.
@@ -630,9 +626,9 @@ li { margin: 5px; }
-Note how you don't need a separate `awardCount` prop if `awards` is an array. Then you can use `awards.length` to count the number of awards. Remember that props can take any values, and that includes arrays too!
+Lưu ý rằng bạn không cần một đạo cụ `awardCount` riêng biệt nếu `awards` là một mảng. Sau đó, bạn có thể sử dụng `awards.length` để đếm số lượng giải thưởng. Hãy nhớ rằng các đạo cụ có thể nhận bất kỳ giá trị nào và điều đó bao gồm cả mảng!
-Another solution, which is more similar to the earlier examples on this page, is to group all information about a person in a single object, and pass that object as one prop:
+Một giải pháp khác, tương tự hơn với các ví dụ trước đó trên trang này, là nhóm tất cả thông tin về một người trong một đối tượng duy nhất và chuyển đối tượng đó làm một đạo cụ:
@@ -727,15 +723,15 @@ li { margin: 5px; }
-Although the syntax looks slightly different because you're describing properties of a JavaScript object rather than a collection of JSX attributes, these examples are mostly equivalent, and you can pick either approach.
+Mặc dù cú pháp trông hơi khác một chút vì bạn đang mô tả các thuộc tính của một đối tượng JavaScript hơn là một tập hợp các thuộc tính JSX, nhưng các ví dụ này hầu như tương đương nhau và bạn có thể chọn một trong hai cách tiếp cận.
-#### Adjust the image size based on a prop {/*adjust-the-image-size-based-on-a-prop*/}
+#### Điều chỉnh kích thước hình ảnh dựa trên một đạo cụ {/*adjust-the-image-size-based-on-a-prop*/}
-In this example, `Avatar` receives a numeric `size` prop which determines the ` ` width and height. The `size` prop is set to `40` in this example. However, if you open the image in a new tab, you'll notice that the image itself is larger (`160` pixels). The real image size is determined by which thumbnail size you're requesting.
+Trong ví dụ này, `Avatar` nhận một đạo cụ số `size` xác định chiều rộng và chiều cao của ` `. Đạo cụ `size` được đặt thành `40` trong ví dụ này. Tuy nhiên, nếu bạn mở hình ảnh trong một tab mới, bạn sẽ nhận thấy rằng bản thân hình ảnh lớn hơn (`160` pixel). Kích thước hình ảnh thực tế được xác định bởi kích thước hình thu nhỏ bạn đang yêu cầu.
-Change the `Avatar` component to request the closest image size based on the `size` prop. Specifically, if the `size` is less than `90`, pass `'s'` ("small") rather than `'b'` ("big") to the `getImageUrl` function. Verify that your changes work by rendering avatars with different values of the `size` prop and opening images in a new tab.
+Thay đổi thành phần `Avatar` để yêu cầu kích thước hình ảnh gần nhất dựa trên đạo cụ `size`. Cụ thể, nếu `size` nhỏ hơn `90`, hãy chuyển `'s'` ("nhỏ") thay vì `'b'` ("lớn") cho hàm `getImageUrl`. Xác minh rằng các thay đổi của bạn hoạt động bằng cách hiển thị hình đại diện với các giá trị khác nhau của đạo cụ `size` và mở hình ảnh trong một tab mới.
@@ -786,7 +782,7 @@ export function getImageUrl(person, size) {
-Here is how you could go about it:
+Đây là cách bạn có thể thực hiện:
@@ -848,7 +844,7 @@ export function getImageUrl(person, size) {
-You could also show a sharper image for high DPI screens by taking [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio) into account:
+Bạn cũng có thể hiển thị hình ảnh sắc nét hơn cho màn hình DPI cao bằng cách tính đến [`window.devicePixelRatio`](https://developer.mozilla.org/en-US/docs/Web/API/Window/devicePixelRatio):
@@ -919,13 +915,13 @@ export function getImageUrl(person, size) {
-Props let you encapsulate logic like this inside the `Avatar` component (and change it later if needed) so that everyone can use the `` component without thinking about how the images are requested and resized.
+Đạo cụ cho phép bạn đóng gói logic như thế này bên trong thành phần `Avatar` (và thay đổi nó sau này nếu cần) để mọi người có thể sử dụng thành phần `` mà không cần suy nghĩ về cách hình ảnh được yêu cầu và thay đổi kích thước.
-#### Passing JSX in a `children` prop {/*passing-jsx-in-a-children-prop*/}
+#### Chuyển JSX trong một đạo cụ `children` {/*passing-jsx-in-a-children-prop*/}
-Extract a `Card` component from the markup below, and use the `children` prop to pass different JSX to it:
+Trích xuất một thành phần `Card` từ đánh dấu bên dưới và sử dụng đạo cụ `children` để chuyển các JSX khác nhau cho nó:
@@ -983,13 +979,13 @@ h1 {
-Any JSX you put inside of a component's tag will be passed as the `children` prop to that component.
+Bất kỳ JSX nào bạn đặt bên trong thẻ của một thành phần sẽ được chuyển dưới dạng đạo cụ `children` cho thành phần đó.
-This is how you can use the `Card` component in both places:
+Đây là cách bạn có thể sử dụng thành phần `Card` ở cả hai nơi:
@@ -1051,7 +1047,7 @@ h1 {
-You can also make `title` a separate prop if you want every `Card` to always have a title:
+Bạn cũng có thể tạo `title` một đạo cụ riêng biệt nếu bạn muốn mọi `Card` luôn có tiêu đề:
diff --git a/src/content/learn/react-compiler.md b/src/content/learn/react-compiler.md
index 7c46673e7..58c3cbe73 100644
--- a/src/content/learn/react-compiler.md
+++ b/src/content/learn/react-compiler.md
@@ -3,201 +3,201 @@ title: React Compiler
---
-This page will give you an introduction to React Compiler and how to try it out successfully.
+Trang này sẽ cung cấp cho bạn phần giới thiệu về React Compiler và cách dùng thử thành công.
-These docs are still a work in progress. More documentation is available in the [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions), and will be upstreamed into these docs when they are more stable.
+Tài liệu này vẫn đang trong quá trình hoàn thiện. Bạn có thể tìm thêm tài liệu trong [React Compiler Working Group repo](https://github.com/reactwg/react-compiler/discussions) và sẽ được đưa vào tài liệu này khi chúng ổn định hơn.
-* Getting started with the compiler
-* Installing the compiler and ESLint plugin
-* Troubleshooting
+* Bắt đầu với trình biên dịch
+* Cài đặt trình biên dịch và plugin ESLint
+* Khắc phục sự cố
-React Compiler is a new compiler currently in Beta, that we've open sourced to get early feedback from the community. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you’ve followed the [Rules of React](/reference/rules).
+React Compiler là một trình biên dịch mới hiện đang ở giai đoạn Beta, chúng tôi đã mở mã nguồn để nhận phản hồi sớm từ cộng đồng. Mặc dù nó đã được sử dụng trong sản xuất tại các công ty như Meta, nhưng việc triển khai trình biên dịch vào sản xuất cho ứng dụng của bạn sẽ phụ thuộc vào tình trạng của codebase và mức độ tuân thủ [Rules of React](/reference/rules).
-The latest Beta release can be found with the `@beta` tag, and daily experimental releases with `@experimental`.
+Bạn có thể tìm thấy bản phát hành Beta mới nhất với tag `@beta` và các bản phát hành thử nghiệm hàng ngày với `@experimental`.
-React Compiler is a new compiler that we've open sourced to get early feedback from the community. It is a build-time only tool that automatically optimizes your React app. It works with plain JavaScript, and understands the [Rules of React](/reference/rules), so you don't need to rewrite any code to use it.
+React Compiler là một trình biên dịch mới mà chúng tôi đã mở mã nguồn để nhận phản hồi sớm từ cộng đồng. Nó là một công cụ chỉ chạy trong thời gian build và tự động tối ưu hóa ứng dụng React của bạn. Nó hoạt động với JavaScript thuần túy và hiểu [Rules of React](/reference/rules), vì vậy bạn không cần phải viết lại bất kỳ mã nào để sử dụng nó.
-The compiler also includes an [ESLint plugin](#installing-eslint-plugin-react-compiler) that surfaces the analysis from the compiler right in your editor. **We strongly recommend everyone use the linter today.** The linter does not require that you have the compiler installed, so you can use it even if you are not ready to try out the compiler.
+Trình biên dịch cũng bao gồm một [ESLint plugin](#installing-eslint-plugin-react-compiler) hiển thị các phân tích từ trình biên dịch ngay trong trình soạn thảo của bạn. **Chúng tôi đặc biệt khuyên mọi người nên sử dụng linter ngay hôm nay.** Linter không yêu cầu bạn phải cài đặt trình biên dịch, vì vậy bạn có thể sử dụng nó ngay cả khi bạn chưa sẵn sàng dùng thử trình biên dịch.
-The compiler is currently released as `beta`, and is available to try out on React 17+ apps and libraries. To install the Beta:
+Trình biên dịch hiện được phát hành dưới dạng `beta` và có sẵn để dùng thử trên các ứng dụng và thư viện React 17+. Để cài đặt Beta:
npm install -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta
-Or, if you're using Yarn:
+Hoặc, nếu bạn đang sử dụng Yarn:
yarn add -D babel-plugin-react-compiler@beta eslint-plugin-react-compiler@beta
-If you are not using React 19 yet, please see [the section below](#using-react-compiler-with-react-17-or-18) for further instructions.
+Nếu bạn chưa sử dụng React 19, vui lòng xem [phần bên dưới](#using-react-compiler-with-react-17-or-18) để biết thêm hướng dẫn.
-### What does the compiler do? {/*what-does-the-compiler-do*/}
+### Trình biên dịch làm gì? {/*what-does-the-compiler-do*/}
-In order to optimize applications, React Compiler automatically memoizes your code. You may be familiar today with memoization through APIs such as `useMemo`, `useCallback`, and `React.memo`. With these APIs you can tell React that certain parts of your application don't need to recompute if their inputs haven't changed, reducing work on updates. While powerful, it's easy to forget to apply memoization or apply them incorrectly. This can lead to inefficient updates as React has to check parts of your UI that don't have any _meaningful_ changes.
+Để tối ưu hóa ứng dụng, React Compiler tự động memoize code của bạn. Bạn có thể đã quen thuộc với memoization thông qua các API như `useMemo`, `useCallback` và `React.memo`. Với các API này, bạn có thể cho React biết rằng một số phần nhất định của ứng dụng không cần tính toán lại nếu đầu vào của chúng không thay đổi, giảm tải công việc khi cập nhật. Mặc dù mạnh mẽ, nhưng rất dễ quên áp dụng memoization hoặc áp dụng chúng không chính xác. Điều này có thể dẫn đến các bản cập nhật không hiệu quả vì React phải kiểm tra các phần của UI không có bất kỳ thay đổi _ý nghĩa_ nào.
-The compiler uses its knowledge of JavaScript and React's rules to automatically memoize values or groups of values within your components and hooks. If it detects breakages of the rules, it will automatically skip over just those components or hooks, and continue safely compiling other code.
+Trình biên dịch sử dụng kiến thức về JavaScript và các quy tắc của React để tự động memoize các giá trị hoặc nhóm giá trị trong các component và hook của bạn. Nếu nó phát hiện ra các vi phạm quy tắc, nó sẽ tự động bỏ qua các component hoặc hook đó và tiếp tục biên dịch an toàn các code khác.
-React Compiler can statically detect when Rules of React are broken, and safely opt-out of optimizing just the affected components or hooks. It is not necessary for the compiler to optimize 100% of your codebase.
+React Compiler có thể phát hiện tĩnh khi Rules of React bị vi phạm và tự động chọn không tối ưu hóa chỉ các component hoặc hook bị ảnh hưởng. Không cần thiết để trình biên dịch tối ưu hóa 100% codebase của bạn.
-If your codebase is already very well-memoized, you might not expect to see major performance improvements with the compiler. However, in practice memoizing the correct dependencies that cause performance issues is tricky to get right by hand.
+Nếu codebase của bạn đã được memoize rất tốt, bạn có thể không thấy những cải thiện lớn về hiệu suất với trình biên dịch. Tuy nhiên, trong thực tế, việc memoize các dependency chính xác gây ra các vấn đề về hiệu suất là rất khó để thực hiện bằng tay.
-#### What kind of memoization does React Compiler add? {/*what-kind-of-memoization-does-react-compiler-add*/}
+#### Loại memoization nào mà React Compiler thêm vào? {/*what-kind-of-memoization-does-react-compiler-add*/}
-The initial release of React Compiler is primarily focused on **improving update performance** (re-rendering existing components), so it focuses on these two use cases:
+Bản phát hành ban đầu của React Compiler chủ yếu tập trung vào **cải thiện hiệu suất cập nhật** (re-rendering các component hiện có), vì vậy nó tập trung vào hai trường hợp sử dụng sau:
-1. **Skipping cascading re-rendering of components**
- * Re-rendering ` ` causes many components in its component tree to re-render, even though only ` ` has changed
-1. **Skipping expensive calculations from outside of React**
- * For example, calling `expensivelyProcessAReallyLargeArrayOfObjects()` inside of your component or hook that needs that data
+1. **Bỏ qua re-rendering theo tầng của các component**
+ * Re-rendering ` ` khiến nhiều component trong cây component của nó re-render, mặc dù chỉ có ` ` thay đổi
+2. **Bỏ qua các tính toán tốn kém từ bên ngoài React**
+ * Ví dụ: gọi `expensivelyProcessAReallyLargeArrayOfObjects()` bên trong component hoặc hook của bạn cần dữ liệu đó
-#### Optimizing Re-renders {/*optimizing-re-renders*/}
+#### Tối ưu hóa Re-renders {/*optimizing-re-renders*/}
-React lets you express your UI as a function of their current state (more concretely: their props, state, and context). In its current implementation, when a component's state changes, React will re-render that component _and all of its children_ — unless you have applied some form of manual memoization with `useMemo()`, `useCallback()`, or `React.memo()`. For example, in the following example, `` will re-render whenever ``'s state changes:
+React cho phép bạn thể hiện UI của mình như một hàm của trạng thái hiện tại của chúng (cụ thể hơn: props, state và context của chúng). Trong implementation hiện tại, khi state của một component thay đổi, React sẽ re-render component đó _và tất cả các component con của nó_ — trừ khi bạn đã áp dụng một số hình thức memoization thủ công với `useMemo()`, `useCallback()` hoặc `React.memo()`. Ví dụ: trong ví dụ sau, `` sẽ re-render bất cứ khi nào state của `` thay đổi:
```javascript
function FriendList({ friends }) {
const onlineCount = useFriendOnlineCount();
if (friends.length === 0) {
- return ;
+ return ;
}
return (
-
- {onlineCount} online
- {friends.map((friend) => (
-
- ))}
-
-
+
+ {onlineCount} online
+ {friends.map((friend) => (
+
+ ))}
+
+
);
}
```
-[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA)
+[_Xem ví dụ này trong React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAMygOzgFwJYSYAEAYjHgpgCYAyeYOAFMEWuZVWEQL4CURwADrEicQgyKEANnkwIAwtEw4iAXiJQwCMhWoB5TDLmKsTXgG5hRInjRFGbXZwB0UygHMcACzWr1ABn4hEWsYBBxYYgAeADkIHQ4uAHoAPksRbisiMIiYYkYs6yiqPAA3FMLrIiiwAAcAQ0wU4GlZBSUcbklDNqikusaKkKrgR0TnAFt62sYHdmp+VRT7SqrqhOo6Bnl6mCoiAGsEAE9VUfmqZzwqLrHqM7ubolTVol5eTOGigFkEMDB6u4EAAhKA4HCEZ5DNZ9ErlLIWYTcEDcIA)
-React Compiler automatically applies the equivalent of manual memoization, ensuring that only the relevant parts of an app re-render as state changes, which is sometimes referred to as "fine-grained reactivity". In the above example, React Compiler determines that the return value of ` ` can be reused even as `friends` changes, and can avoid recreating this JSX _and_ avoid re-rendering `` as the count changes.
+React Compiler tự động áp dụng tương đương với memoization thủ công, đảm bảo rằng chỉ các phần liên quan của ứng dụng re-render khi state thay đổi, đôi khi được gọi là "fine-grained reactivity". Trong ví dụ trên, React Compiler xác định rằng giá trị trả về của ` ` có thể được sử dụng lại ngay cả khi `friends` thay đổi và có thể tránh tạo lại JSX này _và_ tránh re-rendering `` khi số lượng thay đổi.
-#### Expensive calculations also get memoized {/*expensive-calculations-also-get-memoized*/}
+#### Các tính toán tốn kém cũng được memoize {/*expensive-calculations-also-get-memoized*/}
-The compiler can also automatically memoize for expensive calculations used during rendering:
+Trình biên dịch cũng có thể tự động memoize cho các tính toán tốn kém được sử dụng trong quá trình rendering:
```js
-// **Not** memoized by React Compiler, since this is not a component or hook
+// **Không** được memoize bởi React Compiler, vì đây không phải là component hoặc hook
function expensivelyProcessAReallyLargeArrayOfObjects() { /* ... */ }
-// Memoized by React Compiler since this is a component
+// Được memoize bởi React Compiler vì đây là một component
function TableContainer({ items }) {
- // This function call would be memoized:
+ // Lệnh gọi hàm này sẽ được memoize:
const data = expensivelyProcessAReallyLargeArrayOfObjects(items);
// ...
}
```
-[_See this example in the React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA)
+[_Xem ví dụ này trong React Compiler Playground_](https://playground.react.dev/#N4Igzg9grgTgxgUxALhAejQAgFTYHIQAuumAtgqRAJYBeCAJpgEYCemASggIZyGYDCEUgAcqAGwQwANJjBUAdokyEAFlTCZ1meUUxdMcIcIjyE8vhBiYVECAGsAOvIBmURYSonMCAB7CzcgBuCGIsAAowEIhgYACCnFxioQAyXDAA5gixMDBcLADyzvlMAFYIvGAAFACUmMCYaNiYAHStOFgAvk5OGJgAshTUdIysHNy8AkbikrIKSqpaWvqGIiZmhE6u7p7ymAAqXEwSguZcCpKV9VSEFBodtcBOmAYmYHz0XIT6ALzefgFUYKhCJRBAxeLcJIsVIZLI5PKFYplCqVa63aoAbm6u0wMAQhFguwAPPRAQA+YAfL4dIloUmBMlODogDpAA)
-However, if `expensivelyProcessAReallyLargeArrayOfObjects` is truly an expensive function, you may want to consider implementing its own memoization outside of React, because:
+Tuy nhiên, nếu `expensivelyProcessAReallyLargeArrayOfObjects` thực sự là một hàm tốn kém, bạn có thể muốn xem xét việc triển khai memoization của riêng nó bên ngoài React, vì:
-- React Compiler only memoizes React components and hooks, not every function
-- React Compiler's memoization is not shared across multiple components or hooks
+- React Compiler chỉ memoize các React component và hook, không phải mọi hàm
+- Memoization của React Compiler không được chia sẻ giữa nhiều component hoặc hook
-So if `expensivelyProcessAReallyLargeArrayOfObjects` was used in many different components, even if the same exact items were passed down, that expensive calculation would be run repeatedly. We recommend [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) first to see if it really is that expensive before making code more complicated.
+Vì vậy, nếu `expensivelyProcessAReallyLargeArrayOfObjects` được sử dụng trong nhiều component khác nhau, ngay cả khi các item giống hệt nhau được truyền xuống, thì tính toán tốn kém đó sẽ được chạy lặp đi lặp lại. Chúng tôi khuyên bạn nên [profiling](https://react.dev/reference/react/useMemo#how-to-tell-if-a-calculation-is-expensive) trước để xem nó có thực sự tốn kém hay không trước khi làm cho code trở nên phức tạp hơn.
-### Should I try out the compiler? {/*should-i-try-out-the-compiler*/}
+### Tôi có nên dùng thử trình biên dịch không? {/*should-i-try-out-the-compiler*/}
-Please note that the compiler is still in Beta and has many rough edges. While it has been used in production at companies like Meta, rolling out the compiler to production for your app will depend on the health of your codebase and how well you've followed the [Rules of React](/reference/rules).
+Xin lưu ý rằng trình biên dịch vẫn đang ở giai đoạn Beta và có nhiều điểm chưa hoàn thiện. Mặc dù nó đã được sử dụng trong sản xuất tại các công ty như Meta, nhưng việc triển khai trình biên dịch vào sản xuất cho ứng dụng của bạn sẽ phụ thuộc vào tình trạng của codebase và mức độ tuân thủ [Rules of React](/reference/rules).
-**You don't have to rush into using the compiler now. It's okay to wait until it reaches a stable release before adopting it.** However, we do appreciate trying it out in small experiments in your apps so that you can [provide feedback](#reporting-issues) to us to help make the compiler better.
+**Bạn không cần phải vội vàng sử dụng trình biên dịch ngay bây giờ. Bạn có thể đợi cho đến khi nó đạt đến bản phát hành ổn định trước khi áp dụng nó.** Tuy nhiên, chúng tôi đánh giá cao việc bạn dùng thử nó trong các thử nghiệm nhỏ trong ứng dụng của mình để bạn có thể [cung cấp phản hồi](#reporting-issues) cho chúng tôi để giúp trình biên dịch tốt hơn.
-## Getting Started {/*getting-started*/}
+## Bắt đầu {/*getting-started*/}
-In addition to these docs, we recommend checking the [React Compiler Working Group](https://github.com/reactwg/react-compiler) for additional information and discussion about the compiler.
+Ngoài các tài liệu này, chúng tôi khuyên bạn nên kiểm tra [React Compiler Working Group](https://github.com/reactwg/react-compiler) để biết thêm thông tin và thảo luận về trình biên dịch.
-### Installing eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/}
+### Cài đặt eslint-plugin-react-compiler {/*installing-eslint-plugin-react-compiler*/}
-React Compiler also powers an ESLint plugin. The ESLint plugin can be used **independently** of the compiler, meaning you can use the ESLint plugin even if you don't use the compiler.
+React Compiler cũng cung cấp một ESLint plugin. ESLint plugin có thể được sử dụng **độc lập** với trình biên dịch, có nghĩa là bạn có thể sử dụng ESLint plugin ngay cả khi bạn không sử dụng trình biên dịch.
npm install -D eslint-plugin-react-compiler@beta
-Then, add it to your ESLint config:
+Sau đó, thêm nó vào cấu hình ESLint của bạn:
```js
import reactCompiler from 'eslint-plugin-react-compiler'
export default [
{
- plugins: {
- 'react-compiler': reactCompiler,
- },
- rules: {
- 'react-compiler/react-compiler': 'error',
- },
+ plugins: {
+ 'react-compiler': reactCompiler,
+ },
+ rules: {
+ 'react-compiler/react-compiler': 'error',
+ },
},
]
```
-Or, in the deprecated eslintrc config format:
+Hoặc, trong định dạng cấu hình eslintrc không được dùng nữa:
```js
module.exports = {
plugins: [
- 'eslint-plugin-react-compiler',
+ 'eslint-plugin-react-compiler',
],
rules: {
- 'react-compiler/react-compiler': 'error',
+ 'react-compiler/react-compiler': 'error',
},
}
```
-The ESLint plugin will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase.
+ESLint plugin sẽ hiển thị bất kỳ vi phạm nào đối với các quy tắc của React trong trình soạn thảo của bạn. Khi nó làm điều này, điều đó có nghĩa là trình biên dịch đã bỏ qua việc tối ưu hóa component hoặc hook đó. Điều này hoàn toàn ổn và trình biên dịch có thể khôi phục và tiếp tục tối ưu hóa các component khác trong codebase của bạn.
-**You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized, but it is not required to fix everything before you can use the compiler.
+**Bạn không cần phải sửa tất cả các vi phạm ESLint ngay lập tức.** Bạn có thể giải quyết chúng theo tốc độ của riêng bạn để tăng số lượng component và hook được tối ưu hóa, nhưng không bắt buộc phải sửa mọi thứ trước khi bạn có thể sử dụng trình biên dịch.
-### Rolling out the compiler to your codebase {/*using-the-compiler-effectively*/}
+### Triển khai trình biên dịch cho codebase của bạn {/*using-the-compiler-effectively*/}
-#### Existing projects {/*existing-projects*/}
-The compiler is designed to compile functional components and hooks that follow the [Rules of React](/reference/rules). It can also handle code that breaks those rules by bailing out (skipping over) those components or hooks. However, due to the flexible nature of JavaScript, the compiler cannot catch every possible violation and may compile with false negatives: that is, the compiler may accidentally compile a component/hook that breaks the Rules of React which can lead to undefined behavior.
+#### Các dự án hiện có {/*existing-projects*/}
+Trình biên dịch được thiết kế để biên dịch các functional component và hook tuân theo [Rules of React](/reference/rules). Nó cũng có thể xử lý code vi phạm các quy tắc đó bằng cách bỏ qua (skipping over) các component hoặc hook đó. Tuy nhiên, do tính chất linh hoạt của JavaScript, trình biên dịch không thể bắt mọi vi phạm có thể xảy ra và có thể biên dịch với false negative: nghĩa là, trình biên dịch có thể vô tình biên dịch một component/hook vi phạm Rules of React, điều này có thể dẫn đến hành vi không xác định.
-For this reason, to adopt the compiler successfully on existing projects, we recommend running it on a small directory in your product code first. You can do this by configuring the compiler to only run on a specific set of directories:
+Vì lý do này, để áp dụng trình biên dịch thành công trên các dự án hiện có, chúng tôi khuyên bạn nên chạy nó trên một thư mục nhỏ trong product code của bạn trước. Bạn có thể thực hiện việc này bằng cách định cấu hình trình biên dịch chỉ chạy trên một tập hợp các thư mục cụ thể:
```js {3}
const ReactCompilerConfig = {
sources: (filename) => {
- return filename.indexOf('src/path/to/dir') !== -1;
+ return filename.indexOf('src/path/to/dir') !== -1;
},
};
```
-When you have more confidence with rolling out the compiler, you can expand coverage to other directories as well and slowly roll it out to your whole app.
+Khi bạn tự tin hơn với việc triển khai trình biên dịch, bạn có thể mở rộng phạm vi phủ sóng sang các thư mục khác và từ từ triển khai nó cho toàn bộ ứng dụng của bạn.
-#### New projects {/*new-projects*/}
+#### Các dự án mới {/*new-projects*/}
-If you're starting a new project, you can enable the compiler on your entire codebase, which is the default behavior.
+Nếu bạn đang bắt đầu một dự án mới, bạn có thể bật trình biên dịch trên toàn bộ codebase của mình, đây là hành vi mặc định.
-### Using React Compiler with React 17 or 18 {/*using-react-compiler-with-react-17-or-18*/}
+### Sử dụng React Compiler với React 17 hoặc 18 {/*using-react-compiler-with-react-17-or-18*/}
-React Compiler works best with React 19 RC. If you are unable to upgrade, you can install the extra `react-compiler-runtime` package which will allow the compiled code to run on versions prior to 19. However, note that the minimum supported version is 17.
+React Compiler hoạt động tốt nhất với React 19 RC. Nếu bạn không thể nâng cấp, bạn có thể cài đặt gói `react-compiler-runtime` bổ sung, gói này sẽ cho phép code đã biên dịch chạy trên các phiên bản trước 19. Tuy nhiên, lưu ý rằng phiên bản được hỗ trợ tối thiểu là 17.
npm install react-compiler-runtime@beta
-You should also add the correct `target` to your compiler config, where `target` is the major version of React you are targeting:
+Bạn cũng nên thêm `target` chính xác vào cấu hình trình biên dịch của mình, trong đó `target` là phiên bản chính của React mà bạn đang nhắm mục tiêu:
```js {3}
// babel.config.js
@@ -207,24 +207,24 @@ const ReactCompilerConfig = {
module.exports = function () {
return {
- plugins: [
- ['babel-plugin-react-compiler', ReactCompilerConfig],
- ],
+ plugins: [
+ ['babel-plugin-react-compiler', ReactCompilerConfig],
+ ],
};
};
```
-### Using the compiler on libraries {/*using-the-compiler-on-libraries*/}
+### Sử dụng trình biên dịch trên các thư viện {/*using-the-compiler-on-libraries*/}
-React Compiler can also be used to compile libraries. Because React Compiler needs to run on the original source code prior to any code transformations, it is not possible for an application's build pipeline to compile the libraries they use. Hence, our recommendation is for library maintainers to independently compile and test their libraries with the compiler, and ship compiled code to npm.
+React Compiler cũng có thể được sử dụng để biên dịch các thư viện. Vì React Compiler cần chạy trên source code gốc trước bất kỳ chuyển đổi code nào, nên không thể để pipeline build của ứng dụng biên dịch các thư viện mà chúng sử dụng. Do đó, chúng tôi khuyên các người duy trì thư viện nên độc lập biên dịch và kiểm tra thư viện của họ bằng trình biên dịch và chuyển code đã biên dịch lên npm.
-Because your code is pre-compiled, users of your library will not need to have the compiler enabled in order to benefit from the automatic memoization applied to your library. If your library targets apps not yet on React 19, specify a minimum [`target` and add `react-compiler-runtime` as a direct dependency](#using-react-compiler-with-react-17-or-18). The runtime package will use the correct implementation of APIs depending on the application's version, and polyfill the missing APIs if necessary.
+Vì code của bạn được biên dịch trước, người dùng thư viện của bạn sẽ không cần bật trình biên dịch để hưởng lợi từ memoization tự động được áp dụng cho thư viện của bạn. Nếu thư viện của bạn nhắm mục tiêu đến các ứng dụng chưa có trên React 19, hãy chỉ định [`target` tối thiểu và thêm `react-compiler-runtime` làm dependency trực tiếp](#using-react-compiler-with-react-17-or-18). Gói runtime sẽ sử dụng implementation chính xác của các API tùy thuộc vào phiên bản của ứng dụng và polyfill các API bị thiếu nếu cần thiết.
-Library code can often require more complex patterns and usage of escape hatches. For this reason, we recommend ensuring that you have sufficient testing in order to identify any issues that might arise from using the compiler on your library. If you identify any issues, you can always opt-out the specific components or hooks with the [`'use no memo'` directive](#something-is-not-working-after-compilation).
+Code thư viện thường có thể yêu cầu các pattern phức tạp hơn và sử dụng các escape hatch. Vì lý do này, chúng tôi khuyên bạn nên đảm bảo rằng bạn có đủ thử nghiệm để xác định bất kỳ vấn đề nào có thể phát sinh từ việc sử dụng trình biên dịch trên thư viện của bạn. Nếu bạn xác định bất kỳ vấn đề nào, bạn luôn có thể chọn không sử dụng các component hoặc hook cụ thể bằng directive [`'use no memo'`](#something-is-not-working-after-compilation).
-Similarly to apps, it is not necessary to fully compile 100% of your components or hooks to see benefits in your library. A good starting point might be to identify the most performance sensitive parts of your library and ensuring that they don't break the [Rules of React](/reference/rules), which you can use `eslint-plugin-react-compiler` to identify.
+Tương tự như các ứng dụng, không cần thiết phải biên dịch hoàn toàn 100% component hoặc hook của bạn để thấy lợi ích trong thư viện của bạn. Một điểm khởi đầu tốt có thể là xác định các phần nhạy cảm nhất về hiệu suất của thư viện của bạn và đảm bảo rằng chúng không vi phạm [Rules of React](/reference/rules), bạn có thể sử dụng `eslint-plugin-react-compiler` để xác định.
-## Usage {/*installation*/}
+## Cách sử dụng {/*installation*/}
### Babel {/*usage-with-babel*/}
@@ -232,9 +232,9 @@ Similarly to apps, it is not necessary to fully compile 100% of your components
npm install babel-plugin-react-compiler@beta
-The compiler includes a Babel plugin which you can use in your build pipeline to run the compiler.
+Trình biên dịch bao gồm một Babel plugin mà bạn có thể sử dụng trong pipeline build của mình để chạy trình biên dịch.
-After installing, add it to your Babel config. Please note that it's critical that the compiler run **first** in the pipeline:
+Sau khi cài đặt, hãy thêm nó vào cấu hình Babel của bạn. Xin lưu ý rằng điều quan trọng là trình biên dịch phải chạy **đầu tiên** trong pipeline:
```js {7}
// babel.config.js
@@ -242,19 +242,19 @@ const ReactCompilerConfig = { /* ... */ };
module.exports = function () {
return {
- plugins: [
- ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first!
- // ...
- ],
+ plugins: [
+ ['babel-plugin-react-compiler', ReactCompilerConfig], // must run first!
+ // ...
+ ],
};
};
```
-`babel-plugin-react-compiler` should run first before other Babel plugins as the compiler requires the input source information for sound analysis.
+`babel-plugin-react-compiler` phải chạy trước các Babel plugin khác vì trình biên dịch yêu cầu thông tin source đầu vào để phân tích âm thanh.
### Vite {/*usage-with-vite*/}
-If you use Vite, you can add the plugin to vite-plugin-react:
+Nếu bạn sử dụng Vite, bạn có thể thêm plugin vào vite-plugin-react:
```js {10}
// vite.config.js
@@ -262,26 +262,26 @@ const ReactCompilerConfig = { /* ... */ };
export default defineConfig(() => {
return {
- plugins: [
- react({
- babel: {
- plugins: [
- ["babel-plugin-react-compiler", ReactCompilerConfig],
- ],
- },
- }),
- ],
- // ...
+ plugins: [
+ react({
+ babel: {
+ plugins: [
+ ["babel-plugin-react-compiler", ReactCompilerConfig],
+ ],
+ },
+ }),
+ ],
+ // ...
};
});
```
### Next.js {/*usage-with-nextjs*/}
-Please refer to the [Next.js docs](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) for more information.
+Vui lòng tham khảo [tài liệu Next.js](https://nextjs.org/docs/app/api-reference/next-config-js/reactCompiler) để biết thêm thông tin.
### Remix {/*usage-with-remix*/}
-Install `vite-plugin-babel`, and add the compiler's Babel plugin to it:
+Cài đặt `vite-plugin-babel` và thêm Babel plugin của trình biên dịch vào nó:
npm install vite-plugin-babel
@@ -295,66 +295,66 @@ const ReactCompilerConfig = { /* ... */ };
export default defineConfig({
plugins: [
- remix({ /* ... */}),
- babel({
- filter: /\.[jt]sx?$/,
- babelConfig: {
- presets: ["@babel/preset-typescript"], // if you use TypeScript
- plugins: [
- ["babel-plugin-react-compiler", ReactCompilerConfig],
- ],
- },
- }),
+ remix({ /* ... */}),
+ babel({
+ filter: /\.[jt]sx?$/,
+ babelConfig: {
+ presets: ["@babel/preset-typescript"], // if you use TypeScript
+ plugins: [
+ ["babel-plugin-react-compiler", ReactCompilerConfig],
+ ],
+ },
+ }),
],
});
```
### Webpack {/*usage-with-webpack*/}
-A community webpack loader is [now available here](https://github.com/SukkaW/react-compiler-webpack).
+Một webpack loader cộng đồng [hiện có tại đây](https://github.com/SukkaW/react-compiler-webpack).
### Expo {/*usage-with-expo*/}
-Please refer to [Expo's docs](https://docs.expo.dev/guides/react-compiler/) to enable and use the React Compiler in Expo apps.
+Vui lòng tham khảo [tài liệu của Expo](https://docs.expo.dev/guides/react-compiler/) để bật và sử dụng React Compiler trong các ứng dụng Expo.
### Metro (React Native) {/*usage-with-react-native-metro*/}
-React Native uses Babel via Metro, so refer to the [Usage with Babel](#usage-with-babel) section for installation instructions.
+React Native sử dụng Babel thông qua Metro, vì vậy hãy tham khảo phần [Cách sử dụng với Babel](#usage-with-babel) để biết hướng dẫn cài đặt.
### Rspack {/*usage-with-rspack*/}
-Please refer to [Rspack's docs](https://rspack.dev/guide/tech/react#react-compiler) to enable and use the React Compiler in Rspack apps.
+Vui lòng tham khảo [tài liệu của Rspack](https://rspack.dev/guide/tech/react#react-compiler) để bật và sử dụng React Compiler trong các ứng dụng Rspack.
### Rsbuild {/*usage-with-rsbuild*/}
-Please refer to [Rsbuild's docs](https://rsbuild.dev/guide/framework/react#react-compiler) to enable and use the React Compiler in Rsbuild apps.
+Vui lòng tham khảo [tài liệu của Rsbuild](https://rsbuild.dev/guide/framework/react#react-compiler) để bật và sử dụng React Compiler trong các ứng dụng Rsbuild.
-## Troubleshooting {/*troubleshooting*/}
+## Khắc phục sự cố {/*troubleshooting*/}
-To report issues, please first create a minimal repro on the [React Compiler Playground](https://playground.react.dev/) and include it in your bug report. You can open issues in the [facebook/react](https://github.com/facebook/react/issues) repo.
+Để báo cáo sự cố, trước tiên hãy tạo một bản repro tối thiểu trên [React Compiler Playground](https://playground.react.dev/) và đưa nó vào báo cáo lỗi của bạn. Bạn có thể mở các issue trong repo [facebook/react](https://github.com/facebook/react/issues).
-You can also provide feedback in the React Compiler Working Group by applying to be a member. Please see [the README for more details on joining](https://github.com/reactwg/react-compiler).
+Bạn cũng có thể cung cấp phản hồi trong React Compiler Working Group bằng cách đăng ký làm thành viên. Vui lòng xem [README để biết thêm chi tiết về cách tham gia](https://github.com/reactwg/react-compiler).
-### What does the compiler assume? {/*what-does-the-compiler-assume*/}
+### Trình biên dịch giả định điều gì? {/*what-does-the-compiler-assume*/}
-React Compiler assumes that your code:
+React Compiler giả định rằng code của bạn:
-1. Is valid, semantic JavaScript.
-2. Tests that nullable/optional values and properties are defined before accessing them (for example, by enabling [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) if using TypeScript), i.e., `if (object.nullableProperty) { object.nullableProperty.foo }` or with optional-chaining `object.nullableProperty?.foo`.
-3. Follows the [Rules of React](https://react.dev/reference/rules).
+1. Là JavaScript hợp lệ, ngữ nghĩa.
+2. Kiểm tra xem các giá trị và thuộc tính nullable/optional có được xác định trước khi truy cập chúng hay không (ví dụ: bằng cách bật [`strictNullChecks`](https://www.typescriptlang.org/tsconfig/#strictNullChecks) nếu sử dụng TypeScript), tức là `if (object.nullableProperty) { object.nullableProperty.foo }` hoặc với optional-chaining `object.nullableProperty?.foo`.
+3. Tuân theo [Rules of React](https://react.dev/reference/rules).
-React Compiler can verify many of the Rules of React statically, and will safely skip compilation when it detects an error. To see the errors we recommend also installing [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler).
+React Compiler có thể xác minh nhiều Rules of React một cách tĩnh và sẽ bỏ qua quá trình biên dịch một cách an toàn khi phát hiện lỗi. Để xem các lỗi, chúng tôi khuyên bạn cũng nên cài đặt [eslint-plugin-react-compiler](https://www.npmjs.com/package/eslint-plugin-react-compiler).
-### How do I know my components have been optimized? {/*how-do-i-know-my-components-have-been-optimized*/}
+### Làm cách nào để biết các component của tôi đã được tối ưu hóa? {/*how-do-i-know-my-components-have-been-optimized*/}
-[React DevTools](/learn/react-developer-tools) (v5.0+) and [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) have built-in support for React Compiler and will display a "Memo ✨" badge next to components that have been optimized by the compiler.
+[React DevTools](/learn/react-developer-tools) (v5.0+) và [React Native DevTools](https://reactnative.dev/docs/react-native-devtools) có hỗ trợ tích hợp cho React Compiler và sẽ hiển thị huy hiệu "Memo ✨" bên cạnh các component đã được tối ưu hóa bởi trình biên dịch.
-### Something is not working after compilation {/*something-is-not-working-after-compilation*/}
-If you have eslint-plugin-react-compiler installed, the compiler will display any violations of the rules of React in your editor. When it does this, it means that the compiler has skipped over optimizing that component or hook. This is perfectly okay, and the compiler can recover and continue optimizing other components in your codebase. **You don't have to fix all ESLint violations straight away.** You can address them at your own pace to increase the amount of components and hooks being optimized.
+### Có gì đó không hoạt động sau khi biên dịch {/*something-is-not-working-after-compilation*/}
+Nếu bạn đã cài đặt eslint-plugin-react-compiler, trình biên dịch sẽ hiển thị bất kỳ vi phạm nào đối với các quy tắc của React trong trình soạn thảo của bạn. Khi nó làm điều này, điều đó có nghĩa là trình biên dịch đã bỏ qua việc tối ưu hóa component hoặc hook đó. Điều này hoàn toàn ổn và trình biên dịch có thể khôi phục và tiếp tục tối ưu hóa các component khác trong codebase của bạn. **Bạn không cần phải sửa tất cả các vi phạm ESLint ngay lập tức.** Bạn có thể giải quyết chúng theo tốc độ của riêng bạn để tăng số lượng component và hook được tối ưu hóa.
-Due to the flexible and dynamic nature of JavaScript however, it's not possible to comprehensively detect all cases. Bugs and undefined behavior such as infinite loops may occur in those cases.
+Tuy nhiên, do tính chất linh hoạt và động của JavaScript, không thể phát hiện toàn diện tất cả các trường hợp. Các lỗi và hành vi không xác định như vòng lặp vô hạn có thể xảy ra trong những trường hợp đó.
-If your app doesn't work properly after compilation and you aren't seeing any ESLint errors, the compiler may be incorrectly compiling your code. To confirm this, try to make the issue go away by aggressively opting out any component or hook you think might be related via the [`"use no memo"` directive](#opt-out-of-the-compiler-for-a-component).
+Nếu ứng dụng của bạn không hoạt động bình thường sau khi biên dịch và bạn không thấy bất kỳ lỗi ESLint nào, thì trình biên dịch có thể đang biên dịch code của bạn không chính xác. Để xác nhận điều này, hãy thử làm cho sự cố biến mất bằng cách chủ động chọn không sử dụng bất kỳ component hoặc hook nào bạn cho là có liên quan thông qua directive [`"use no memo"`](#opt-out-of-the-compiler-for-a-component).
```js {2}
function SuspiciousComponent() {
@@ -366,13 +366,13 @@ function SuspiciousComponent() {
#### `"use no memo"` {/*use-no-memo*/}
-`"use no memo"` is a _temporary_ escape hatch that lets you opt-out components and hooks from being compiled by the React Compiler. This directive is not meant to be long lived the same way as eg [`"use client"`](/reference/rsc/use-client) is.
+`"use no memo"` là một escape hatch _tạm thời_ cho phép bạn chọn không biên dịch các component và hook bởi React Compiler. Directive này không có nghĩa là tồn tại lâu dài giống như [`"use client"`](/reference/rsc/use-client).
-It is not recommended to reach for this directive unless it's strictly necessary. Once you opt-out a component or hook, it is opted-out forever until the directive is removed. This means that even if you fix the code, the compiler will still skip over compiling it unless you remove the directive.
+Không nên sử dụng directive này trừ khi thực sự cần thiết. Khi bạn chọn không sử dụng một component hoặc hook, nó sẽ bị chọn không sử dụng vĩnh viễn cho đến khi directive bị xóa. Điều này có nghĩa là ngay cả khi bạn sửa code, trình biên dịch vẫn sẽ bỏ qua việc biên dịch nó trừ khi bạn xóa directive.
-When you make the error go away, confirm that removing the opt out directive makes the issue come back. Then share a bug report with us (you can try to reduce it to a small repro, or if it's open source code you can also just paste the entire source) using the [React Compiler Playground](https://playground.react.dev) so we can identify and help fix the issue.
+Khi bạn làm cho lỗi biến mất, hãy xác nhận rằng việc xóa directive chọn không sử dụng sẽ khiến sự cố quay trở lại. Sau đó, hãy chia sẻ báo cáo lỗi với chúng tôi (bạn có thể thử giảm nó xuống một bản repro nhỏ hoặc nếu đó là code nguồn mở, bạn cũng có thể chỉ cần dán toàn bộ source) bằng [React Compiler Playground](https://playground.react.dev) để chúng tôi có thể xác định và giúp khắc phục sự cố.
-### Other issues {/*other-issues*/}
+### Các vấn đề khác {/*other-issues*/}
-Please see https://github.com/reactwg/react-compiler/discussions/7.
+Vui lòng xem https://github.com/reactwg/react-compiler/discussions/7.
diff --git a/src/content/learn/reacting-to-input-with-state.md b/src/content/learn/reacting-to-input-with-state.md
index da559dc0f..aa010d16e 100644
--- a/src/content/learn/reacting-to-input-with-state.md
+++ b/src/content/learn/reacting-to-input-with-state.md
@@ -1,37 +1,37 @@
---
-title: Reacting to Input with State
+title: Phản hồi Đầu vào bằng State
---
-React provides a declarative way to manipulate the UI. Instead of manipulating individual pieces of the UI directly, you describe the different states that your component can be in, and switch between them in response to the user input. This is similar to how designers think about the UI.
+React cung cấp một cách khai báo để thao tác UI. Thay vì thao tác trực tiếp các phần tử UI riêng lẻ, bạn mô tả các trạng thái khác nhau mà component của bạn có thể ở và chuyển đổi giữa chúng để phản hồi đầu vào của người dùng. Điều này tương tự như cách các nhà thiết kế nghĩ về UI.
-* How declarative UI programming differs from imperative UI programming
-* How to enumerate the different visual states your component can be in
-* How to trigger the changes between the different visual states from code
+* Sự khác biệt giữa lập trình UI khai báo và lập trình UI mệnh lệnh
+* Cách liệt kê các trạng thái hiển thị khác nhau mà component của bạn có thể ở
+* Cách kích hoạt các thay đổi giữa các trạng thái hiển thị khác nhau từ code
-## How declarative UI compares to imperative {/*how-declarative-ui-compares-to-imperative*/}
+## So sánh UI khai báo với UI mệnh lệnh {/*how-declarative-ui-compares-to-imperative*/}
-When you design UI interactions, you probably think about how the UI *changes* in response to user actions. Consider a form that lets the user submit an answer:
+Khi bạn thiết kế các tương tác UI, bạn có thể nghĩ về cách UI *thay đổi* để phản hồi các hành động của người dùng. Hãy xem xét một biểu mẫu cho phép người dùng gửi câu trả lời:
-* When you type something into the form, the "Submit" button **becomes enabled.**
-* When you press "Submit", both the form and the button **become disabled,** and a spinner **appears.**
-* If the network request succeeds, the form **gets hidden,** and the "Thank you" message **appears.**
-* If the network request fails, an error message **appears,** and the form **becomes enabled** again.
+* Khi bạn nhập nội dung gì đó vào biểu mẫu, nút "Gửi" **sẽ được bật.**
+* Khi bạn nhấn "Gửi", cả biểu mẫu và nút **sẽ bị tắt,** và một spinner **xuất hiện.**
+* Nếu yêu cầu mạng thành công, biểu mẫu **sẽ bị ẩn,** và thông báo "Cảm ơn" **xuất hiện.**
+* Nếu yêu cầu mạng không thành công, một thông báo lỗi **xuất hiện,** và biểu mẫu **sẽ được bật** lại.
-In **imperative programming,** the above corresponds directly to how you implement interaction. You have to write the exact instructions to manipulate the UI depending on what just happened. Here's another way to think about this: imagine riding next to someone in a car and telling them turn by turn where to go.
+Trong **lập trình mệnh lệnh,** điều trên tương ứng trực tiếp với cách bạn triển khai tương tác. Bạn phải viết các hướng dẫn chính xác để thao tác UI tùy thuộc vào những gì vừa xảy ra. Đây là một cách khác để nghĩ về điều này: hãy tưởng tượng bạn đang đi cạnh ai đó trong xe hơi và chỉ cho họ từng ngã rẽ nơi cần đi.
-
+
-They don't know where you want to go, they just follow your commands. (And if you get the directions wrong, you end up in the wrong place!) It's called *imperative* because you have to "command" each element, from the spinner to the button, telling the computer *how* to update the UI.
+Họ không biết bạn muốn đi đâu, họ chỉ làm theo lệnh của bạn. (Và nếu bạn chỉ sai đường, bạn sẽ đến nhầm chỗ!) Nó được gọi là *mệnh lệnh* vì bạn phải "ra lệnh" cho từng phần tử, từ spinner đến nút, cho máy tính biết *cách* cập nhật UI.
-In this example of imperative UI programming, the form is built *without* React. It only uses the browser [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model):
+Trong ví dụ về lập trình UI mệnh lệnh này, biểu mẫu được xây dựng *không* có React. Nó chỉ sử dụng [DOM](https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model) của trình duyệt:
@@ -131,37 +131,37 @@ body { font-family: sans-serif; margin: 20px; padding: 0; }
-Manipulating the UI imperatively works well enough for isolated examples, but it gets exponentially more difficult to manage in more complex systems. Imagine updating a page full of different forms like this one. Adding a new UI element or a new interaction would require carefully checking all existing code to make sure you haven't introduced a bug (for example, forgetting to show or hide something).
+Thao tác UI một cách mệnh lệnh hoạt động đủ tốt cho các ví dụ riêng lẻ, nhưng nó trở nên khó quản lý hơn theo cấp số nhân trong các hệ thống phức tạp hơn. Hãy tưởng tượng việc cập nhật một trang đầy các biểu mẫu khác nhau như thế này. Việc thêm một phần tử UI mới hoặc một tương tác mới sẽ yêu cầu kiểm tra cẩn thận tất cả code hiện có để đảm bảo bạn không gây ra lỗi (ví dụ: quên hiển thị hoặc ẩn nội dung gì đó).
-React was built to solve this problem.
+React được xây dựng để giải quyết vấn đề này.
-In React, you don't directly manipulate the UI--meaning you don't enable, disable, show, or hide components directly. Instead, you **declare what you want to show,** and React figures out how to update the UI. Think of getting into a taxi and telling the driver where you want to go instead of telling them exactly where to turn. It's the driver's job to get you there, and they might even know some shortcuts you haven't considered!
+Trong React, bạn không thao tác trực tiếp UI--nghĩa là bạn không bật, tắt, hiển thị hoặc ẩn các component trực tiếp. Thay vào đó, bạn **khai báo những gì bạn muốn hiển thị,** và React sẽ tìm ra cách cập nhật UI. Hãy nghĩ đến việc bắt taxi và nói với tài xế nơi bạn muốn đến thay vì chỉ cho họ chính xác nơi cần rẽ. Công việc của tài xế là đưa bạn đến đó, và họ thậm chí có thể biết một số đường tắt mà bạn chưa xem xét!
-
+
-## Thinking about UI declaratively {/*thinking-about-ui-declaratively*/}
+## Tư duy về UI một cách khai báo {/*thinking-about-ui-declaratively*/}
-You've seen how to implement a form imperatively above. To better understand how to think in React, you'll walk through reimplementing this UI in React below:
+Bạn đã thấy cách triển khai một biểu mẫu một cách mệnh lệnh ở trên. Để hiểu rõ hơn về cách tư duy trong React, bạn sẽ thực hiện lại UI này trong React bên dưới:
-1. **Identify** your component's different visual states
-2. **Determine** what triggers those state changes
-3. **Represent** the state in memory using `useState`
-4. **Remove** any non-essential state variables
-5. **Connect** the event handlers to set the state
+1. **Xác định** các trạng thái hiển thị khác nhau của component của bạn
+2. **Xác định** điều gì kích hoạt những thay đổi trạng thái đó
+3. **Biểu diễn** trạng thái trong bộ nhớ bằng `useState`
+4. **Loại bỏ** bất kỳ biến trạng thái không cần thiết nào
+5. **Kết nối** các trình xử lý sự kiện để đặt trạng thái
-### Step 1: Identify your component's different visual states {/*step-1-identify-your-components-different-visual-states*/}
+### Bước 1: Xác định các trạng thái hiển thị khác nhau của component của bạn {/*step-1-identify-your-components-different-visual-states*/}
-In computer science, you may hear about a ["state machine"](https://en.wikipedia.org/wiki/Finite-state_machine) being in one of several “states”. If you work with a designer, you may have seen mockups for different "visual states". React stands at the intersection of design and computer science, so both of these ideas are sources of inspiration.
+Trong khoa học máy tính, bạn có thể nghe nói về một ["máy trạng thái"](https://en.wikipedia.org/wiki/Finite-state_machine) đang ở một trong số các "trạng thái". Nếu bạn làm việc với một nhà thiết kế, bạn có thể đã thấy các bản mô phỏng cho các "trạng thái hiển thị" khác nhau. React đứng ở giao điểm giữa thiết kế và khoa học máy tính, vì vậy cả hai ý tưởng này đều là nguồn cảm hứng.
-First, you need to visualize all the different "states" of the UI the user might see:
+Đầu tiên, bạn cần hình dung tất cả các "trạng thái" khác nhau của UI mà người dùng có thể thấy:
-* **Empty**: Form has a disabled "Submit" button.
-* **Typing**: Form has an enabled "Submit" button.
-* **Submitting**: Form is completely disabled. Spinner is shown.
-* **Success**: "Thank you" message is shown instead of a form.
-* **Error**: Same as Typing state, but with an extra error message.
+* **Trống**: Biểu mẫu có nút "Gửi" bị tắt.
+* **Đang nhập**: Biểu mẫu có nút "Gửi" được bật.
+* **Đang gửi**: Biểu mẫu hoàn toàn bị tắt. Spinner được hiển thị.
+* **Thành công**: Thông báo "Cảm ơn" được hiển thị thay vì biểu mẫu.
+* **Lỗi**: Giống như trạng thái Đang nhập, nhưng có thêm thông báo lỗi.
-Just like a designer, you'll want to "mock up" or create "mocks" for the different states before you add logic. For example, here is a mock for just the visual part of the form. This mock is controlled by a prop called `status` with a default value of `'empty'`:
+Giống như một nhà thiết kế, bạn sẽ muốn "mô phỏng" hoặc tạo "bản mô phỏng" cho các trạng thái khác nhau trước khi bạn thêm logic. Ví dụ: đây là bản mô phỏng chỉ cho phần hiển thị của biểu mẫu. Bản mô phỏng này được điều khiển bởi một prop có tên là `status` với giá trị mặc định là `'empty'`:
@@ -192,7 +192,7 @@ export default function Form({
-You could call that prop anything you like, the naming is not important. Try editing `status = 'empty'` to `status = 'success'` to see the success message appear. Mocking lets you quickly iterate on the UI before you wire up any logic. Here is a more fleshed out prototype of the same component, still "controlled" by the `status` prop:
+Bạn có thể gọi prop đó là bất cứ điều gì bạn thích, việc đặt tên không quan trọng. Hãy thử chỉnh sửa `status = 'empty'` thành `status = 'success'` để thấy thông báo thành công xuất hiện. Mô phỏng cho phép bạn nhanh chóng lặp lại trên UI trước khi bạn kết nối bất kỳ logic nào. Dưới đây là một nguyên mẫu đầy đủ hơn của cùng một component, vẫn "được điều khiển" bởi prop `status`:
@@ -240,9 +240,9 @@ export default function Form({
-#### Displaying many visual states at once {/*displaying-many-visual-states-at-once*/}
+#### Hiển thị nhiều trạng thái hiển thị cùng một lúc {/*displaying-many-visual-states-at-once*/}
-If a component has a lot of visual states, it can be convenient to show them all on one page:
+Nếu một component có nhiều trạng thái hiển thị, có thể thuận tiện để hiển thị tất cả chúng trên một trang:
@@ -307,61 +307,61 @@ body { margin: 0; }
-Pages like this are often called "living styleguides" or "storybooks".
+Các trang như thế này thường được gọi là "living styleguides" hoặc "storybooks".
-### Step 2: Determine what triggers those state changes {/*step-2-determine-what-triggers-those-state-changes*/}
+### Bước 2: Xác định điều gì kích hoạt những thay đổi trạng thái đó {/*step-2-determine-what-triggers-those-state-changes*/}
-You can trigger state updates in response to two kinds of inputs:
+Bạn có thể kích hoạt cập nhật trạng thái để phản hồi hai loại đầu vào:
-* **Human inputs,** like clicking a button, typing in a field, navigating a link.
-* **Computer inputs,** like a network response arriving, a timeout completing, an image loading.
+* **Đầu vào của con người,** như nhấp vào nút, nhập vào một trường, điều hướng một liên kết.
+* **Đầu vào của máy tính,** như phản hồi mạng đến, thời gian chờ hoàn thành, hình ảnh tải.
-In both cases, **you must set [state variables](/learn/state-a-components-memory#anatomy-of-usestate) to update the UI.** For the form you're developing, you will need to change state in response to a few different inputs:
+Trong cả hai trường hợp, **bạn phải đặt [biến trạng thái](/learn/state-a-components-memory#anatomy-of-usestate) để cập nhật UI.** Đối với biểu mẫu bạn đang phát triển, bạn sẽ cần thay đổi trạng thái để phản hồi một vài đầu vào khác nhau:
-* **Changing the text input** (human) should switch it from the *Empty* state to the *Typing* state or back, depending on whether the text box is empty or not.
-* **Clicking the Submit button** (human) should switch it to the *Submitting* state.
-* **Successful network response** (computer) should switch it to the *Success* state.
-* **Failed network response** (computer) should switch it to the *Error* state with the matching error message.
+* **Thay đổi đầu vào văn bản** (con người) sẽ chuyển nó từ trạng thái *Trống* sang trạng thái *Đang nhập* hoặc ngược lại, tùy thuộc vào việc hộp văn bản có trống hay không.
+* **Nhấp vào nút Gửi** (con người) sẽ chuyển nó sang trạng thái *Đang gửi*.
+* **Phản hồi mạng thành công** (máy tính) sẽ chuyển nó sang trạng thái *Thành công*.
+* **Phản hồi mạng không thành công** (máy tính) sẽ chuyển nó sang trạng thái *Lỗi* với thông báo lỗi phù hợp.
-Notice that human inputs often require [event handlers](/learn/responding-to-events)!
+Lưu ý rằng đầu vào của con người thường yêu cầu [trình xử lý sự kiện](/learn/responding-to-events)!
-To help visualize this flow, try drawing each state on paper as a labeled circle, and each change between two states as an arrow. You can sketch out many flows this way and sort out bugs long before implementation.
+Để giúp hình dung luồng này, hãy thử vẽ từng trạng thái trên giấy dưới dạng một vòng tròn được gắn nhãn và mỗi thay đổi giữa hai trạng thái dưới dạng một mũi tên. Bạn có thể phác thảo nhiều luồng theo cách này và sắp xếp các lỗi trước khi triển khai.
-
+
-Form states
+Trạng thái biểu mẫu
-### Step 3: Represent the state in memory with `useState` {/*step-3-represent-the-state-in-memory-with-usestate*/}
+### Bước 3: Biểu diễn trạng thái trong bộ nhớ bằng `useState` {/*step-3-represent-the-state-in-memory-with-usestate*/}
-Next you'll need to represent the visual states of your component in memory with [`useState`.](/reference/react/useState) Simplicity is key: each piece of state is a "moving piece", and **you want as few "moving pieces" as possible.** More complexity leads to more bugs!
+Tiếp theo, bạn sẽ cần biểu diễn các trạng thái hiển thị của component của bạn trong bộ nhớ bằng [`useState`.](/reference/react/useState) Sự đơn giản là chìa khóa: mỗi phần của trạng thái là một "mảnh ghép chuyển động" và **bạn muốn càng ít "mảnh ghép chuyển động" càng tốt.** Càng phức tạp thì càng có nhiều lỗi!
-Start with the state that *absolutely must* be there. For example, you'll need to store the `answer` for the input, and the `error` (if it exists) to store the last error:
+Bắt đầu với trạng thái *tuyệt đối phải* có ở đó. Ví dụ: bạn sẽ cần lưu trữ `answer` cho đầu vào và `error` (nếu có) để lưu trữ lỗi cuối cùng:
```js
const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
```
-Then, you'll need a state variable representing which one of the visual states that you want to display. There's usually more than a single way to represent that in memory, so you'll need to experiment with it.
+Sau đó, bạn sẽ cần một biến trạng thái đại diện cho một trong các trạng thái hiển thị mà bạn muốn hiển thị. Thường có nhiều hơn một cách để biểu diễn điều đó trong bộ nhớ, vì vậy bạn sẽ cần thử nghiệm với nó.
-If you struggle to think of the best way immediately, start by adding enough state that you're *definitely* sure that all the possible visual states are covered:
+Nếu bạn gặp khó khăn trong việc nghĩ ra cách tốt nhất ngay lập tức, hãy bắt đầu bằng cách thêm đủ trạng thái mà bạn *chắc chắn* rằng tất cả các trạng thái hiển thị có thể có đều được bao phủ:
```js
const [isEmpty, setIsEmpty] = useState(true);
@@ -371,19 +371,19 @@ const [isSuccess, setIsSuccess] = useState(false);
const [isError, setIsError] = useState(false);
```
-Your first idea likely won't be the best, but that's ok--refactoring state is a part of the process!
+Ý tưởng đầu tiên của bạn có thể không phải là tốt nhất, nhưng điều đó không sao--tái cấu trúc trạng thái là một phần của quy trình!
-### Step 4: Remove any non-essential state variables {/*step-4-remove-any-non-essential-state-variables*/}
+### Bước 4: Loại bỏ bất kỳ biến trạng thái không cần thiết nào {/*step-4-remove-any-non-essential-state-variables*/}
-You want to avoid duplication in the state content so you're only tracking what is essential. Spending a little time on refactoring your state structure will make your components easier to understand, reduce duplication, and avoid unintended meanings. Your goal is to **prevent the cases where the state in memory doesn't represent any valid UI that you'd want a user to see.** (For example, you never want to show an error message and disable the input at the same time, or the user won't be able to correct the error!)
+Bạn muốn tránh trùng lặp trong nội dung trạng thái để bạn chỉ theo dõi những gì cần thiết. Dành một chút thời gian để tái cấu trúc cấu trúc trạng thái của bạn sẽ giúp các component của bạn dễ hiểu hơn, giảm trùng lặp và tránh các ý nghĩa không mong muốn. Mục tiêu của bạn là **ngăn chặn các trường hợp trạng thái trong bộ nhớ không đại diện cho bất kỳ UI hợp lệ nào mà bạn muốn người dùng thấy.** (Ví dụ: bạn không bao giờ muốn hiển thị thông báo lỗi và tắt đầu vào cùng một lúc, nếu không người dùng sẽ không thể sửa lỗi!)
-Here are some questions you can ask about your state variables:
+Dưới đây là một số câu hỏi bạn có thể hỏi về các biến trạng thái của mình:
-* **Does this state cause a paradox?** For example, `isTyping` and `isSubmitting` can't both be `true`. A paradox usually means that the state is not constrained enough. There are four possible combinations of two booleans, but only three correspond to valid states. To remove the "impossible" state, you can combine these into a `status` that must be one of three values: `'typing'`, `'submitting'`, or `'success'`.
-* **Is the same information available in another state variable already?** Another paradox: `isEmpty` and `isTyping` can't be `true` at the same time. By making them separate state variables, you risk them going out of sync and causing bugs. Fortunately, you can remove `isEmpty` and instead check `answer.length === 0`.
-* **Can you get the same information from the inverse of another state variable?** `isError` is not needed because you can check `error !== null` instead.
+* **Trạng thái này có gây ra nghịch lý không?** Ví dụ: `isTyping` và `isSubmitting` không thể đồng thời là `true`. Một nghịch lý thường có nghĩa là trạng thái không đủ ràng buộc. Có bốn tổ hợp có thể có của hai boolean, nhưng chỉ ba tổ hợp tương ứng với các trạng thái hợp lệ. Để loại bỏ trạng thái "không thể", bạn có thể kết hợp chúng thành một `status` phải là một trong ba giá trị: `'typing'`, `'submitting'` hoặc `'success'`.
+* **Thông tin tương tự đã có trong một biến trạng thái khác chưa?** Một nghịch lý khác: `isEmpty` và `isTyping` không thể đồng thời là `true`. Bằng cách tạo chúng thành các biến trạng thái riêng biệt, bạn có nguy cơ chúng không đồng bộ và gây ra lỗi. May mắn thay, bạn có thể loại bỏ `isEmpty` và thay vào đó kiểm tra `answer.length === 0`.
+* **Bạn có thể nhận được thông tin tương tự từ nghịch đảo của một biến trạng thái khác không?** Không cần `isError` vì bạn có thể kiểm tra `error !== null` thay thế.
-After this clean-up, you're left with 3 (down from 7!) *essential* state variables:
+Sau khi dọn dẹp này, bạn còn lại 3 (giảm từ 7!) biến trạng thái *cần thiết*:
```js
const [answer, setAnswer] = useState('');
@@ -391,19 +391,19 @@ const [error, setError] = useState(null);
const [status, setStatus] = useState('typing'); // 'typing', 'submitting', or 'success'
```
-You know they are essential, because you can't remove any of them without breaking the functionality.
+Bạn biết chúng là cần thiết, vì bạn không thể loại bỏ bất kỳ biến nào trong số chúng mà không làm hỏng chức năng.
-#### Eliminating “impossible” states with a reducer {/*eliminating-impossible-states-with-a-reducer*/}
+#### Loại bỏ các trạng thái “không thể” bằng một reducer {/*eliminating-impossible-states-with-a-reducer*/}
-These three variables are a good enough representation of this form's state. However, there are still some intermediate states that don't fully make sense. For example, a non-null `error` doesn't make sense when `status` is `'success'`. To model the state more precisely, you can [extract it into a reducer.](/learn/extracting-state-logic-into-a-reducer) Reducers let you unify multiple state variables into a single object and consolidate all the related logic!
+Ba biến này là một biểu diễn đủ tốt về trạng thái của biểu mẫu này. Tuy nhiên, vẫn còn một số trạng thái trung gian không hoàn toàn có ý nghĩa. Ví dụ: `error` khác null không có ý nghĩa khi `status` là `'success'`. Để mô hình hóa trạng thái chính xác hơn, bạn có thể [trích xuất nó vào một reducer.](/learn/extracting-state-logic-into-a-reducer) Reducer cho phép bạn hợp nhất nhiều biến trạng thái thành một đối tượng duy nhất và hợp nhất tất cả logic liên quan!
-### Step 5: Connect the event handlers to set state {/*step-5-connect-the-event-handlers-to-set-state*/}
+### Bước 5: Kết nối các trình xử lý sự kiện để đặt trạng thái {/*step-5-connect-the-event-handlers-to-set-state*/}
-Lastly, create event handlers that update the state. Below is the final form, with all event handlers wired up:
+Cuối cùng, tạo các trình xử lý sự kiện để cập nhật trạng thái. Dưới đây là biểu mẫu cuối cùng, với tất cả các trình xử lý sự kiện được kết nối:
@@ -485,29 +485,27 @@ function submitForm(answer) {
-Although this code is longer than the original imperative example, it is much less fragile. Expressing all interactions as state changes lets you later introduce new visual states without breaking existing ones. It also lets you change what should be displayed in each state without changing the logic of the interaction itself.
+Mặc dù code này dài hơn ví dụ mệnh lệnh ban đầu, nhưng nó ít bị lỗi hơn nhiều. Việc thể hiện tất cả các tương tác như là các thay đổi trạng thái cho phép bạn giới thiệu các trạng thái hiển thị mới mà không làm hỏng các trạng thái hiện có. Nó cũng cho phép bạn thay đổi những gì sẽ được hiển thị trong mỗi trạng thái mà không thay đổi logic của chính tương tác đó.
-* Declarative programming means describing the UI for each visual state rather than micromanaging the UI (imperative).
-* When developing a component:
- 1. Identify all its visual states.
- 2. Determine the human and computer triggers for state changes.
- 3. Model the state with `useState`.
- 4. Remove non-essential state to avoid bugs and paradoxes.
- 5. Connect the event handlers to set state.
+* Lập trình khai báo có nghĩa là mô tả giao diện người dùng cho mỗi trạng thái hiển thị thay vì quản lý chi tiết giao diện người dùng (mệnh lệnh).
+* Khi phát triển một component:
+ 1. Xác định tất cả các trạng thái hiển thị của nó.
+ 2. Xác định các tác nhân kích hoạt thay đổi trạng thái từ con người và máy tính.
+ 3. Mô hình hóa trạng thái bằng `useState`.
+ 4. Loại bỏ trạng thái không cần thiết để tránh lỗi và nghịch lý.
+ 5. Kết nối các trình xử lý sự kiện để đặt trạng thái.
-
-
-#### Add and remove a CSS class {/*add-and-remove-a-css-class*/}
+#### Thêm và xóa một lớp CSS {/*add-and-remove-a-css-class*/}
-Make it so that clicking on the picture *removes* the `background--active` CSS class from the outer ``, but *adds* the `picture--active` class to the `
`. Clicking the background again should restore the original CSS classes.
+Làm cho việc nhấp vào hình ảnh *xóa* lớp CSS `background--active` khỏi `
` bên ngoài, nhưng *thêm* lớp `picture--active` vào `
`. Nhấp lại vào nền sẽ khôi phục các lớp CSS ban đầu.
-Visually, you should expect that clicking on the picture removes the purple background and highlights the picture border. Clicking outside the picture highlights the background, but removes the picture border highlight.
+Về mặt hình ảnh, bạn nên mong đợi rằng việc nhấp vào hình ảnh sẽ loại bỏ nền màu tím và làm nổi bật đường viền của hình ảnh. Nhấp vào bên ngoài hình ảnh sẽ làm nổi bật nền, nhưng loại bỏ điểm nổi bật của đường viền hình ảnh.
@@ -557,14 +555,14 @@ body { margin: 0; padding: 0; height: 250px; }
-This component has two visual states: when the image is active, and when the image is inactive:
+Component này có hai trạng thái hiển thị: khi hình ảnh hoạt động và khi hình ảnh không hoạt động:
-* When the image is active, the CSS classes are `background` and `picture picture--active`.
-* When the image is inactive, the CSS classes are `background background--active` and `picture`.
+* Khi hình ảnh hoạt động, các lớp CSS là `background` và `picture picture--active`.
+* Khi hình ảnh không hoạt động, các lớp CSS là `background background--active` và `picture`.
-A single boolean state variable is enough to remember whether the image is active. The original task was to remove or add CSS classes. However, in React you need to *describe* what you want to see rather than *manipulate* the UI elements. So you need to calculate both CSS classes based on the current state. You also need to [stop the propagation](/learn/responding-to-events#stopping-propagation) so that clicking the image doesn't register as a click on the background.
+Một biến trạng thái boolean duy nhất là đủ để ghi nhớ xem hình ảnh có hoạt động hay không. Nhiệm vụ ban đầu là xóa hoặc thêm các lớp CSS. Tuy nhiên, trong React, bạn cần *mô tả* những gì bạn muốn thấy thay vì *thao tác* các phần tử giao diện người dùng. Vì vậy, bạn cần tính toán cả hai lớp CSS dựa trên trạng thái hiện tại. Bạn cũng cần [ngăn chặn sự lan truyền](/learn/responding-to-events#stopping-propagation) để việc nhấp vào hình ảnh không được đăng ký là một cú nhấp vào nền.
-Verify that this version works by clicking the image and then outside of it:
+Xác minh rằng phiên bản này hoạt động bằng cách nhấp vào hình ảnh và sau đó bên ngoài nó:
@@ -631,7 +629,7 @@ body { margin: 0; padding: 0; height: 250px; }
-Alternatively, you could return two separate chunks of JSX:
+Ngoài ra, bạn có thể trả về hai đoạn JSX riêng biệt:
@@ -698,13 +696,13 @@ body { margin: 0; padding: 0; height: 250px; }
-Keep in mind that if two different JSX chunks describe the same tree, their nesting (first `` → first `
`) has to line up. Otherwise, toggling `isActive` would recreate the whole tree below and [reset its state.](/learn/preserving-and-resetting-state) This is why, if a similar JSX tree gets returned in both cases, it is better to write them as a single piece of JSX.
+Hãy nhớ rằng nếu hai đoạn JSX khác nhau mô tả cùng một cây, thì sự lồng nhau của chúng (thẻ `
` đầu tiên → thẻ `
` đầu tiên) phải thẳng hàng. Nếu không, việc chuyển đổi `isActive` sẽ tạo lại toàn bộ cây bên dưới và [đặt lại trạng thái của nó.](/learn/preserving-and-resetting-state) Đây là lý do tại sao, nếu một cây JSX tương tự được trả về trong cả hai trường hợp, thì tốt hơn là viết chúng dưới dạng một đoạn JSX duy nhất.
-#### Profile editor {/*profile-editor*/}
+#### Trình chỉnh sửa hồ sơ {/*profile-editor*/}
-Here is a small form implemented with plain JavaScript and DOM. Play with it to understand its behavior:
+Đây là một biểu mẫu nhỏ được triển khai bằng JavaScript và DOM thuần túy. Hãy chơi với nó để hiểu hành vi của nó:
@@ -801,11 +799,11 @@ label { display: block; margin-bottom: 20px; }
-This form switches between two modes: in the editing mode, you see the inputs, and in the viewing mode, you only see the result. The button label changes between "Edit" and "Save" depending on the mode you're in. When you change the inputs, the welcome message at the bottom updates in real time.
+Biểu mẫu này chuyển đổi giữa hai chế độ: ở chế độ chỉnh sửa, bạn thấy các trường nhập liệu và ở chế độ xem, bạn chỉ thấy kết quả. Nhãn nút thay đổi giữa "Chỉnh sửa" và "Lưu" tùy thuộc vào chế độ bạn đang ở. Khi bạn thay đổi các trường nhập liệu, thông báo chào mừng ở phía dưới sẽ cập nhật theo thời gian thực.
-Your task is to reimplement it in React in the sandbox below. For your convenience, the markup was already converted to JSX, but you'll need to make it show and hide the inputs like the original does.
+Nhiệm vụ của bạn là triển khai lại nó trong React trong sandbox bên dưới. Để thuận tiện cho bạn, đánh dấu đã được chuyển đổi sang JSX, nhưng bạn sẽ cần làm cho nó hiển thị và ẩn các trường nhập liệu như bản gốc.
-Make sure that it updates the text at the bottom, too!
+Đảm bảo rằng nó cũng cập nhật văn bản ở phía dưới!
@@ -840,9 +838,9 @@ label { display: block; margin-bottom: 20px; }
-You will need two state variables to hold the input values: `firstName` and `lastName`. You're also going to need an `isEditing` state variable that holds whether to display the inputs or not. You should _not_ need a `fullName` variable because the full name can always be calculated from the `firstName` and the `lastName`.
+Bạn sẽ cần hai biến trạng thái để giữ các giá trị đầu vào: `firstName` và `lastName`. Bạn cũng sẽ cần một biến trạng thái `isEditing` để biết có hiển thị các trường nhập liệu hay không. Bạn _không_ nên cần một biến `fullName` vì tên đầy đủ luôn có thể được tính từ `firstName` và `lastName`.
-Finally, you should use [conditional rendering](/learn/conditional-rendering) to show or hide the inputs depending on `isEditing`.
+Cuối cùng, bạn nên sử dụng [kết xuất có điều kiện](/learn/conditional-rendering) để hiển thị hoặc ẩn các trường nhập liệu tùy thuộc vào `isEditing`.
@@ -900,13 +898,13 @@ label { display: block; margin-bottom: 20px; }
-Compare this solution to the original imperative code. How are they different?
+So sánh giải pháp này với mã mệnh lệnh ban đầu. Chúng khác nhau như thế nào?
-#### Refactor the imperative solution without React {/*refactor-the-imperative-solution-without-react*/}
+#### Tái cấu trúc giải pháp mệnh lệnh mà không cần React {/*refactor-the-imperative-solution-without-react*/}
-Here is the original sandbox from the previous challenge, written imperatively without React:
+Đây là sandbox ban đầu từ thử thách trước, được viết theo kiểu mệnh lệnh mà không cần React:
@@ -1003,9 +1001,9 @@ label { display: block; margin-bottom: 20px; }
-Imagine React didn't exist. Can you refactor this code in a way that makes the logic less fragile and more similar to the React version? What would it look like if the state was explicit, like in React?
+Hãy tưởng tượng React không tồn tại. Bạn có thể tái cấu trúc mã này theo cách làm cho logic ít bị lỗi hơn và tương tự như phiên bản React hơn không? Nó sẽ trông như thế nào nếu trạng thái là rõ ràng, giống như trong React?
-If you're struggling to think where to start, the stub below already has most of the structure in place. If you start here, fill in the missing logic in the `updateDOM` function. (Refer to the original code where needed.)
+Nếu bạn đang gặp khó khăn trong việc suy nghĩ về nơi bắt đầu, thì đoạn mã dưới đây đã có hầu hết cấu trúc tại chỗ. Nếu bạn bắt đầu từ đây, hãy điền vào logic còn thiếu trong hàm `updateDOM`. (Tham khảo mã gốc khi cần.)
@@ -1228,8 +1226,7 @@ label { display: block; margin-bottom: 20px; }
```
-
-The `updateDOM` function you wrote shows what React does under the hood when you set the state. (However, React also avoids touching the DOM for properties that have not changed since the last time they were set.)
+Hàm `updateDOM` mà bạn đã viết cho thấy những gì React thực hiện bên dưới khi bạn đặt trạng thái. (Tuy nhiên, React cũng tránh chạm vào DOM đối với các thuộc tính không thay đổi kể từ lần cuối cùng chúng được đặt.)
diff --git a/src/content/learn/referencing-values-with-refs.md b/src/content/learn/referencing-values-with-refs.md
index 4faf18786..4c9eded9d 100644
--- a/src/content/learn/referencing-values-with-refs.md
+++ b/src/content/learn/referencing-values-with-refs.md
@@ -1,49 +1,49 @@
---
-title: 'Referencing Values with Refs'
+title: 'Tham chiếu các giá trị với Refs'
---
-When you want a component to "remember" some information, but you don't want that information to [trigger new renders](/learn/render-and-commit), you can use a *ref*.
+Khi bạn muốn một component "ghi nhớ" một số thông tin, nhưng bạn không muốn thông tin đó [kích hoạt các lần render mới](/learn/render-and-commit), bạn có thể sử dụng *ref*.
-- How to add a ref to your component
-- How to update a ref's value
-- How refs are different from state
-- How to use refs safely
+- Cách thêm một ref vào component của bạn
+- Cách cập nhật giá trị của một ref
+- Sự khác biệt giữa refs và state
+- Cách sử dụng refs một cách an toàn
-## Adding a ref to your component {/*adding-a-ref-to-your-component*/}
+## Thêm một ref vào component của bạn {/*adding-a-ref-to-your-component*/}
-You can add a ref to your component by importing the `useRef` Hook from React:
+Bạn có thể thêm một ref vào component của mình bằng cách import Hook `useRef` từ React:
```js
import { useRef } from 'react';
```
-Inside your component, call the `useRef` Hook and pass the initial value that you want to reference as the only argument. For example, here is a ref to the value `0`:
+Bên trong component của bạn, hãy gọi Hook `useRef` và truyền giá trị ban đầu mà bạn muốn tham chiếu làm đối số duy nhất. Ví dụ: đây là một ref đến giá trị `0`:
```js
const ref = useRef(0);
```
-`useRef` returns an object like this:
+`useRef` trả về một đối tượng như thế này:
```js
{
- current: 0 // The value you passed to useRef
+ current: 0 // Giá trị bạn đã truyền cho useRef
}
```
-
+
-You can access the current value of that ref through the `ref.current` property. This value is intentionally mutable, meaning you can both read and write to it. It's like a secret pocket of your component that React doesn't track. (This is what makes it an "escape hatch" from React's one-way data flow--more on that below!)
+Bạn có thể truy cập giá trị hiện tại của ref đó thông qua thuộc tính `ref.current`. Giá trị này có thể thay đổi một cách có chủ ý, có nghĩa là bạn có thể đọc và ghi vào nó. Nó giống như một túi bí mật của component mà React không theo dõi. (Đây là điều làm cho nó trở thành một "lối thoát" khỏi luồng dữ liệu một chiều của React--thêm về điều đó bên dưới!)
-Here, a button will increment `ref.current` on every click:
+Ở đây, một nút sẽ tăng `ref.current` trên mỗi lần nhấp:
@@ -55,12 +55,12 @@ export default function Counter() {
function handleClick() {
ref.current = ref.current + 1;
- alert('You clicked ' + ref.current + ' times!');
+ alert('Bạn đã nhấp ' + ref.current + ' lần!');
}
return (
- Click me!
+ Nhấp vào tôi!
);
}
@@ -68,20 +68,20 @@ export default function Counter() {
-The ref points to a number, but, like [state](/learn/state-a-components-memory), you could point to anything: a string, an object, or even a function. Unlike state, ref is a plain JavaScript object with the `current` property that you can read and modify.
+Ref trỏ đến một số, nhưng, giống như [state](/learn/state-a-components-memory), bạn có thể trỏ đến bất cứ thứ gì: một chuỗi, một đối tượng hoặc thậm chí một hàm. Không giống như state, ref là một đối tượng JavaScript thuần túy với thuộc tính `current` mà bạn có thể đọc và sửa đổi.
-Note that **the component doesn't re-render with every increment.** Like state, refs are retained by React between re-renders. However, setting state re-renders a component. Changing a ref does not!
+Lưu ý rằng **component không re-render với mỗi lần tăng.** Giống như state, refs được React giữ lại giữa các lần re-render. Tuy nhiên, việc đặt state sẽ re-render một component. Thay đổi một ref thì không!
-## Example: building a stopwatch {/*example-building-a-stopwatch*/}
+## Ví dụ: xây dựng đồng hồ bấm giờ {/*example-building-a-stopwatch*/}
-You can combine refs and state in a single component. For example, let's make a stopwatch that the user can start or stop by pressing a button. In order to display how much time has passed since the user pressed "Start", you will need to keep track of when the Start button was pressed and what the current time is. **This information is used for rendering, so you'll keep it in state:**
+Bạn có thể kết hợp refs và state trong một component duy nhất. Ví dụ: hãy tạo một đồng hồ bấm giờ mà người dùng có thể bắt đầu hoặc dừng bằng cách nhấn một nút. Để hiển thị thời gian đã trôi qua kể từ khi người dùng nhấn "Bắt đầu", bạn sẽ cần theo dõi thời điểm nút Bắt đầu được nhấn và thời gian hiện tại là bao nhiêu. **Thông tin này được sử dụng để render, vì vậy bạn sẽ giữ nó trong state:**
```js
const [startTime, setStartTime] = useState(null);
const [now, setNow] = useState(null);
```
-When the user presses "Start", you'll use [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval) in order to update the time every 10 milliseconds:
+Khi người dùng nhấn "Bắt đầu", bạn sẽ sử dụng [`setInterval`](https://developer.mozilla.org/docs/Web/API/setInterval) để cập nhật thời gian sau mỗi 10 mili giây:
@@ -93,12 +93,12 @@ export default function Stopwatch() {
const [now, setNow] = useState(null);
function handleStart() {
- // Start counting.
+ // Bắt đầu đếm.
setStartTime(Date.now());
setNow(Date.now());
setInterval(() => {
- // Update the current time every 10ms.
+ // Cập nhật thời gian hiện tại sau mỗi 10ms.
setNow(Date.now());
}, 10);
}
@@ -110,9 +110,9 @@ export default function Stopwatch() {
return (
<>
- Time passed: {secondsPassed.toFixed(3)}
+ Thời gian đã trôi qua: {secondsPassed.toFixed(3)}
- Start
+ Bắt đầu
>
);
@@ -121,7 +121,7 @@ export default function Stopwatch() {
-When the "Stop" button is pressed, you need to cancel the existing interval so that it stops updating the `now` state variable. You can do this by calling [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), but you need to give it the interval ID that was previously returned by the `setInterval` call when the user pressed Start. You need to keep the interval ID somewhere. **Since the interval ID is not used for rendering, you can keep it in a ref:**
+Khi nút "Dừng" được nhấn, bạn cần hủy interval hiện có để nó ngừng cập nhật biến state `now`. Bạn có thể thực hiện việc này bằng cách gọi [`clearInterval`](https://developer.mozilla.org/en-US/docs/Web/API/clearInterval), nhưng bạn cần cung cấp cho nó ID interval đã được trả về trước đó bởi lệnh gọi `setInterval` khi người dùng nhấn Bắt đầu. Bạn cần giữ ID interval ở đâu đó. **Vì ID interval không được sử dụng để render, bạn có thể giữ nó trong một ref:**
@@ -154,12 +154,12 @@ export default function Stopwatch() {
return (
<>
- Time passed: {secondsPassed.toFixed(3)}
+ Thời gian đã trôi qua: {secondsPassed.toFixed(3)}
- Start
+ Bắt đầu
- Stop
+ Dừng
>
);
@@ -168,20 +168,20 @@ export default function Stopwatch() {
-When a piece of information is used for rendering, keep it in state. When a piece of information is only needed by event handlers and changing it doesn't require a re-render, using a ref may be more efficient.
+Khi một phần thông tin được sử dụng để render, hãy giữ nó trong state. Khi một phần thông tin chỉ cần thiết cho các trình xử lý sự kiện và việc thay đổi nó không yêu cầu re-render, thì việc sử dụng ref có thể hiệu quả hơn.
-## Differences between refs and state {/*differences-between-refs-and-state*/}
+## Sự khác biệt giữa refs và state {/*differences-between-refs-and-state*/}
-Perhaps you're thinking refs seem less "strict" than state—you can mutate them instead of always having to use a state setting function, for instance. But in most cases, you'll want to use state. Refs are an "escape hatch" you won't need often. Here's how state and refs compare:
+Có lẽ bạn đang nghĩ rằng refs có vẻ ít "nghiêm ngặt" hơn state—ví dụ: bạn có thể thay đổi chúng thay vì luôn phải sử dụng một hàm thiết lập state. Nhưng trong hầu hết các trường hợp, bạn sẽ muốn sử dụng state. Refs là một "lối thoát" mà bạn sẽ không cần thường xuyên. Đây là cách so sánh state và refs:
| refs | state |
| ------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
-| `useRef(initialValue)` returns `{ current: initialValue }` | `useState(initialValue)` returns the current value of a state variable and a state setter function ( `[value, setValue]`) |
-| Doesn't trigger re-render when you change it. | Triggers re-render when you change it. |
-| Mutable—you can modify and update `current`'s value outside of the rendering process. | "Immutable"—you must use the state setting function to modify state variables to queue a re-render. |
-| You shouldn't read (or write) the `current` value during rendering. | You can read state at any time. However, each render has its own [snapshot](/learn/state-as-a-snapshot) of state which does not change.
+| `useRef(initialValue)` trả về `{ current: initialValue }` | `useState(initialValue)` trả về giá trị hiện tại của một biến state và một hàm thiết lập state ( `[value, setValue]`) |
+| Không kích hoạt re-render khi bạn thay đổi nó. | Kích hoạt re-render khi bạn thay đổi nó. |
+| Có thể thay đổi—bạn có thể sửa đổi và cập nhật giá trị của `current` bên ngoài quá trình render. | "Bất biến"—bạn phải sử dụng hàm thiết lập state để sửa đổi các biến state để xếp hàng đợi re-render. |
+| Bạn không nên đọc (hoặc ghi) giá trị `current` trong quá trình render. | Bạn có thể đọc state bất cứ lúc nào. Tuy nhiên, mỗi lần render có [ảnh chụp nhanh](/learn/state-as-a-snapshot) riêng của state mà không thay đổi.
-Here is a counter button that's implemented with state:
+Đây là một nút đếm được triển khai bằng state:
@@ -197,7 +197,7 @@ export default function Counter() {
return (
- You clicked {count} times
+ Bạn đã nhấp {count} lần
);
}
@@ -205,9 +205,9 @@ export default function Counter() {
-Because the `count` value is displayed, it makes sense to use a state value for it. When the counter's value is set with `setCount()`, React re-renders the component and the screen updates to reflect the new count.
+Vì giá trị `count` được hiển thị, nên việc sử dụng giá trị state cho nó là hợp lý. Khi giá trị của bộ đếm được đặt bằng `setCount()`, React sẽ re-render component và màn hình sẽ cập nhật để phản ánh số lượng mới.
-If you tried to implement this with a ref, React would never re-render the component, so you'd never see the count change! See how clicking this button **does not update its text**:
+Nếu bạn cố gắng triển khai điều này với một ref, React sẽ không bao giờ re-render component, vì vậy bạn sẽ không bao giờ thấy số lượng thay đổi! Xem cách nhấp vào nút này **không cập nhật văn bản của nó**:
@@ -218,13 +218,13 @@ export default function Counter() {
let countRef = useRef(0);
function handleClick() {
- // This doesn't re-render the component!
+ // Điều này không re-render component!
countRef.current = countRef.current + 1;
}
return (
- You clicked {countRef.current} times
+ Bạn đã nhấp {countRef.current} lần
);
}
@@ -232,82 +232,80 @@ export default function Counter() {
-This is why reading `ref.current` during render leads to unreliable code. If you need that, use state instead.
+Đây là lý do tại sao việc đọc `ref.current` trong quá trình render dẫn đến mã không đáng tin cậy. Nếu bạn cần điều đó, hãy sử dụng state thay thế.
-#### How does useRef work inside? {/*how-does-use-ref-work-inside*/}
+#### useRef hoạt động như thế nào bên trong? {/*how-does-use-ref-work-inside*/}
-Although both `useState` and `useRef` are provided by React, in principle `useRef` could be implemented _on top of_ `useState`. You can imagine that inside of React, `useRef` is implemented like this:
+Mặc dù cả `useState` và `useRef` đều được cung cấp bởi React, nhưng về nguyên tắc, `useRef` có thể được triển khai _trên_ `useState`. Bạn có thể tưởng tượng rằng bên trong React, `useRef` được triển khai như thế này:
```js
-// Inside of React
+// Bên trong React
function useRef(initialValue) {
const [ref, unused] = useState({ current: initialValue });
return ref;
}
```
-During the first render, `useRef` returns `{ current: initialValue }`. This object is stored by React, so during the next render the same object will be returned. Note how the state setter is unused in this example. It is unnecessary because `useRef` always needs to return the same object!
+Trong lần render đầu tiên, `useRef` trả về `{ current: initialValue }`. Đối tượng này được React lưu trữ, vì vậy trong lần render tiếp theo, cùng một đối tượng sẽ được trả về. Lưu ý cách setter state không được sử dụng trong ví dụ này. Nó là không cần thiết vì `useRef` luôn cần trả về cùng một đối tượng!
-React provides a built-in version of `useRef` because it is common enough in practice. But you can think of it as a regular state variable without a setter. If you're familiar with object-oriented programming, refs might remind you of instance fields--but instead of `this.something` you write `somethingRef.current`.
+React cung cấp một phiên bản tích hợp của `useRef` vì nó đủ phổ biến trong thực tế. Nhưng bạn có thể coi nó như một biến state thông thường mà không có setter. Nếu bạn quen thuộc với lập trình hướng đối tượng, refs có thể nhắc bạn về các trường instance--nhưng thay vì `this.something`, bạn viết `somethingRef.current`.
-## When to use refs {/*when-to-use-refs*/}
+## Khi nào nên sử dụng refs {/*when-to-use-refs*/}
-Typically, you will use a ref when your component needs to "step outside" React and communicate with external APIs—often a browser API that won't impact the appearance of the component. Here are a few of these rare situations:
+Thông thường, bạn sẽ sử dụng ref khi component của bạn cần "bước ra ngoài" React và giao tiếp với các API bên ngoài—thường là một API trình duyệt sẽ không ảnh hưởng đến giao diện của component. Dưới đây là một vài trong số những tình huống hiếm gặp này:
-- Storing [timeout IDs](https://developer.mozilla.org/docs/Web/API/setTimeout)
-- Storing and manipulating [DOM elements](https://developer.mozilla.org/docs/Web/API/Element), which we cover on [the next page](/learn/manipulating-the-dom-with-refs)
-- Storing other objects that aren't necessary to calculate the JSX.
+- Lưu trữ [ID timeout](https://developer.mozilla.org/docs/Web/API/setTimeout)
+- Lưu trữ và thao tác [các phần tử DOM](https://developer.mozilla.org/docs/Web/API/Element), mà chúng ta sẽ đề cập trên [trang tiếp theo](/learn/manipulating-the-dom-with-refs)
+- Lưu trữ các đối tượng khác không cần thiết để tính toán JSX.
-If your component needs to store some value, but it doesn't impact the rendering logic, choose refs.
+Nếu component của bạn cần lưu trữ một số giá trị, nhưng nó không ảnh hưởng đến logic render, hãy chọn refs.
-## Best practices for refs {/*best-practices-for-refs*/}
+## Các phương pháp hay nhất cho refs {/*best-practices-for-refs*/}
-Following these principles will make your components more predictable:
+Tuân theo các nguyên tắc này sẽ làm cho các component của bạn dễ đoán hơn:
-- **Treat refs as an escape hatch.** Refs are useful when you work with external systems or browser APIs. If much of your application logic and data flow relies on refs, you might want to rethink your approach.
-- **Don't read or write `ref.current` during rendering.** If some information is needed during rendering, use [state](/learn/state-a-components-memory) instead. Since React doesn't know when `ref.current` changes, even reading it while rendering makes your component's behavior difficult to predict. (The only exception to this is code like `if (!ref.current) ref.current = new Thing()` which only sets the ref once during the first render.)
+- **Coi refs như một lối thoát.** Refs rất hữu ích khi bạn làm việc với các hệ thống bên ngoài hoặc API trình duyệt. Nếu phần lớn logic ứng dụng và luồng dữ liệu của bạn dựa vào refs, bạn có thể muốn xem xét lại cách tiếp cận của mình.
+- **Không đọc hoặc ghi `ref.current` trong quá trình render.** Nếu một số thông tin là cần thiết trong quá trình render, hãy sử dụng [state](/learn/state-a-components-memory) thay thế. Vì React không biết khi nào `ref.current` thay đổi, ngay cả việc đọc nó trong khi render cũng khiến hành vi của component của bạn khó dự đoán. (Ngoại lệ duy nhất cho điều này là mã như `if (!ref.current) ref.current = new Thing()` chỉ đặt ref một lần trong lần render đầu tiên.)
-Limitations of React state don't apply to refs. For example, state acts like a [snapshot for every render](/learn/state-as-a-snapshot) and [doesn't update synchronously.](/learn/queueing-a-series-of-state-updates) But when you mutate the current value of a ref, it changes immediately:
+Các hạn chế của state React không áp dụng cho refs. Ví dụ: state hoạt động như một [ảnh chụp nhanh cho mỗi lần render](/learn/state-as-a-snapshot) và [không cập nhật đồng bộ.](/learn/queueing-a-series-of-state-updates) Nhưng khi bạn thay đổi giá trị hiện tại của một ref, nó sẽ thay đổi ngay lập tức:
```js
ref.current = 5;
console.log(ref.current); // 5
```
-This is because **the ref itself is a regular JavaScript object,** and so it behaves like one.
+Điều này là do **bản thân ref là một đối tượng JavaScript thông thường,** và do đó nó hoạt động như một đối tượng.
-You also don't need to worry about [avoiding mutation](/learn/updating-objects-in-state) when you work with a ref. As long as the object you're mutating isn't used for rendering, React doesn't care what you do with the ref or its contents.
+Bạn cũng không cần phải lo lắng về việc [tránh đột biến](/learn/updating-objects-in-state) khi bạn làm việc với một ref. Miễn là đối tượng bạn đang đột biến không được sử dụng để render, React không quan tâm bạn làm gì với ref hoặc nội dung của nó.
-## Refs and the DOM {/*refs-and-the-dom*/}
+## Refs và DOM {/*refs-and-the-dom*/}
-You can point a ref to any value. However, the most common use case for a ref is to access a DOM element. For example, this is handy if you want to focus an input programmatically. When you pass a ref to a `ref` attribute in JSX, like ``, React will put the corresponding DOM element into `myRef.current`. Once the element is removed from the DOM, React will update `myRef.current` to be `null`. You can read more about this in [Manipulating the DOM with Refs.](/learn/manipulating-the-dom-with-refs)
+Bạn có thể trỏ một ref đến bất kỳ giá trị nào. Tuy nhiên, trường hợp sử dụng phổ biến nhất cho một ref là truy cập một phần tử DOM. Ví dụ: điều này rất hữu ích nếu bạn muốn tập trung vào một đầu vào theo chương trình. Khi bạn chuyển một ref đến một thuộc tính `ref` trong JSX, như `
`, React sẽ đặt phần tử DOM tương ứng vào `myRef.current`. Khi phần tử bị xóa khỏi DOM, React sẽ cập nhật `myRef.current` thành `null`. Bạn có thể đọc thêm về điều này trong [Thao tác DOM với Refs.](/learn/manipulating-the-dom-with-refs)
-- Refs are an escape hatch to hold onto values that aren't used for rendering. You won't need them often.
-- A ref is a plain JavaScript object with a single property called `current`, which you can read or set.
-- You can ask React to give you a ref by calling the `useRef` Hook.
-- Like state, refs let you retain information between re-renders of a component.
-- Unlike state, setting the ref's `current` value does not trigger a re-render.
-- Don't read or write `ref.current` during rendering. This makes your component hard to predict.
+- Refs là một lối thoát để giữ các giá trị không được sử dụng để render. Bạn sẽ không cần chúng thường xuyên.
+- Một ref là một đối tượng JavaScript thuần túy với một thuộc tính duy nhất có tên là `current`, mà bạn có thể đọc hoặc đặt.
+- Bạn có thể yêu cầu React cung cấp cho bạn một ref bằng cách gọi Hook `useRef`.
+- Giống như state, refs cho phép bạn giữ lại thông tin giữa các lần re-render của một component.
+- Không giống như state, việc đặt giá trị `current` của ref không kích hoạt re-render.
+- Không đọc hoặc ghi `ref.current` trong quá trình render. Điều này làm cho component của bạn khó dự đoán.
-
-
-#### Fix a broken chat input {/*fix-a-broken-chat-input*/}
+#### Sửa một đầu vào trò chuyện bị hỏng {/*fix-a-broken-chat-input*/}
-Type a message and click "Send". You will notice there is a three second delay before you see the "Sent!" alert. During this delay, you can see an "Undo" button. Click it. This "Undo" button is supposed to stop the "Sent!" message from appearing. It does this by calling [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) for the timeout ID saved during `handleSend`. However, even after "Undo" is clicked, the "Sent!" message still appears. Find why it doesn't work, and fix it.
+Nhập một tin nhắn và nhấp vào "Gửi". Bạn sẽ nhận thấy có một độ trễ ba giây trước khi bạn thấy cảnh báo "Đã gửi!". Trong thời gian trễ này, bạn có thể thấy nút "Hoàn tác". Nhấp vào nó. Nút "Hoàn tác" này được cho là để ngăn thông báo "Đã gửi!" xuất hiện. Nó thực hiện điều này bằng cách gọi [`clearTimeout`](https://developer.mozilla.org/en-US/docs/Web/API/clearTimeout) cho ID timeout được lưu trong `handleSend`. Tuy nhiên, ngay cả sau khi nhấp vào "Hoàn tác", thông báo "Đã gửi!" vẫn xuất hiện. Tìm lý do tại sao nó không hoạt động và sửa nó.
-Regular variables like `let timeoutID` don't "survive" between re-renders because every render runs your component (and initializes its variables) from scratch. Should you keep the timeout ID somewhere else?
+Các biến thông thường như `let timeoutID` không "sống sót" giữa các lần re-render vì mỗi lần render chạy component của bạn (và khởi tạo các biến của nó) từ đầu. Bạn có nên giữ ID timeout ở một nơi khác không?
@@ -324,7 +322,7 @@ export default function Chat() {
function handleSend() {
setIsSending(true);
timeoutID = setTimeout(() => {
- alert('Sent!');
+ alert('Đã gửi!');
setIsSending(false);
}, 3000);
}
@@ -344,11 +342,11 @@ export default function Chat() {
- {isSending ? 'Sending...' : 'Send'}
+ {isSending ? 'Đang gửi...' : 'Gửi'}
{isSending &&
- Undo
+ Hoàn tác
}
>
@@ -360,7 +358,7 @@ export default function Chat() {
-Whenever your component re-renders (such as when you set state), all local variables get initialized from scratch. This is why you can't save the timeout ID in a local variable like `timeoutID` and then expect another event handler to "see" it in the future. Instead, store it in a ref, which React will preserve between renders.
+Bất cứ khi nào component của bạn re-render (chẳng hạn như khi bạn đặt state), tất cả các biến cục bộ sẽ được khởi tạo từ đầu. Đây là lý do tại sao bạn không thể lưu ID timeout trong một biến cục bộ như `timeoutID` và sau đó mong đợi một trình xử lý sự kiện khác "nhìn thấy" nó trong tương lai. Thay vào đó, hãy lưu trữ nó trong một ref, mà React sẽ giữ lại giữa các lần render.
@@ -375,7 +373,7 @@ export default function Chat() {
function handleSend() {
setIsSending(true);
timeoutRef.current = setTimeout(() => {
- alert('Sent!');
+ alert('Đã gửi!');
setIsSending(false);
}, 3000);
}
@@ -395,11 +393,11 @@ export default function Chat() {
- {isSending ? 'Sending...' : 'Send'}
+ {isSending ? 'Đang gửi...' : 'Gửi'}
{isSending &&
- Undo
+ Hoàn tác
}
>
@@ -411,10 +409,9 @@ export default function Chat() {
+#### Sửa một component không re-render {/*fix-a-component-failing-to-re-render*/}
-#### Fix a component failing to re-render {/*fix-a-component-failing-to-re-render*/}
-
-This button is supposed to toggle between showing "On" and "Off". However, it always shows "Off". What is wrong with this code? Fix it.
+Nút này được cho là chuyển đổi giữa hiển thị "Bật" và "Tắt". Tuy nhiên, nó luôn hiển thị "Tắt". Có gì sai với mã này? Sửa nó.
@@ -428,7 +425,7 @@ export default function Toggle() {
{
isOnRef.current = !isOnRef.current;
}}>
- {isOnRef.current ? 'On' : 'Off'}
+ {isOnRef.current ? 'Bật' : 'Tắt'}
);
}
@@ -438,7 +435,7 @@ export default function Toggle() {
-In this example, the current value of a ref is used to calculate the rendering output: `{isOnRef.current ? 'On' : 'Off'}`. This is a sign that this information should not be in a ref, and should have instead been put in state. To fix it, remove the ref and use state instead:
+Trong ví dụ này, giá trị hiện tại của một ref được sử dụng để tính toán đầu ra render: `{isOnRef.current ? 'Bật' : 'Tắt'}`. Đây là một dấu hiệu cho thấy thông tin này không nên ở trong một ref, và thay vào đó nên được đưa vào state. Để sửa nó, hãy xóa ref và sử dụng state thay thế:
@@ -452,7 +449,7 @@ export default function Toggle() {
{
setIsOn(!isOn);
}}>
- {isOn ? 'On' : 'Off'}
+ {isOn ? 'Bật' : 'Tắt'}
);
}
@@ -462,17 +459,17 @@ export default function Toggle() {
-#### Fix debouncing {/*fix-debouncing*/}
+#### Sửa lỗi debouncing {/*fix-debouncing*/}
-In this example, all button click handlers are ["debounced".](https://redd.one/blog/debounce-vs-throttle) To see what this means, press one of the buttons. Notice how the message appears a second later. If you press the button while waiting for the message, the timer will reset. So if you keep clicking the same button fast many times, the message won't appear until a second *after* you stop clicking. Debouncing lets you delay some action until the user "stops doing things".
+Trong ví dụ này, tất cả các trình xử lý nhấp vào nút đều được ["debounced".](https://redd.one/blog/debounce-vs-throttle) Để xem điều này có nghĩa là gì, hãy nhấn một trong các nút. Lưu ý cách thông báo xuất hiện một giây sau đó. Nếu bạn nhấn nút trong khi chờ thông báo, bộ hẹn giờ sẽ đặt lại. Vì vậy, nếu bạn tiếp tục nhấp vào cùng một nút nhanh nhiều lần, thông báo sẽ không xuất hiện cho đến một giây *sau khi* bạn ngừng nhấp. Debouncing cho phép bạn trì hoãn một số hành động cho đến khi người dùng "ngừng làm mọi thứ".
-This example works, but not quite as intended. The buttons are not independent. To see the problem, click one of the buttons, and then immediately click another button. You'd expect that after a delay, you would see both button's messages. But only the last button's message shows up. The first button's message gets lost.
+Ví dụ này hoạt động, nhưng không hoàn toàn như dự định. Các nút không độc lập. Để xem sự cố, hãy nhấp vào một trong các nút, sau đó nhấp ngay vào một nút khác. Bạn sẽ mong đợi rằng sau một thời gian trễ, bạn sẽ thấy thông báo của cả hai nút. Nhưng chỉ có thông báo của nút cuối cùng hiển thị. Thông báo của nút đầu tiên bị mất.
-Why are the buttons interfering with each other? Find and fix the issue.
+Tại sao các nút lại can thiệp lẫn nhau? Tìm và sửa sự cố.
-The last timeout ID variable is shared between all `DebouncedButton` components. This is why clicking one button resets another button's timeout. Can you store a separate timeout ID for each button?
+Biến ID timeout cuối cùng được chia sẻ giữa tất cả các component `DebouncedButton`. Đây là lý do tại sao việc nhấp vào một nút sẽ đặt lại timeout của một nút khác. Bạn có thể lưu trữ một ID timeout riêng cho mỗi nút không?
@@ -498,19 +495,19 @@ export default function Dashboard() {
return (
<>
alert('Spaceship launched!')}
+ onClick={() => alert('Tàu vũ trụ đã được phóng!')}
>
- Launch the spaceship
+ Phóng tàu vũ trụ
alert('Soup boiled!')}
+ onClick={() => alert('Súp đã được đun sôi!')}
>
- Boil the soup
+ Đun sôi súp
alert('Lullaby sung!')}
+ onClick={() => alert('Bài hát ru đã được hát!')}
>
- Sing a lullaby
+ Hát một bài hát ru
>
)
@@ -525,7 +522,7 @@ button { display: block; margin: 10px; }
-A variable like `timeoutID` is shared between all components. This is why clicking on the second button resets the first button's pending timeout. To fix this, you can keep timeout in a ref. Each button will get its own ref, so they won't conflict with each other. Notice how clicking two buttons fast will show both messages.
+Một biến như `timeoutID` được chia sẻ giữa tất cả các component. Đây là lý do tại sao việc nhấp vào nút thứ hai sẽ đặt lại timeout đang chờ xử lý của nút đầu tiên. Để sửa lỗi này, bạn có thể giữ timeout trong một ref. Mỗi nút sẽ nhận được ref riêng, vì vậy chúng sẽ không xung đột với nhau. Lưu ý cách nhấp vào hai nút nhanh sẽ hiển thị cả hai thông báo.
@@ -550,19 +547,19 @@ export default function Dashboard() {
return (
<>
alert('Spaceship launched!')}
+ onClick={() => alert('Tàu vũ trụ đã được phóng!')}
>
- Launch the spaceship
+ Phóng tàu vũ trụ
alert('Soup boiled!')}
+ onClick={() => alert('Súp đã được đun sôi!')}
>
- Boil the soup
+ Đun sôi súp
alert('Lullaby sung!')}
+ onClick={() => alert('Bài hát ru đã được hát!')}
>
- Sing a lullaby
+ Hát một bài hát ru
>
)
@@ -577,11 +574,11 @@ button { display: block; margin: 10px; }
-#### Read the latest state {/*read-the-latest-state*/}
+#### Đọc state mới nhất {/*read-the-latest-state*/}
-In this example, after you press "Send", there is a small delay before the message is shown. Type "hello", press Send, and then quickly edit the input again. Despite your edits, the alert would still show "hello" (which was the value of state [at the time](/learn/state-as-a-snapshot#state-over-time) the button was clicked).
+Trong ví dụ này, sau khi bạn nhấn "Gửi", có một độ trễ nhỏ trước khi thông báo được hiển thị. Nhập "xin chào", nhấn Gửi, và sau đó nhanh chóng chỉnh sửa lại đầu vào. Mặc dù bạn đã chỉnh sửa, cảnh báo vẫn sẽ hiển thị "xin chào" (đó là giá trị của state [vào thời điểm](/learn/state-as-a-snapshot#state-over-time) nút được nhấp).
-Usually, this behavior is what you want in an app. However, there may be occasional cases where you want some asynchronous code to read the *latest* version of some state. Can you think of a way to make the alert show the *current* input text rather than what it was at the time of the click?
+Thông thường, hành vi này là những gì bạn muốn trong một ứng dụng. Tuy nhiên, có thể có những trường hợp bạn muốn một số mã không đồng bộ đọc phiên bản *mới nhất* của một số state. Bạn có thể nghĩ ra cách nào để làm cho cảnh báo hiển thị văn bản đầu vào *hiện tại* thay vì những gì nó đã có tại thời điểm nhấp không?
@@ -593,7 +590,7 @@ export default function Chat() {
function handleSend() {
setTimeout(() => {
- alert('Sending: ' + text);
+ alert('Đang gửi: ' + text);
}, 3000);
}
@@ -605,7 +602,7 @@ export default function Chat() {
/>
- Send
+ Gửi
>
);
@@ -616,7 +613,7 @@ export default function Chat() {
-State works [like a snapshot](/learn/state-as-a-snapshot), so you can't read the latest state from an asynchronous operation like a timeout. However, you can keep the latest input text in a ref. A ref is mutable, so you can read the `current` property at any time. Since the current text is also used for rendering, in this example, you will need *both* a state variable (for rendering), *and* a ref (to read it in the timeout). You will need to update the current ref value manually.
+State hoạt động [giống như một ảnh chụp nhanh](/learn/state-as-a-snapshot), vì vậy bạn không thể đọc state mới nhất từ một thao tác không đồng bộ như timeout. Tuy nhiên, bạn có thể giữ văn bản đầu vào mới nhất trong một ref. Một ref có thể thay đổi, vì vậy bạn có thể đọc thuộc tính `current` bất cứ lúc nào. Vì văn bản hiện tại cũng được sử dụng để render, trong ví dụ này, bạn sẽ cần *cả* một biến state (để render), *và* một ref (để đọc nó trong timeout). Bạn sẽ cần cập nhật giá trị ref hiện tại theo cách thủ công.
@@ -634,7 +631,7 @@ export default function Chat() {
function handleSend() {
setTimeout(() => {
- alert('Sending: ' + textRef.current);
+ alert('Đang gửi: ' + textRef.current);
}, 3000);
}
@@ -646,7 +643,7 @@ export default function Chat() {
/>
- Send
+ Gửi
>
);
diff --git a/src/content/learn/rendering-lists.md b/src/content/learn/rendering-lists.md
index 32f81c447..f7d9f0821 100644
--- a/src/content/learn/rendering-lists.md
+++ b/src/content/learn/rendering-lists.md
@@ -3,72 +3,71 @@ title: Rendering Lists
---
-
-You will often want to display multiple similar components from a collection of data. You can use the [JavaScript array methods](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#) to manipulate an array of data. On this page, you'll use [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) and [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) with React to filter and transform your array of data into an array of components.
+Bạn thường muốn hiển thị nhiều component tương tự từ một tập hợp dữ liệu. Bạn có thể sử dụng [các phương thức mảng JavaScript](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array#) để thao tác với một mảng dữ liệu. Trên trang này, bạn sẽ sử dụng [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) và [`map()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/map) với React để lọc và chuyển đổi mảng dữ liệu của bạn thành một mảng các component.
-* How to render components from an array using JavaScript's `map()`
-* How to render only specific components using JavaScript's `filter()`
-* When and why to use React keys
+* Cách hiển thị các component từ một mảng bằng cách sử dụng `map()` của JavaScript
+* Cách chỉ hiển thị các component cụ thể bằng cách sử dụng `filter()` của JavaScript
+* Khi nào và tại sao nên sử dụng các key của React
-## Rendering data from arrays {/*rendering-data-from-arrays*/}
+## Hiển thị dữ liệu từ mảng {/*rendering-data-from-arrays*/}
-Say that you have a list of content.
+Giả sử bạn có một danh sách nội dung.
```js
- Creola Katherine Johnson: mathematician
- Mario José Molina-Pasquel Henríquez: chemist
- Mohammad Abdus Salam: physicist
- Percy Lavon Julian: chemist
- Subrahmanyan Chandrasekhar: astrophysicist
+ Creola Katherine Johnson: nhà toán học
+ Mario José Molina-Pasquel Henríquez: nhà hóa học
+ Mohammad Abdus Salam: nhà vật lý
+ Percy Lavon Julian: nhà hóa học
+ Subrahmanyan Chandrasekhar: nhà vật lý thiên văn
```
-The only difference among those list items is their contents, their data. You will often need to show several instances of the same component using different data when building interfaces: from lists of comments to galleries of profile images. In these situations, you can store that data in JavaScript objects and arrays and use methods like [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) and [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) to render lists of components from them.
+Sự khác biệt duy nhất giữa các mục danh sách đó là nội dung của chúng, dữ liệu của chúng. Bạn thường cần hiển thị một số phiên bản của cùng một component bằng cách sử dụng dữ liệu khác nhau khi xây dựng giao diện: từ danh sách các bình luận đến thư viện ảnh hồ sơ. Trong những tình huống này, bạn có thể lưu trữ dữ liệu đó trong các đối tượng và mảng JavaScript và sử dụng các phương thức như [`map()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map) và [`filter()`](https://developer.mozilla.org/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) để hiển thị danh sách các component từ chúng.
-Here’s a short example of how to generate a list of items from an array:
+Dưới đây là một ví dụ ngắn gọn về cách tạo danh sách các mục từ một mảng:
-1. **Move** the data into an array:
+1. **Di chuyển** dữ liệu vào một mảng:
```js
const people = [
- 'Creola Katherine Johnson: mathematician',
- 'Mario José Molina-Pasquel Henríquez: chemist',
- 'Mohammad Abdus Salam: physicist',
- 'Percy Lavon Julian: chemist',
- 'Subrahmanyan Chandrasekhar: astrophysicist'
+ 'Creola Katherine Johnson: nhà toán học',
+ 'Mario José Molina-Pasquel Henríquez: nhà hóa học',
+ 'Mohammad Abdus Salam: nhà vật lý',
+ 'Percy Lavon Julian: nhà hóa học',
+ 'Subrahmanyan Chandrasekhar: nhà vật lý thiên văn'
];
```
-2. **Map** the `people` members into a new array of JSX nodes, `listItems`:
+2. **Ánh xạ** các thành viên `people` vào một mảng mới các nút JSX, `listItems`:
```js
const listItems = people.map(person => {person} );
```
-3. **Return** `listItems` from your component wrapped in a ``:
+3. **Trả về** `listItems` từ component của bạn được bao bọc trong một thẻ ``:
```js
return ;
```
-Here is the result:
+Đây là kết quả:
```js
const people = [
- 'Creola Katherine Johnson: mathematician',
- 'Mario José Molina-Pasquel Henríquez: chemist',
- 'Mohammad Abdus Salam: physicist',
- 'Percy Lavon Julian: chemist',
- 'Subrahmanyan Chandrasekhar: astrophysicist'
+ 'Creola Katherine Johnson: nhà toán học',
+ 'Mario José Molina-Pasquel Henríquez: nhà hóa học',
+ 'Mohammad Abdus Salam: nhà vật lý',
+ 'Percy Lavon Julian: nhà hóa học',
+ 'Subrahmanyan Chandrasekhar: nhà vật lý thiên văn'
];
export default function List() {
@@ -85,19 +84,19 @@ li { margin-bottom: 10px; }
-Notice the sandbox above displays a console error:
+Lưu ý sandbox ở trên hiển thị một lỗi trong bảng điều khiển:
-Warning: Each child in a list should have a unique "key" prop.
+Warning: Mỗi phần tử con trong một danh sách nên có một prop "key" duy nhất.
-You'll learn how to fix this error later on this page. Before we get to that, let's add some structure to your data.
+Bạn sẽ học cách sửa lỗi này sau trên trang này. Trước khi chúng ta đi đến đó, hãy thêm một số cấu trúc vào dữ liệu của bạn.
-## Filtering arrays of items {/*filtering-arrays-of-items*/}
+## Lọc mảng các mục {/*filtering-arrays-of-items*/}
-This data can be structured even more.
+Dữ liệu này có thể được cấu trúc hơn nữa.
```js
const people = [{
@@ -123,11 +122,11 @@ const people = [{
}];
```
-Let's say you want a way to only show people whose profession is `'chemist'`. You can use JavaScript's `filter()` method to return just those people. This method takes an array of items, passes them through a “test” (a function that returns `true` or `false`), and returns a new array of only those items that passed the test (returned `true`).
+Giả sử bạn muốn một cách để chỉ hiển thị những người có nghề nghiệp là `'chemist'`. Bạn có thể sử dụng phương thức `filter()` của JavaScript để chỉ trả về những người đó. Phương thức này lấy một mảng các mục, chuyển chúng qua một "bài kiểm tra" (một hàm trả về `true` hoặc `false`) và trả về một mảng mới chỉ gồm những mục đã vượt qua bài kiểm tra (trả về `true`).
-You only want the items where `profession` is `'chemist'`. The "test" function for this looks like `(person) => person.profession === 'chemist'`. Here's how to put it together:
+Bạn chỉ muốn các mục mà `profession` là `'chemist'`. Hàm "kiểm tra" cho việc này trông giống như `(person) => person.profession === 'chemist'`. Đây là cách để kết hợp nó:
-1. **Create** a new array of just “chemist” people, `chemists`, by calling `filter()` on the `people` filtering by `person.profession === 'chemist'`:
+1. **Tạo** một mảng mới chỉ gồm những người là "chemist", `chemists`, bằng cách gọi `filter()` trên `people` lọc theo `person.profession === 'chemist'`:
```js
const chemists = people.filter(person =>
@@ -135,7 +134,7 @@ const chemists = people.filter(person =>
);
```
-2. Now **map** over `chemists`:
+2. Bây giờ **ánh xạ** trên `chemists`:
```js {1,13}
const listItems = chemists.map(person =>
@@ -153,7 +152,7 @@ const listItems = chemists.map(person =>
);
```
-3. Lastly, **return** the `listItems` from your component:
+3. Cuối cùng, **trả về** `listItems` từ component của bạn:
```js
return ;
@@ -246,37 +245,37 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-Arrow functions implicitly return the expression right after `=>`, so you didn't need a `return` statement:
+Các hàm mũi tên trả về biểu thức ngay sau `=>` một cách ngầm định, vì vậy bạn không cần câu lệnh `return`:
```js
const listItems = chemists.map(person =>
- ... // Implicit return!
+ ... // Trả về ngầm định!
);
```
-However, **you must write `return` explicitly if your `=>` is followed by a `{` curly brace!**
+Tuy nhiên, **bạn phải viết `return` một cách rõ ràng nếu `=>` của bạn theo sau bởi dấu ngoặc nhọn `{`!**
```js
-const listItems = chemists.map(person => { // Curly brace
+const listItems = chemists.map(person => { // Dấu ngoặc nhọn
return ... ;
});
```
-Arrow functions containing `=> {` are said to have a ["block body".](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) They let you write more than a single line of code, but you *have to* write a `return` statement yourself. If you forget it, nothing gets returned!
+Các hàm mũi tên chứa `=> {` được cho là có ["thân khối".](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions#function_body) Chúng cho phép bạn viết nhiều hơn một dòng mã, nhưng bạn *phải* tự viết câu lệnh `return`. Nếu bạn quên nó, sẽ không có gì được trả về!
-## Keeping list items in order with `key` {/*keeping-list-items-in-order-with-key*/}
+## Giữ các mục danh sách theo thứ tự với `key` {/*keeping-list-items-in-order-with-key*/}
-Notice that all the sandboxes above show an error in the console:
+Lưu ý rằng tất cả các sandbox ở trên đều hiển thị một lỗi trong bảng điều khiển:
-Warning: Each child in a list should have a unique "key" prop.
+Warning: Mỗi phần tử con trong một danh sách nên có một prop "key" duy nhất.
-You need to give each array item a `key` -- a string or a number that uniquely identifies it among other items in that array:
+Bạn cần cung cấp cho mỗi mục trong mảng một `key` -- một chuỗi hoặc một số nhận dạng duy nhất nó giữa các mục khác trong mảng đó:
```js
...
@@ -284,13 +283,13 @@ You need to give each array item a `key` -- a string or a number that uniquely i
-JSX elements directly inside a `map()` call always need keys!
+Các phần tử JSX trực tiếp bên trong một lệnh gọi `map()` luôn cần các key!
-Keys tell React which array item each component corresponds to, so that it can match them up later. This becomes important if your array items can move (e.g. due to sorting), get inserted, or get deleted. A well-chosen `key` helps React infer what exactly has happened, and make the correct updates to the DOM tree.
+Các key cho React biết mục mảng nào mà mỗi component tương ứng, để nó có thể khớp chúng sau này. Điều này trở nên quan trọng nếu các mục trong mảng của bạn có thể di chuyển (ví dụ: do sắp xếp), được chèn hoặc bị xóa. Một `key` được chọn tốt sẽ giúp React suy ra chính xác những gì đã xảy ra và thực hiện các cập nhật chính xác cho cây DOM.
-Rather than generating keys on the fly, you should include them in your data:
+Thay vì tạo các key một cách nhanh chóng, bạn nên đưa chúng vào dữ liệu của mình:
@@ -318,31 +317,31 @@ export default function List() {
```js src/data.js active
export const people = [{
- id: 0, // Used in JSX as a key
+ id: 0, // Được sử dụng trong JSX làm key
name: 'Creola Katherine Johnson',
profession: 'mathematician',
accomplishment: 'spaceflight calculations',
imageId: 'MK3eW3A'
}, {
- id: 1, // Used in JSX as a key
+ id: 1, // Được sử dụng trong JSX làm key
name: 'Mario José Molina-Pasquel Henríquez',
profession: 'chemist',
accomplishment: 'discovery of Arctic ozone hole',
imageId: 'mynHUSa'
}, {
- id: 2, // Used in JSX as a key
+ id: 2, // Được sử dụng trong JSX làm key
name: 'Mohammad Abdus Salam',
profession: 'physicist',
accomplishment: 'electromagnetism theory',
imageId: 'bE7W1ji'
}, {
- id: 3, // Used in JSX as a key
+ id: 3, // Được sử dụng trong JSX làm key
name: 'Percy Lavon Julian',
profession: 'chemist',
accomplishment: 'pioneering cortisone drugs, steroids and birth control pills',
imageId: 'IOjWm71'
}, {
- id: 4, // Used in JSX as a key
+ id: 4, // Được sử dụng trong JSX làm key
name: 'Subrahmanyan Chandrasekhar',
profession: 'astrophysicist',
accomplishment: 'white dwarf star mass calculations',
@@ -376,11 +375,11 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-#### Displaying several DOM nodes for each list item {/*displaying-several-dom-nodes-for-each-list-item*/}
+#### Hiển thị một số nút DOM cho mỗi mục danh sách {/*displaying-several-dom-nodes-for-each-list-item*/}
-What do you do when each item needs to render not one, but several DOM nodes?
+Bạn làm gì khi mỗi mục cần hiển thị không phải một, mà là một số nút DOM?
-The short [`<>...>` Fragment](/reference/react/Fragment) syntax won't let you pass a key, so you need to either group them into a single ``, or use the slightly longer and [more explicit `
` syntax:](/reference/react/Fragment#rendering-a-list-of-fragments)
+Cú pháp [`<>...>` Fragment](/reference/react/Fragment) ngắn gọn sẽ không cho phép bạn truyền một key, vì vậy bạn cần nhóm chúng thành một `` duy nhất hoặc sử dụng cú pháp `
` dài hơn và [rõ ràng hơn:](/reference/react/Fragment#rendering-a-list-of-fragments)
```js
import { Fragment } from 'react';
@@ -395,46 +394,46 @@ const listItems = people.map(person =>
);
```
-Fragments disappear from the DOM, so this will produce a flat list of ``, ` `, `
`, ` `, and so on.
+Các Fragment biến mất khỏi DOM, vì vậy điều này sẽ tạo ra một danh sách phẳng gồm `
`, ` `, `
`, ` `, v.v.
-### Where to get your `key` {/*where-to-get-your-key*/}
+### Nơi để lấy `key` của bạn {/*where-to-get-your-key*/}
-Different sources of data provide different sources of keys:
+Các nguồn dữ liệu khác nhau cung cấp các nguồn key khác nhau:
-* **Data from a database:** If your data is coming from a database, you can use the database keys/IDs, which are unique by nature.
-* **Locally generated data:** If your data is generated and persisted locally (e.g. notes in a note-taking app), use an incrementing counter, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) or a package like [`uuid`](https://www.npmjs.com/package/uuid) when creating items.
+* **Dữ liệu từ cơ sở dữ liệu:** Nếu dữ liệu của bạn đến từ cơ sở dữ liệu, bạn có thể sử dụng các key/ID của cơ sở dữ liệu, vốn dĩ là duy nhất.
+* **Dữ liệu được tạo cục bộ:** Nếu dữ liệu của bạn được tạo và lưu trữ cục bộ (ví dụ: ghi chú trong một ứng dụng ghi chú), hãy sử dụng một bộ đếm tăng dần, [`crypto.randomUUID()`](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) hoặc một gói như [`uuid`](https://www.npmjs.com/package/uuid) khi tạo các mục.
-### Rules of keys {/*rules-of-keys*/}
+### Các quy tắc của key {/*rules-of-keys*/}
-* **Keys must be unique among siblings.** However, it’s okay to use the same keys for JSX nodes in _different_ arrays.
-* **Keys must not change** or that defeats their purpose! Don't generate them while rendering.
+* **Các key phải là duy nhất giữa các anh chị em.** Tuy nhiên, bạn có thể sử dụng cùng một key cho các nút JSX trong các mảng _khác nhau_.
+* **Các key không được thay đổi** nếu không điều đó sẽ phá vỡ mục đích của chúng! Không tạo chúng trong khi hiển thị.
-### Why does React need keys? {/*why-does-react-need-keys*/}
+### Tại sao React cần các key? {/*why-does-react-need-keys*/}
-Imagine that files on your desktop didn't have names. Instead, you'd refer to them by their order -- the first file, the second file, and so on. You could get used to it, but once you delete a file, it would get confusing. The second file would become the first file, the third file would be the second file, and so on.
+Hãy tưởng tượng rằng các tệp trên màn hình của bạn không có tên. Thay vào đó, bạn sẽ tham khảo chúng theo thứ tự của chúng -- tệp đầu tiên, tệp thứ hai, v.v. Bạn có thể làm quen với nó, nhưng một khi bạn xóa một tệp, nó sẽ trở nên khó hiểu. Tệp thứ hai sẽ trở thành tệp đầu tiên, tệp thứ ba sẽ là tệp thứ hai, v.v.
-File names in a folder and JSX keys in an array serve a similar purpose. They let us uniquely identify an item between its siblings. A well-chosen key provides more information than the position within the array. Even if the _position_ changes due to reordering, the `key` lets React identify the item throughout its lifetime.
+Tên tệp trong một thư mục và các key JSX trong một mảng phục vụ một mục đích tương tự. Chúng cho phép chúng ta xác định duy nhất một mục giữa các anh chị em của nó. Một key được chọn tốt cung cấp nhiều thông tin hơn vị trí trong mảng. Ngay cả khi _vị trí_ thay đổi do sắp xếp lại, `key` cho phép React xác định mục trong suốt vòng đời của nó.
-You might be tempted to use an item's index in the array as its key. In fact, that's what React will use if you don't specify a `key` at all. But the order in which you render items will change over time if an item is inserted, deleted, or if the array gets reordered. Index as a key often leads to subtle and confusing bugs.
+Bạn có thể bị cám dỗ sử dụng chỉ mục của một mục trong mảng làm key của nó. Trên thực tế, đó là những gì React sẽ sử dụng nếu bạn không chỉ định `key` nào cả. Nhưng thứ tự mà bạn hiển thị các mục sẽ thay đổi theo thời gian nếu một mục được chèn, xóa hoặc nếu mảng được sắp xếp lại. Chỉ mục làm key thường dẫn đến các lỗi tinh vi và khó hiểu.
-Similarly, do not generate keys on the fly, e.g. with `key={Math.random()}`. This will cause keys to never match up between renders, leading to all your components and DOM being recreated every time. Not only is this slow, but it will also lose any user input inside the list items. Instead, use a stable ID based on the data.
+Tương tự, không tạo các key một cách nhanh chóng, ví dụ: với `key={Math.random()}`. Điều này sẽ khiến các key không bao giờ khớp giữa các lần hiển thị, dẫn đến tất cả các component và DOM của bạn được tạo lại mỗi lần. Điều này không chỉ chậm mà còn làm mất mọi dữ liệu đầu vào của người dùng bên trong các mục danh sách. Thay vào đó, hãy sử dụng một ID ổn định dựa trên dữ liệu.
-Note that your components won't receive `key` as a prop. It's only used as a hint by React itself. If your component needs an ID, you have to pass it as a separate prop: ` `.
+Lưu ý rằng các component của bạn sẽ không nhận được `key` làm một prop. Nó chỉ được sử dụng như một gợi ý bởi chính React. Nếu component của bạn cần một ID, bạn phải chuyển nó như một prop riêng biệt: ` `.
-On this page you learned:
+Trên trang này, bạn đã học:
-* How to move data out of components and into data structures like arrays and objects.
-* How to generate sets of similar components with JavaScript's `map()`.
-* How to create arrays of filtered items with JavaScript's `filter()`.
-* Why and how to set `key` on each component in a collection so React can keep track of each of them even if their position or data changes.
+* Cách di chuyển dữ liệu ra khỏi các component và vào các cấu trúc dữ liệu như mảng và đối tượng.
+* Cách tạo các tập hợp các component tương tự với `map()` của JavaScript.
+* Cách tạo các mảng các mục được lọc với `filter()` của JavaScript.
+* Tại sao và cách đặt `key` trên mỗi component trong một tập hợp để React có thể theo dõi từng component ngay cả khi vị trí hoặc dữ liệu của chúng thay đổi.
@@ -442,11 +441,11 @@ On this page you learned:
-#### Splitting a list in two {/*splitting-a-list-in-two*/}
+#### Chia một danh sách thành hai {/*splitting-a-list-in-two*/}
-This example shows a list of all people.
+Ví dụ này hiển thị một danh sách tất cả mọi người.
-Change it to show two separate lists one after another: **Chemists** and **Everyone Else.** Like previously, you can determine whether a person is a chemist by checking if `person.profession === 'chemist'`.
+Thay đổi nó để hiển thị hai danh sách riêng biệt liên tiếp: **Các nhà hóa học** và **Mọi người khác.** Giống như trước đây, bạn có thể xác định xem một người có phải là nhà hóa học hay không bằng cách kiểm tra xem `person.profession === 'chemist'`.
@@ -537,7 +536,7 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-You could use `filter()` twice, creating two separate arrays, and then `map` over both of them:
+Bạn có thể sử dụng `filter()` hai lần, tạo hai mảng riêng biệt, sau đó `map` trên cả hai:
@@ -650,9 +649,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-In this solution, the `map` calls are placed directly inline into the parent `` elements, but you could introduce variables for them if you find that more readable.
+Trong giải pháp này, các lệnh gọi `map` được đặt trực tiếp vào các phần tử `` cha, nhưng bạn có thể giới thiệu các biến cho chúng nếu bạn thấy điều đó dễ đọc hơn.
-There is still a bit duplication between the rendered lists. You can go further and extract the repetitive parts into a `` component:
+Vẫn còn một chút trùng lặp giữa các danh sách được hiển thị. Bạn có thể tiến xa hơn và trích xuất các phần lặp đi lặp lại vào một component ``:
@@ -763,10 +762,9 @@ img { width: 100px; height: 100px; border-radius: 50%; }
```
+Một người đọc rất kỹ có thể nhận thấy rằng với hai lệnh gọi `filter`, chúng ta kiểm tra nghề nghiệp của mỗi người hai lần. Kiểm tra một thuộc tính rất nhanh, vì vậy trong ví dụ này thì ổn. Nếu logic của bạn tốn kém hơn thế, bạn có thể thay thế các lệnh gọi `filter` bằng một vòng lặp tự xây dựng các mảng và kiểm tra mỗi người một lần.
-A very attentive reader might notice that with two `filter` calls, we check each person's profession twice. Checking a property is very fast, so in this example it's fine. If your logic was more expensive than that, you could replace the `filter` calls with a loop that manually constructs the arrays and checks each person once.
-
-In fact, if `people` never change, you could move this code out of your component. From React's perspective, all that matters is that you give it an array of JSX nodes in the end. It doesn't care how you produce that array:
+Trên thực tế, nếu `people` không bao giờ thay đổi, bạn có thể di chuyển đoạn mã này ra khỏi component của mình. Theo quan điểm của React, tất cả những gì quan trọng là bạn cung cấp cho nó một mảng các nút JSX ở cuối. Nó không quan tâm bạn tạo ra mảng đó như thế nào:
@@ -884,13 +882,13 @@ img { width: 100px; height: 100px; border-radius: 50%; }
-#### Nested lists in one component {/*nested-lists-in-one-component*/}
+#### Danh sách lồng nhau trong một component {/*nested-lists-in-one-component*/}
-Make a list of recipes from this array! For each recipe in the array, display its name as an `` and list its ingredients in a ``.
+Tạo một danh sách các công thức từ mảng này! Đối với mỗi công thức trong mảng, hiển thị tên của nó dưới dạng `` và liệt kê các thành phần của nó trong một ``.
-This will require nesting two different `map` calls.
+Điều này sẽ yêu cầu lồng hai lệnh gọi `map` khác nhau.
@@ -928,7 +926,7 @@ export const recipes = [{
-Here is one way you could go about it:
+Đây là một cách bạn có thể thực hiện:
@@ -974,13 +972,13 @@ export const recipes = [{
-Each of the `recipes` already includes an `id` field, so that's what the outer loop uses for its `key`. There is no ID you could use to loop over ingredients. However, it's reasonable to assume that the same ingredient won't be listed twice within the same recipe, so its name can serve as a `key`. Alternatively, you could change the data structure to add IDs, or use index as a `key` (with the caveat that you can't safely reorder ingredients).
+Mỗi `recipes` đã bao gồm một trường `id`, vì vậy đó là những gì vòng lặp bên ngoài sử dụng cho `key` của nó. Không có ID nào bạn có thể sử dụng để lặp lại các thành phần. Tuy nhiên, có lý do để cho rằng cùng một thành phần sẽ không được liệt kê hai lần trong cùng một công thức, vì vậy tên của nó có thể đóng vai trò là `key`. Ngoài ra, bạn có thể thay đổi cấu trúc dữ liệu để thêm ID hoặc sử dụng chỉ mục làm `key` (với cảnh báo rằng bạn không thể sắp xếp lại các thành phần một cách an toàn).
-#### Extracting a list item component {/*extracting-a-list-item-component*/}
+#### Trích xuất một component mục danh sách {/*extracting-a-list-item-component*/}
-This `RecipeList` component contains two nested `map` calls. To simplify it, extract a `Recipe` component from it which will accept `id`, `name`, and `ingredients` props. Where do you place the outer `key` and why?
+Component `RecipeList` này chứa hai lệnh gọi `map` lồng nhau. Để đơn giản hóa nó, hãy trích xuất một component `Recipe` từ nó, component này sẽ chấp nhận các props `id`, `name` và `ingredients`. Bạn đặt `key` bên ngoài ở đâu và tại sao?
@@ -1028,7 +1026,7 @@ export const recipes = [{
-You can copy-paste the JSX from the outer `map` into a new `Recipe` component and return that JSX. Then you can change `recipe.name` to `name`, `recipe.id` to `id`, and so on, and pass them as props to the `Recipe`:
+Bạn có thể sao chép-dán JSX từ `map` bên ngoài vào một component `Recipe` mới và trả về JSX đó. Sau đó, bạn có thể thay đổi `recipe.name` thành `name`, `recipe.id` thành `id`, v.v. và chuyển chúng làm props cho `Recipe`:
@@ -1080,15 +1078,15 @@ export const recipes = [{
-Here, ` ` is a syntax shortcut saying "pass all properties of the `recipe` object as props to the `Recipe` component". You could also write each prop explicitly: ` `.
+Ở đây, ` ` là một cú pháp tắt cho biết "truyền tất cả các thuộc tính của đối tượng `recipe` làm props cho component `Recipe`". Bạn cũng có thể viết rõ ràng từng prop: ` `.
-**Note that the `key` is specified on the `` itself rather than on the root `` returned from `Recipe`.** This is because this `key` is needed directly within the context of the surrounding array. Previously, you had an array of `
`s so each of them needed a `key`, but now you have an array of `
`s. In other words, when you extract a component, don't forget to leave the `key` outside the JSX you copy and paste.
+**Lưu ý rằng `key` được chỉ định trên chính `` chứ không phải trên `` gốc được trả về từ `Recipe`.** Điều này là do `key` này cần thiết trực tiếp trong ngữ cảnh của mảng xung quanh. Trước đây, bạn có một mảng các `
` nên mỗi `
` cần một `key`, nhưng bây giờ bạn có một mảng các `
`. Nói cách khác, khi bạn trích xuất một component, đừng quên để `key` bên ngoài JSX bạn sao chép và dán.
-#### List with a separator {/*list-with-a-separator*/}
+#### Danh sách với dấu phân cách {/*list-with-a-separator*/}
-This example renders a famous haiku by Tachibana Hokushi, with each line wrapped in a `` tag. Your job is to insert an `
` separator between each paragraph. Your resulting structure should look like this:
+Ví dụ này hiển thị một bài haiku nổi tiếng của Tachibana Hokushi, với mỗi dòng được bao bọc trong một thẻ ``. Nhiệm vụ của bạn là chèn một dấu phân cách `
` giữa mỗi đoạn văn. Cấu trúc kết quả của bạn sẽ như thế này:
```js
@@ -1100,7 +1098,7 @@ This example renders a famous haiku by Tachibana Hokushi, with each line wrapped
```
-A haiku only contains three lines, but your solution should work with any number of lines. Note that ` ` elements only appear *between* the `` elements, not in the beginning or the end!
+Một bài haiku chỉ chứa ba dòng, nhưng giải pháp của bạn phải hoạt động với bất kỳ số lượng dòng nào. Lưu ý rằng các phần tử `
` chỉ xuất hiện *giữa* các phần tử ``, không phải ở đầu hoặc cuối!
@@ -1143,17 +1141,17 @@ hr {
-(This is a rare case where index as a key is acceptable because a poem's lines will never reorder.)
+(Đây là một trường hợp hiếm hoi mà chỉ mục làm key là chấp nhận được vì các dòng của một bài thơ sẽ không bao giờ được sắp xếp lại.)
-You'll either need to convert `map` to a manual loop, or use a Fragment.
+Bạn sẽ cần chuyển đổi `map` thành một vòng lặp thủ công hoặc sử dụng Fragment.
-You can write a manual loop, inserting ` ` and `...
` into the output array as you go:
+Bạn có thể viết một vòng lặp thủ công, chèn ` ` và `...
` vào mảng đầu ra khi bạn thực hiện:
@@ -1208,9 +1206,9 @@ hr {
-Using the original line index as a `key` doesn't work anymore because each separator and paragraph are now in the same array. However, you can give each of them a distinct key using a suffix, e.g. `key={i + '-text'}`.
+Sử dụng chỉ mục dòng ban đầu làm `key` không còn hoạt động nữa vì mỗi dấu phân cách và đoạn văn hiện nằm trong cùng một mảng. Tuy nhiên, bạn có thể cung cấp cho mỗi phần tử một key riêng biệt bằng cách sử dụng một hậu tố, ví dụ: `key={i + '-text'}`.
-Alternatively, you could render a collection of Fragments which contain ` ` and `...
`. However, the `<>...>` shorthand syntax doesn't support passing keys, so you'd have to write `` explicitly:
+Ngoài ra, bạn có thể hiển thị một tập hợp các Fragment chứa ` ` và `...
`. Tuy nhiên, cú pháp viết tắt `<>...>` không hỗ trợ truyền key, vì vậy bạn sẽ phải viết `` một cách rõ ràng:
@@ -1256,7 +1254,7 @@ hr {
-Remember, Fragments (often written as `<> >`) let you group JSX nodes without adding extra ``s!
+Hãy nhớ rằng, Fragments (thường được viết là `<> >`) cho phép bạn nhóm các nút JSX mà không cần thêm `
` bổ sung!
diff --git a/src/content/learn/responding-to-events.md b/src/content/learn/responding-to-events.md
index 17bd087ed..d637085bc 100644
--- a/src/content/learn/responding-to-events.md
+++ b/src/content/learn/responding-to-events.md
@@ -1,24 +1,24 @@
---
-title: Responding to Events
+title: Phản hồi sự kiện
---
-React lets you add *event handlers* to your JSX. Event handlers are your own functions that will be triggered in response to interactions like clicking, hovering, focusing form inputs, and so on.
+React cho phép bạn thêm *trình xử lý sự kiện* vào JSX của mình. Trình xử lý sự kiện là các hàm của riêng bạn sẽ được kích hoạt để đáp ứng các tương tác như nhấp chuột, di chuột, tập trung vào các đầu vào biểu mẫu, v.v.
-* Different ways to write an event handler
-* How to pass event handling logic from a parent component
-* How events propagate and how to stop them
+* Các cách khác nhau để viết một trình xử lý sự kiện
+* Cách truyền logic xử lý sự kiện từ một component cha
+* Cách các sự kiện lan truyền và cách ngăn chặn chúng
-## Adding event handlers {/*adding-event-handlers*/}
+## Thêm trình xử lý sự kiện {/*adding-event-handlers*/}
-To add an event handler, you will first define a function and then [pass it as a prop](/learn/passing-props-to-a-component) to the appropriate JSX tag. For example, here is a button that doesn't do anything yet:
+Để thêm một trình xử lý sự kiện, trước tiên bạn sẽ định nghĩa một hàm và sau đó [truyền nó như một prop](/learn/passing-props-to-a-component) cho thẻ JSX thích hợp. Ví dụ: đây là một nút chưa làm gì cả:
@@ -26,7 +26,7 @@ To add an event handler, you will first define a function and then [pass it as a
export default function Button() {
return (
- I don't do anything
+ Tôi không làm gì cả
);
}
@@ -34,23 +34,23 @@ export default function Button() {
-You can make it show a message when a user clicks by following these three steps:
+Bạn có thể làm cho nó hiển thị một thông báo khi người dùng nhấp vào bằng cách làm theo ba bước sau:
-1. Declare a function called `handleClick` *inside* your `Button` component.
-2. Implement the logic inside that function (use `alert` to show the message).
-3. Add `onClick={handleClick}` to the `
` JSX.
+1. Khai báo một hàm có tên là `handleClick` *bên trong* component `Button` của bạn.
+2. Triển khai logic bên trong hàm đó (sử dụng `alert` để hiển thị thông báo).
+3. Thêm `onClick={handleClick}` vào JSX ``.
```js
export default function Button() {
function handleClick() {
- alert('You clicked me!');
+ alert('Bạn đã nhấp vào tôi!');
}
return (
- Click me
+ Nhấp vào tôi
);
}
@@ -62,77 +62,77 @@ button { margin-right: 10px; }
-You defined the `handleClick` function and then [passed it as a prop](/learn/passing-props-to-a-component) to ``. `handleClick` is an **event handler.** Event handler functions:
+Bạn đã định nghĩa hàm `handleClick` và sau đó [truyền nó như một prop](/learn/passing-props-to-a-component) cho ``. `handleClick` là một **trình xử lý sự kiện.** Các hàm xử lý sự kiện:
-* Are usually defined *inside* your components.
-* Have names that start with `handle`, followed by the name of the event.
+* Thường được định nghĩa *bên trong* các component của bạn.
+* Có tên bắt đầu bằng `handle`, theo sau là tên của sự kiện.
-By convention, it is common to name event handlers as `handle` followed by the event name. You'll often see `onClick={handleClick}`, `onMouseEnter={handleMouseEnter}`, and so on.
+Theo quy ước, người ta thường đặt tên cho các trình xử lý sự kiện là `handle` theo sau là tên sự kiện. Bạn sẽ thường thấy `onClick={handleClick}`, `onMouseEnter={handleMouseEnter}`, v.v.
-Alternatively, you can define an event handler inline in the JSX:
+Ngoài ra, bạn có thể định nghĩa một trình xử lý sự kiện nội tuyến trong JSX:
```jsx
```
-Or, more concisely, using an arrow function:
+Hoặc, ngắn gọn hơn, sử dụng một hàm mũi tên:
```jsx
{
- alert('You clicked me!');
+ alert('Bạn đã nhấp vào tôi!');
}}>
```
-All of these styles are equivalent. Inline event handlers are convenient for short functions.
+Tất cả các kiểu này là tương đương. Trình xử lý sự kiện nội tuyến rất tiện lợi cho các hàm ngắn.
-Functions passed to event handlers must be passed, not called. For example:
+Các hàm được truyền cho trình xử lý sự kiện phải được truyền, không được gọi. Ví dụ:
-| passing a function (correct) | calling a function (incorrect) |
+| truyền một hàm (chính xác) | gọi một hàm (không chính xác) |
| -------------------------------- | ---------------------------------- |
| `` | `` |
-The difference is subtle. In the first example, the `handleClick` function is passed as an `onClick` event handler. This tells React to remember it and only call your function when the user clicks the button.
+Sự khác biệt là rất nhỏ. Trong ví dụ đầu tiên, hàm `handleClick` được truyền như một trình xử lý sự kiện `onClick`. Điều này cho React biết để ghi nhớ nó và chỉ gọi hàm của bạn khi người dùng nhấp vào nút.
-In the second example, the `()` at the end of `handleClick()` fires the function *immediately* during [rendering](/learn/render-and-commit), without any clicks. This is because JavaScript inside the [JSX `{` and `}`](/learn/javascript-in-jsx-with-curly-braces) executes right away.
+Trong ví dụ thứ hai, `()` ở cuối `handleClick()` kích hoạt hàm *ngay lập tức* trong quá trình [rendering](/learn/render-and-commit), mà không cần bất kỳ nhấp chuột nào. Điều này là do JavaScript bên trong [JSX `{` và `}`](/learn/javascript-in-jsx-with-curly-braces) thực thi ngay lập tức.
-When you write code inline, the same pitfall presents itself in a different way:
+Khi bạn viết mã nội tuyến, cùng một cạm bẫy xuất hiện theo một cách khác:
-| passing a function (correct) | calling a function (incorrect) |
+| truyền một hàm (chính xác) | gọi một hàm (không chính xác) |
| --------------------------------------- | --------------------------------- |
| ` alert('...')}>` | `` |
-Passing inline code like this won't fire on click—it fires every time the component renders:
+Truyền mã nội tuyến như thế này sẽ không kích hoạt khi nhấp chuột—nó kích hoạt mỗi khi component render:
```jsx
-// This alert fires when the component renders, not when clicked!
-
+// Cảnh báo này kích hoạt khi component render, không phải khi nhấp vào!
+
```
-If you want to define your event handler inline, wrap it in an anonymous function like so:
+Nếu bạn muốn định nghĩa trình xử lý sự kiện của mình nội tuyến, hãy bọc nó trong một hàm ẩn danh như sau:
```jsx
- alert('You clicked me!')}>
+ alert('Bạn đã nhấp vào tôi!')}>
```
-Rather than executing the code inside with every render, this creates a function to be called later.
+Thay vì thực thi mã bên trong với mỗi lần render, điều này tạo ra một hàm sẽ được gọi sau.
-In both cases, what you want to pass is a function:
+Trong cả hai trường hợp, những gì bạn muốn truyền là một hàm:
-* `` passes the `handleClick` function.
-* ` alert('...')}>` passes the `() => alert('...')` function.
+* `` truyền hàm `handleClick`.
+* ` alert('...')}>` truyền hàm `() => alert('...')`.
-[Read more about arrow functions.](https://javascript.info/arrow-functions-basics)
+[Đọc thêm về hàm mũi tên.](https://javascript.javascript.info/arrow-functions-basics)
-### Reading props in event handlers {/*reading-props-in-event-handlers*/}
+### Đọc props trong trình xử lý sự kiện {/*reading-props-in-event-handlers*/}
-Because event handlers are declared inside of a component, they have access to the component's props. Here is a button that, when clicked, shows an alert with its `message` prop:
+Vì trình xử lý sự kiện được khai báo bên trong một component, chúng có quyền truy cập vào các props của component đó. Dưới đây là một nút, khi được nhấp vào, sẽ hiển thị một cảnh báo với prop `message` của nó:
@@ -148,11 +148,11 @@ function AlertButton({ message, children }) {
export default function Toolbar() {
return (
-
- Play Movie
+
+ Phát phim
-
- Upload Image
+
+ Tải lên ảnh
);
@@ -165,13 +165,13 @@ button { margin-right: 10px; }
-This lets these two buttons show different messages. Try changing the messages passed to them.
+Điều này cho phép hai nút này hiển thị các thông báo khác nhau. Hãy thử thay đổi các thông báo được truyền cho chúng.
-### Passing event handlers as props {/*passing-event-handlers-as-props*/}
+### Truyền trình xử lý sự kiện như props {/*passing-event-handlers-as-props*/}
-Often you'll want the parent component to specify a child's event handler. Consider buttons: depending on where you're using a `Button` component, you might want to execute a different function—perhaps one plays a movie and another uploads an image.
+Thông thường, bạn sẽ muốn component cha chỉ định trình xử lý sự kiện của một component con. Hãy xem xét các nút: tùy thuộc vào nơi bạn đang sử dụng component `Button`, bạn có thể muốn thực thi một hàm khác—có lẽ một hàm phát một bộ phim và một hàm khác tải lên một hình ảnh.
-To do this, pass a prop the component receives from its parent as the event handler like so:
+Để thực hiện việc này, hãy truyền một prop mà component nhận được từ cha của nó làm trình xử lý sự kiện như sau:
@@ -186,20 +186,20 @@ function Button({ onClick, children }) {
function PlayButton({ movieName }) {
function handlePlayClick() {
- alert(`Playing ${movieName}!`);
+ alert(`Đang phát ${movieName}!`);
}
return (
- Play "{movieName}"
+ Phát "{movieName}"
);
}
function UploadButton() {
return (
- alert('Uploading!')}>
- Upload Image
+ alert('Đang tải lên!')}>
+ Tải lên ảnh
);
}
@@ -207,7 +207,7 @@ function UploadButton() {
export default function Toolbar() {
return (
);
@@ -220,22 +220,22 @@ button { margin-right: 10px; }
-Here, the `Toolbar` component renders a `PlayButton` and an `UploadButton`:
+Ở đây, component `Toolbar` render một `PlayButton` và một `UploadButton`:
-- `PlayButton` passes `handlePlayClick` as the `onClick` prop to the `Button` inside.
-- `UploadButton` passes `() => alert('Uploading!')` as the `onClick` prop to the `Button` inside.
+- `PlayButton` truyền `handlePlayClick` làm prop `onClick` cho `Button` bên trong.
+- `UploadButton` truyền `() => alert('Đang tải lên!')` làm prop `onClick` cho `Button` bên trong.
-Finally, your `Button` component accepts a prop called `onClick`. It passes that prop directly to the built-in browser `` with `onClick={onClick}`. This tells React to call the passed function on click.
+Cuối cùng, component `Button` của bạn chấp nhận một prop có tên là `onClick`. Nó truyền prop đó trực tiếp đến trình duyệt tích hợp sẵn `` với `onClick={onClick}`. Điều này cho React biết để gọi hàm được truyền khi nhấp vào.
-If you use a [design system](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969), it's common for components like buttons to contain styling but not specify behavior. Instead, components like `PlayButton` and `UploadButton` will pass event handlers down.
+Nếu bạn sử dụng [hệ thống thiết kế](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969), thì các component như nút thường chứa kiểu dáng nhưng không chỉ định hành vi. Thay vào đó, các component như `PlayButton` và `UploadButton` sẽ truyền các trình xử lý sự kiện xuống.
-### Naming event handler props {/*naming-event-handler-props*/}
+### Đặt tên cho các props của trình xử lý sự kiện {/*naming-event-handler-props*/}
-Built-in components like `` and `` only support [browser event names](/reference/react-dom/components/common#common-props) like `onClick`. However, when you're building your own components, you can name their event handler props any way that you like.
+Các component tích hợp sẵn như `
` và `` chỉ hỗ trợ [tên sự kiện của trình duyệt](/reference/react-dom/components/common#common-props) như `onClick`. Tuy nhiên, khi bạn đang xây dựng các component của riêng mình, bạn có thể đặt tên cho các props của trình xử lý sự kiện của chúng theo bất kỳ cách nào bạn muốn.
-By convention, event handler props should start with `on`, followed by a capital letter.
+Theo quy ước, các props của trình xử lý sự kiện nên bắt đầu bằng `on`, theo sau là một chữ cái viết hoa.
-For example, the `Button` component's `onClick` prop could have been called `onSmash`:
+Ví dụ: prop `onClick` của component `Button` có thể được gọi là `onSmash`:
@@ -251,11 +251,11 @@ function Button({ onSmash, children }) {
export default function App() {
return (
- alert('Playing!')}>
- Play Movie
+ alert('Đang phát!')}>
+ Phát phim
- alert('Uploading!')}>
- Upload Image
+ alert('Đang tải lên!')}>
+ Tải lên ảnh
);
@@ -268,9 +268,9 @@ button { margin-right: 10px; }
-In this example, `
` shows that the browser `` (lowercase) still needs a prop called `onClick`, but the prop name received by your custom `Button` component is up to you!
+Trong ví dụ này, `` cho thấy rằng trình duyệt `` (chữ thường) vẫn cần một prop có tên là `onClick`, nhưng tên prop mà component `Button` tùy chỉnh của bạn nhận được là tùy thuộc vào bạn!
-When your component supports multiple interactions, you might name event handler props for app-specific concepts. For example, this `Toolbar` component receives `onPlayMovie` and `onUploadImage` event handlers:
+Khi component của bạn hỗ trợ nhiều tương tác, bạn có thể đặt tên cho các props của trình xử lý sự kiện cho các khái niệm dành riêng cho ứng dụng. Ví dụ: component `Toolbar` này nhận các trình xử lý sự kiện `onPlayMovie` và `onUploadImage`:
@@ -278,8 +278,8 @@ When your component supports multiple interactions, you might name event handler
export default function App() {
return (
alert('Playing!')}
- onUploadImage={() => alert('Uploading!')}
+ onPlayMovie={() => alert('Đang phát!')}
+ onUploadImage={() => alert('Đang tải lên!')}
/>
);
}
@@ -288,10 +288,10 @@ function Toolbar({ onPlayMovie, onUploadImage }) {
return (
- Play Movie
+ Phát phim
- Upload Image
+ Tải lên ảnh
);
@@ -312,19 +312,19 @@ button { margin-right: 10px; }
-Notice how the `App` component does not need to know *what* `Toolbar` will do with `onPlayMovie` or `onUploadImage`. That's an implementation detail of the `Toolbar`. Here, `Toolbar` passes them down as `onClick` handlers to its `Button`s, but it could later also trigger them on a keyboard shortcut. Naming props after app-specific interactions like `onPlayMovie` gives you the flexibility to change how they're used later.
-
+Lưu ý cách component `App` không cần biết *những gì* `Toolbar` sẽ làm với `onPlayMovie` hoặc `onUploadImage`. Đó là một chi tiết triển khai của `Toolbar`. Ở đây, `Toolbar` truyền chúng xuống dưới dạng trình xử lý `onClick` cho `Button` của nó, nhưng sau này nó cũng có thể kích hoạt chúng trên một phím tắt. Đặt tên cho các props theo các tương tác dành riêng cho ứng dụng như `onPlayMovie` mang lại cho bạn sự linh hoạt để thay đổi cách chúng được sử dụng sau này.
+
-Make sure that you use the appropriate HTML tags for your event handlers. For example, to handle clicks, use [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) instead of ``. Using a real browser `
` enables built-in browser behaviors like keyboard navigation. If you don't like the default browser styling of a button and want to make it look more like a link or a different UI element, you can achieve it with CSS. [Learn more about writing accessible markup.](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML)
-
+Hãy chắc chắn rằng bạn sử dụng các thẻ HTML thích hợp cho các trình xử lý sự kiện của bạn. Ví dụ: để xử lý các nhấp chuột, hãy sử dụng [``](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/button) thay vì ``. Sử dụng một trình duyệt `
` thực cho phép các hành vi tích hợp sẵn của trình duyệt như điều hướng bằng bàn phím. Nếu bạn không thích kiểu trình duyệt mặc định của một nút và muốn làm cho nó trông giống một liên kết hoặc một phần tử UI khác, bạn có thể đạt được nó bằng CSS. [Tìm hiểu thêm về viết mã đánh dấu có thể truy cập.](https://developer.mozilla.org/en-US/docs/Learn/Accessibility/HTML)
+
-## Event propagation {/*event-propagation*/}
+## Sự kiện lan truyền {/*event-propagation*/}
-Event handlers will also catch events from any children your component might have. We say that an event "bubbles" or "propagates" up the tree: it starts with where the event happened, and then goes up the tree.
+Trình xử lý sự kiện cũng sẽ bắt các sự kiện từ bất kỳ component con nào mà component của bạn có thể có. Chúng ta nói rằng một sự kiện "nổi bọt" hoặc "lan truyền" lên cây: nó bắt đầu với nơi sự kiện xảy ra, và sau đó đi lên cây.
-This `` contains two buttons. Both the `
` *and* each button have their own `onClick` handlers. Which handlers do you think will fire when you click a button?
+`
` này chứa hai nút. Cả `
` *và* mỗi nút đều có trình xử lý `onClick` riêng. Bạn nghĩ trình xử lý nào sẽ kích hoạt khi bạn nhấp vào một nút?
@@ -332,13 +332,13 @@ This `` contains two buttons. Both the `
` *and* each button have their
export default function Toolbar() {
return (
{
- alert('You clicked on the toolbar!');
+ alert('Bạn đã nhấp vào thanh công cụ!');
}}>
- alert('Playing!')}>
- Play Movie
+ alert('Đang phát!')}>
+ Phát phim
- alert('Uploading!')}>
- Upload Image
+ alert('Đang tải lên!')}>
+ Tải lên ảnh
);
@@ -355,19 +355,19 @@ button { margin: 5px; }
-If you click on either button, its `onClick` will run first, followed by the parent `
`'s `onClick`. So two messages will appear. If you click the toolbar itself, only the parent `
`'s `onClick` will run.
+Nếu bạn nhấp vào một trong hai nút, `onClick` của nó sẽ chạy trước, sau đó là `onClick` của `
` cha. Vì vậy, hai thông báo sẽ xuất hiện. Nếu bạn nhấp vào chính thanh công cụ, chỉ `onClick` của `
` cha sẽ chạy.
-All events propagate in React except `onScroll`, which only works on the JSX tag you attach it to.
+Tất cả các sự kiện lan truyền trong React ngoại trừ `onScroll`, chỉ hoạt động trên thẻ JSX mà bạn gắn nó vào.
-### Stopping propagation {/*stopping-propagation*/}
+### Dừng lan truyền {/*stopping-propagation*/}
-Event handlers receive an **event object** as their only argument. By convention, it's usually called `e`, which stands for "event". You can use this object to read information about the event.
+Trình xử lý sự kiện nhận một **đối tượng sự kiện** làm đối số duy nhất của chúng. Theo quy ước, nó thường được gọi là `e`, viết tắt của "event". Bạn có thể sử dụng đối tượng này để đọc thông tin về sự kiện.
-That event object also lets you stop the propagation. If you want to prevent an event from reaching parent components, you need to call `e.stopPropagation()` like this `Button` component does:
+Đối tượng sự kiện đó cũng cho phép bạn dừng lan truyền. Nếu bạn muốn ngăn một sự kiện tiếp cận các component cha, bạn cần gọi `e.stopPropagation()` như component `Button` này:
@@ -386,13 +386,13 @@ function Button({ onClick, children }) {
export default function Toolbar() {
return (
{
- alert('You clicked on the toolbar!');
+ alert('Bạn đã nhấp vào thanh công cụ!');
}}>
- alert('Playing!')}>
- Play Movie
+ alert('Đang phát!')}>
+ Phát phim
- alert('Uploading!')}>
- Upload Image
+ alert('Đang tải lên!')}>
+ Tải lên ảnh
);
@@ -409,43 +409,43 @@ button { margin: 5px; }
-When you click on a button:
+Khi bạn nhấp vào một nút:
-1. React calls the `onClick` handler passed to `
`.
-2. That handler, defined in `Button`, does the following:
- * Calls `e.stopPropagation()`, preventing the event from bubbling further.
- * Calls the `onClick` function, which is a prop passed from the `Toolbar` component.
-3. That function, defined in the `Toolbar` component, displays the button's own alert.
-4. Since the propagation was stopped, the parent ``'s `onClick` handler does *not* run.
+1. React gọi trình xử lý `onClick` được truyền cho `
`.
+2. Trình xử lý đó, được định nghĩa trong `Button`, thực hiện như sau:
+ * Gọi `e.stopPropagation()`, ngăn sự kiện nổi bọt thêm.
+ * Gọi hàm `onClick`, là một prop được truyền từ component `Toolbar`.
+3. Hàm đó, được định nghĩa trong component `Toolbar`, hiển thị cảnh báo riêng của nút.
+4. Vì sự lan truyền đã bị dừng, trình xử lý `onClick` của `` cha *không* chạy.
-As a result of `e.stopPropagation()`, clicking on the buttons now only shows a single alert (from the `
`) rather than the two of them (from the `` and the parent toolbar ``). Clicking a button is not the same thing as clicking the surrounding toolbar, so stopping the propagation makes sense for this UI.
+Do `e.stopPropagation()`, việc nhấp vào các nút bây giờ chỉ hiển thị một cảnh báo duy nhất (từ `
`) thay vì cả hai (từ `` và thanh công cụ `` cha). Nhấp vào một nút không giống như nhấp vào thanh công cụ xung quanh, vì vậy việc dừng lan truyền có ý nghĩa đối với UI này.
-#### Capture phase events {/*capture-phase-events*/}
+#### Sự kiện giai đoạn chụp {/*capture-phase-events*/}
-In rare cases, you might need to catch all events on child elements, *even if they stopped propagation*. For example, maybe you want to log every click to analytics, regardless of the propagation logic. You can do this by adding `Capture` at the end of the event name:
+Trong một số trường hợp hiếm hoi, bạn có thể cần bắt tất cả các sự kiện trên các phần tử con, *ngay cả khi chúng đã dừng lan truyền*. Ví dụ: có thể bạn muốn ghi lại mọi nhấp chuột vào phân tích, bất kể logic lan truyền. Bạn có thể làm điều này bằng cách thêm `Capture` vào cuối tên sự kiện:
```js
- { /* this runs first */ }}>
+
{ /* điều này chạy trước */ }}>
e.stopPropagation()} />
e.stopPropagation()} />
```
-Each event propagates in three phases:
+Mỗi sự kiện lan truyền trong ba giai đoạn:
-1. It travels down, calling all `onClickCapture` handlers.
-2. It runs the clicked element's `onClick` handler.
-3. It travels upwards, calling all `onClick` handlers.
+1. Nó di chuyển xuống, gọi tất cả các trình xử lý `onClickCapture`.
+2. Nó chạy trình xử lý `onClick` của phần tử được nhấp.
+3. Nó di chuyển lên trên, gọi tất cả các trình xử lý `onClick`.
-Capture events are useful for code like routers or analytics, but you probably won't use them in app code.
+Sự kiện chụp rất hữu ích cho mã như bộ định tuyến hoặc phân tích, nhưng bạn có thể sẽ không sử dụng chúng trong mã ứng dụng.
-### Passing handlers as alternative to propagation {/*passing-handlers-as-alternative-to-propagation*/}
+### Truyền trình xử lý như một giải pháp thay thế cho lan truyền {/*passing-handlers-as-alternative-to-propagation*/}
-Notice how this click handler runs a line of code _and then_ calls the `onClick` prop passed by the parent:
+Lưu ý cách trình xử lý nhấp chuột này chạy một dòng mã _và sau đó_ gọi prop `onClick` được truyền bởi cha:
```js {4,5}
function Button({ onClick, children }) {
@@ -460,22 +460,22 @@ function Button({ onClick, children }) {
}
```
-You could add more code to this handler before calling the parent `onClick` event handler, too. This pattern provides an *alternative* to propagation. It lets the child component handle the event, while also letting the parent component specify some additional behavior. Unlike propagation, it's not automatic. But the benefit of this pattern is that you can clearly follow the whole chain of code that executes as a result of some event.
+Bạn cũng có thể thêm nhiều mã hơn vào trình xử lý này trước khi gọi trình xử lý sự kiện `onClick` của cha. Mẫu này cung cấp một *giải pháp thay thế* cho lan truyền. Nó cho phép component con xử lý sự kiện, đồng thời cho phép component cha chỉ định một số hành vi bổ sung. Không giống như lan truyền, nó không tự động. Nhưng lợi ích của mẫu này là bạn có thể theo dõi rõ ràng toàn bộ chuỗi mã thực thi do một số sự kiện gây ra.
-If you rely on propagation and it's difficult to trace which handlers execute and why, try this approach instead.
+Nếu bạn dựa vào lan truyền và khó theo dõi trình xử lý nào thực thi và tại sao, hãy thử phương pháp này thay thế.
-### Preventing default behavior {/*preventing-default-behavior*/}
+### Ngăn chặn hành vi mặc định {/*preventing-default-behavior*/}
-Some browser events have default behavior associated with them. For example, a `
);
}
@@ -679,9 +677,9 @@ export default function App() {
-First, you need to add the event handler, like ``.
+Đầu tiên, bạn cần thêm trình xử lý sự kiện, như ``.
-However, this introduces the problem of the incrementing counter. If `onChangeColor` does not do this, as your colleague insists, then the problem is that this event propagates up, and some handler above does it. To solve this problem, you need to stop the propagation. But don't forget that you should still call `onChangeColor`.
+Tuy nhiên, điều này giới thiệu vấn đề về bộ đếm tăng dần. Nếu `onChangeColor` không làm điều này, như đồng nghiệp của bạn khẳng định, thì vấn đề là sự kiện này lan truyền lên trên và một số trình xử lý ở trên thực hiện nó. Để giải quyết vấn đề này, bạn cần dừng lan truyền. Nhưng đừng quên rằng bạn vẫn nên gọi `onChangeColor`.
@@ -694,7 +692,7 @@ export default function ColorSwitch({
e.stopPropagation();
onChangeColor();
}}>
- Change color
+ Thay đổi màu
);
}
@@ -728,7 +726,7 @@ export default function App() {
- Clicks on the page: {clicks}
+ Số lần nhấp trên trang: {clicks}
);
}
diff --git a/src/content/learn/reusing-logic-with-custom-hooks.md b/src/content/learn/reusing-logic-with-custom-hooks.md
index ea8d0a313..c8f923a6d 100644
--- a/src/content/learn/reusing-logic-with-custom-hooks.md
+++ b/src/content/learn/reusing-logic-with-custom-hooks.md
@@ -1091,15 +1091,15 @@ button { margin-left: 10px; }
-Notice how you no longer need to know *how* `useChatRoom` works in order to use it. You could add it to any other component, pass any other options, and it would work the same way. That's the power of custom Hooks.
+Lưu ý rằng bạn không còn cần phải biết *cách* `useChatRoom` hoạt động để sử dụng nó. Bạn có thể thêm nó vào bất kỳ component nào khác, truyền bất kỳ tùy chọn nào khác và nó sẽ hoạt động theo cùng một cách. Đó là sức mạnh của Custom Hook.
-## When to use custom Hooks {/*when-to-use-custom-hooks*/}
+## Khi nào nên sử dụng Custom Hook {/*when-to-use-custom-hooks*/}
-You don't need to extract a custom Hook for every little duplicated bit of code. Some duplication is fine. For example, extracting a `useFormInput` Hook to wrap a single `useState` call like earlier is probably unnecessary.
+Bạn không cần phải trích xuất một Custom Hook cho mọi đoạn code trùng lặp nhỏ. Một số trùng lặp là chấp nhận được. Ví dụ: trích xuất một Hook `useFormInput` để bọc một lệnh gọi `useState` duy nhất như trước đó có lẽ là không cần thiết.
-However, whenever you write an Effect, consider whether it would be clearer to also wrap it in a custom Hook. [You shouldn't need Effects very often,](/learn/you-might-not-need-an-effect) so if you're writing one, it means that you need to "step outside React" to synchronize with some external system or to do something that React doesn't have a built-in API for. Wrapping it into a custom Hook lets you precisely communicate your intent and how the data flows through it.
+Tuy nhiên, bất cứ khi nào bạn viết một Effect, hãy cân nhắc xem liệu việc bọc nó trong một Custom Hook có rõ ràng hơn không. [Bạn không nên cần Effect quá thường xuyên,](/learn/you-might-not-need-an-effect) vì vậy nếu bạn đang viết một Effect, điều đó có nghĩa là bạn cần "bước ra ngoài React" để đồng bộ hóa với một số hệ thống bên ngoài hoặc để làm điều gì đó mà React không có API tích hợp sẵn. Việc bọc nó vào một Custom Hook cho phép bạn truyền đạt chính xác ý định của mình và cách dữ liệu luân chuyển qua nó.
-For example, consider a `ShippingForm` component that displays two dropdowns: one shows the list of cities, and another shows the list of areas in the selected city. You might start with some code that looks like this:
+Ví dụ: hãy xem xét một component `ShippingForm` hiển thị hai dropdown: một hiển thị danh sách các thành phố và một hiển thị danh sách các khu vực trong thành phố đã chọn. Bạn có thể bắt đầu với một số code trông như thế này:
```js {3-16,20-35}
function ShippingForm({ country }) {
@@ -1141,7 +1141,7 @@ function ShippingForm({ country }) {
// ...
```
-Although this code is quite repetitive, [it's correct to keep these Effects separate from each other.](/learn/removing-effect-dependencies#is-your-effect-doing-several-unrelated-things) They synchronize two different things, so you shouldn't merge them into one Effect. Instead, you can simplify the `ShippingForm` component above by extracting the common logic between them into your own `useData` Hook:
+Mặc dù code này khá lặp đi lặp lại, [việc giữ các Effect này tách biệt nhau là đúng.](/learn/removing-effect-dependencies#is-your-effect-doing-several-unrelated-things) Chúng đồng bộ hóa hai thứ khác nhau, vì vậy bạn không nên hợp nhất chúng thành một Effect. Thay vào đó, bạn có thể đơn giản hóa component `ShippingForm` ở trên bằng cách trích xuất logic chung giữa chúng vào Hook `useData` của riêng bạn:
```js {2-18}
function useData(url) {
@@ -1165,7 +1165,7 @@ function useData(url) {
}
```
-Now you can replace both Effects in the `ShippingForm` components with calls to `useData`:
+Bây giờ bạn có thể thay thế cả hai Effect trong các component `ShippingForm` bằng các lệnh gọi đến `useData`:
```js {2,4}
function ShippingForm({ country }) {
@@ -1175,39 +1175,39 @@ function ShippingForm({ country }) {
// ...
```
-Extracting a custom Hook makes the data flow explicit. You feed the `url` in and you get the `data` out. By "hiding" your Effect inside `useData`, you also prevent someone working on the `ShippingForm` component from adding [unnecessary dependencies](/learn/removing-effect-dependencies) to it. With time, most of your app's Effects will be in custom Hooks.
+Việc trích xuất một Custom Hook làm cho luồng dữ liệu trở nên rõ ràng. Bạn đưa `url` vào và bạn nhận được `data` ra. Bằng cách "ẩn" Effect của bạn bên trong `useData`, bạn cũng ngăn ai đó làm việc trên component `ShippingForm` thêm [các dependency không cần thiết](/learn/removing-effect-dependencies) vào nó. Theo thời gian, hầu hết các Effect của ứng dụng của bạn sẽ nằm trong Custom Hook.
-#### Keep your custom Hooks focused on concrete high-level use cases {/*keep-your-custom-hooks-focused-on-concrete-high-level-use-cases*/}
+#### Tập trung Custom Hook của bạn vào các trường hợp sử dụng cấp cao cụ thể {/*keep-your-custom-hooks-focused-on-concrete-high-level-use-cases*/}
-Start by choosing your custom Hook's name. If you struggle to pick a clear name, it might mean that your Effect is too coupled to the rest of your component's logic, and is not yet ready to be extracted.
+Bắt đầu bằng cách chọn tên cho Custom Hook của bạn. Nếu bạn gặp khó khăn trong việc chọn một cái tên rõ ràng, điều đó có thể có nghĩa là Effect của bạn quá gắn liền với phần còn lại của logic component của bạn và chưa sẵn sàng để được trích xuất.
-Ideally, your custom Hook's name should be clear enough that even a person who doesn't write code often could have a good guess about what your custom Hook does, what it takes, and what it returns:
+Lý tưởng nhất là tên Custom Hook của bạn phải đủ rõ ràng để ngay cả một người không viết code thường xuyên cũng có thể đoán được Custom Hook của bạn làm gì, nó nhận gì và nó trả về gì:
* ✅ `useData(url)`
* ✅ `useImpressionLog(eventName, extraData)`
* ✅ `useChatRoom(options)`
-When you synchronize with an external system, your custom Hook name may be more technical and use jargon specific to that system. It's good as long as it would be clear to a person familiar with that system:
+Khi bạn đồng bộ hóa với một hệ thống bên ngoài, tên Custom Hook của bạn có thể mang tính kỹ thuật hơn và sử dụng biệt ngữ dành riêng cho hệ thống đó. Điều đó tốt miễn là nó rõ ràng đối với một người quen thuộc với hệ thống đó:
* ✅ `useMediaQuery(query)`
* ✅ `useSocket(url)`
* ✅ `useIntersectionObserver(ref, options)`
-**Keep custom Hooks focused on concrete high-level use cases.** Avoid creating and using custom "lifecycle" Hooks that act as alternatives and convenience wrappers for the `useEffect` API itself:
+**Tập trung Custom Hook vào các trường hợp sử dụng cấp cao cụ thể.** Tránh tạo và sử dụng Custom Hook "vòng đời" hoạt động như các giải pháp thay thế và trình bao bọc tiện lợi cho chính API `useEffect`:
* 🔴 `useMount(fn)`
* 🔴 `useEffectOnce(fn)`
* 🔴 `useUpdateEffect(fn)`
-For example, this `useMount` Hook tries to ensure some code only runs "on mount":
+Ví dụ: Hook `useMount` này cố gắng đảm bảo một số code chỉ chạy "khi mount":
```js {4-5,14-15}
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
- // 🔴 Avoid: using custom "lifecycle" Hooks
+ // 🔴 Tránh: sử dụng Custom Hook "vòng đời"
useMount(() => {
const connection = createConnection({ roomId, serverUrl });
connection.connect();
@@ -1217,7 +1217,7 @@ function ChatRoom({ roomId }) {
// ...
}
-// 🔴 Avoid: creating custom "lifecycle" Hooks
+// 🔴 Tránh: tạo Custom Hook "vòng đời"
function useMount(fn) {
useEffect(() => {
fn();
@@ -1225,15 +1225,15 @@ function useMount(fn) {
}
```
-**Custom "lifecycle" Hooks like `useMount` don't fit well into the React paradigm.** For example, this code example has a mistake (it doesn't "react" to `roomId` or `serverUrl` changes), but the linter won't warn you about it because the linter only checks direct `useEffect` calls. It won't know about your Hook.
+**Custom Hook "vòng đời" như `useMount` không phù hợp với mô hình React.** Ví dụ: ví dụ code này có một lỗi (nó không "phản ứng" với các thay đổi `roomId` hoặc `serverUrl`), nhưng trình lint sẽ không cảnh báo bạn về điều đó vì trình lint chỉ kiểm tra các lệnh gọi `useEffect` trực tiếp. Nó sẽ không biết về Hook của bạn.
-If you're writing an Effect, start by using the React API directly:
+Nếu bạn đang viết một Effect, hãy bắt đầu bằng cách sử dụng trực tiếp API React:
```js
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
- // ✅ Good: two raw Effects separated by purpose
+ // ✅ Tốt: hai Effect thô được phân tách theo mục đích
useEffect(() => {
const connection = createConnection({ serverUrl, roomId });
@@ -1249,28 +1249,28 @@ function ChatRoom({ roomId }) {
}
```
-Then, you can (but don't have to) extract custom Hooks for different high-level use cases:
+Sau đó, bạn có thể (nhưng không bắt buộc) trích xuất Custom Hook cho các trường hợp sử dụng cấp cao khác nhau:
```js
function ChatRoom({ roomId }) {
const [serverUrl, setServerUrl] = useState('https://localhost:1234');
- // ✅ Great: custom Hooks named after their purpose
+ // ✅ Tuyệt vời: Custom Hook được đặt tên theo mục đích của chúng
useChatRoom({ serverUrl, roomId });
useImpressionLog('visit_chat', { roomId });
// ...
}
```
-**A good custom Hook makes the calling code more declarative by constraining what it does.** For example, `useChatRoom(options)` can only connect to the chat room, while `useImpressionLog(eventName, extraData)` can only send an impression log to the analytics. If your custom Hook API doesn't constrain the use cases and is very abstract, in the long run it's likely to introduce more problems than it solves.
+**Một Custom Hook tốt làm cho code gọi trở nên khai báo hơn bằng cách hạn chế những gì nó làm.** Ví dụ: `useChatRoom(options)` chỉ có thể kết nối với phòng chat, trong khi `useImpressionLog(eventName, extraData)` chỉ có thể gửi nhật ký hiển thị đến phân tích. Nếu API Custom Hook của bạn không hạn chế các trường hợp sử dụng và rất trừu tượng, về lâu dài, nó có khả năng gây ra nhiều vấn đề hơn là giải quyết.
-### Custom Hooks help you migrate to better patterns {/*custom-hooks-help-you-migrate-to-better-patterns*/}
+### Custom Hook giúp bạn di chuyển sang các pattern tốt hơn {/*custom-hooks-help-you-migrate-to-better-patterns*/}
-Effects are an ["escape hatch"](/learn/escape-hatches): you use them when you need to "step outside React" and when there is no better built-in solution for your use case. With time, the React team's goal is to reduce the number of the Effects in your app to the minimum by providing more specific solutions to more specific problems. Wrapping your Effects in custom Hooks makes it easier to upgrade your code when these solutions become available.
+Effect là một ["lối thoát hiểm"](/learn/escape-hatches): bạn sử dụng chúng khi bạn cần "bước ra ngoài React" và khi không có giải pháp tích hợp tốt hơn cho trường hợp sử dụng của bạn. Theo thời gian, mục tiêu của nhóm React là giảm số lượng Effect trong ứng dụng của bạn xuống mức tối thiểu bằng cách cung cấp các giải pháp cụ thể hơn cho các vấn đề cụ thể hơn. Việc bọc Effect của bạn trong Custom Hook giúp bạn dễ dàng nâng cấp code của mình hơn khi các giải pháp này có sẵn.
-Let's return to this example:
+Hãy quay lại ví dụ này:
@@ -1331,9 +1331,9 @@ export function useOnlineStatus() {
-In the above example, `useOnlineStatus` is implemented with a pair of [`useState`](/reference/react/useState) and [`useEffect`.](/reference/react/useEffect) However, this isn't the best possible solution. There is a number of edge cases it doesn't consider. For example, it assumes that when the component mounts, `isOnline` is already `true`, but this may be wrong if the network already went offline. You can use the browser [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) API to check for that, but using it directly would not work on the server for generating the initial HTML. In short, this code could be improved.
+Trong ví dụ trên, `useOnlineStatus` được triển khai với một cặp [`useState`](/reference/react/useState) và [`useEffect`.](/reference/react/useEffect) Tuy nhiên, đây không phải là giải pháp tốt nhất có thể. Có một số trường hợp đặc biệt mà nó không xem xét. Ví dụ: nó giả định rằng khi component mount, `isOnline` đã là `true`, nhưng điều này có thể sai nếu mạng đã ngoại tuyến. Bạn có thể sử dụng API [`navigator.onLine`](https://developer.mozilla.org/en-US/docs/Web/API/Navigator/onLine) của trình duyệt để kiểm tra điều đó, nhưng việc sử dụng trực tiếp nó sẽ không hoạt động trên máy chủ để tạo HTML ban đầu. Tóm lại, code này có thể được cải thiện.
-React includes a dedicated API called [`useSyncExternalStore`](/reference/react/useSyncExternalStore) which takes care of all of these problems for you. Here is your `useOnlineStatus` Hook, rewritten to take advantage of this new API:
+React bao gồm một API chuyên dụng có tên là [`useSyncExternalStore`](/reference/react/useSyncExternalStore) để giải quyết tất cả những vấn đề này cho bạn. Đây là Hook `useOnlineStatus` của bạn, được viết lại để tận dụng API mới này:
@@ -1393,7 +1393,7 @@ export function useOnlineStatus() {
-Notice how **you didn't need to change any of the components** to make this migration:
+Lưu ý rằng **bạn không cần phải thay đổi bất kỳ component nào** để thực hiện việc di chuyển này:
```js {2,7}
function StatusBar() {
@@ -1407,22 +1407,22 @@ function SaveButton() {
}
```
-This is another reason for why wrapping Effects in custom Hooks is often beneficial:
+Đây là một lý do khác tại sao việc bọc Effect trong Custom Hook thường có lợi:
-1. You make the data flow to and from your Effects very explicit.
-2. You let your components focus on the intent rather than on the exact implementation of your Effects.
-3. When React adds new features, you can remove those Effects without changing any of your components.
+1. Bạn làm cho luồng dữ liệu đến và đi từ Effect của bạn rất rõ ràng.
+2. Bạn cho phép các component của bạn tập trung vào ý định hơn là vào việc triển khai chính xác Effect của bạn.
+3. Khi React thêm các tính năng mới, bạn có thể xóa các Effect đó mà không cần thay đổi bất kỳ component nào của bạn.
-Similar to a [design system,](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969) you might find it helpful to start extracting common idioms from your app's components into custom Hooks. This will keep your components' code focused on the intent, and let you avoid writing raw Effects very often. Many excellent custom Hooks are maintained by the React community.
+Tương tự như một [hệ thống thiết kế,](https://uxdesign.cc/everything-you-need-to-know-about-design-systems-54b109851969) bạn có thể thấy hữu ích khi bắt đầu trích xuất các thành ngữ phổ biến từ các component của ứng dụng của bạn vào Custom Hook. Điều này sẽ giúp code của các component của bạn tập trung vào ý định và cho phép bạn tránh viết Effect thô rất thường xuyên. Nhiều Custom Hook tuyệt vời được duy trì bởi cộng đồng React.
-#### Will React provide any built-in solution for data fetching? {/*will-react-provide-any-built-in-solution-for-data-fetching*/}
+#### React sẽ cung cấp bất kỳ giải pháp tích hợp sẵn nào để tìm nạp dữ liệu không? {/*will-react-provide-any-built-in-solution-for-data-fetching*/}
-We're still working out the details, but we expect that in the future, you'll write data fetching like this:
+Chúng tôi vẫn đang hoàn thiện các chi tiết, nhưng chúng tôi hy vọng rằng trong tương lai, bạn sẽ viết code tìm nạp dữ liệu như thế này:
```js {1,4,6}
-import { use } from 'react'; // Not available yet!
+import { use } from 'react'; // Chưa có sẵn!
function ShippingForm({ country }) {
const cities = use(fetch(`/api/cities?country=${country}`));
@@ -1431,13 +1431,13 @@ function ShippingForm({ country }) {
// ...
```
-If you use custom Hooks like `useData` above in your app, it will require fewer changes to migrate to the eventually recommended approach than if you write raw Effects in every component manually. However, the old approach will still work fine, so if you feel happy writing raw Effects, you can continue to do that.
+Nếu bạn sử dụng Custom Hook như `useData` ở trên trong ứng dụng của mình, bạn sẽ yêu cầu ít thay đổi hơn để di chuyển sang phương pháp được đề xuất cuối cùng so với việc bạn viết Effect thô trong mọi component theo cách thủ công. Tuy nhiên, phương pháp cũ vẫn sẽ hoạt động tốt, vì vậy nếu bạn cảm thấy hài lòng khi viết Effect thô, bạn có thể tiếp tục làm điều đó.
-### There is more than one way to do it {/*there-is-more-than-one-way-to-do-it*/}
+### Có nhiều hơn một cách để làm điều đó {/*there-is-more-than-one-way-to-do-it*/}
-Let's say you want to implement a fade-in animation *from scratch* using the browser [`requestAnimationFrame`](https://developer.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) API. You might start with an Effect that sets up an animation loop. During each frame of the animation, you could change the opacity of the DOM node you [hold in a ref](/learn/manipulating-the-dom-with-refs) until it reaches `1`. Your code might start like this:
+Giả sử bạn muốn triển khai một hiệu ứng hoạt ảnh mờ dần *từ đầu* bằng API [`requestAnimationFrame`](https://developer.mozilla.mozilla.org/en-US/docs/Web/API/window/requestAnimationFrame) của trình duyệt. Bạn có thể bắt đầu với một Effect thiết lập một vòng lặp hoạt ảnh. Trong mỗi khung hình của hoạt ảnh, bạn có thể thay đổi độ mờ của nút DOM mà bạn [giữ trong một ref](/learn/manipulating-the-dom-with-refs) cho đến khi nó đạt đến `1`. Code của bạn có thể bắt đầu như thế này:
@@ -1520,7 +1520,7 @@ html, body { min-height: 300px; }
-To make the component more readable, you might extract the logic into a `useFadeIn` custom Hook:
+Để làm cho component dễ đọc hơn, bạn có thể trích xuất logic vào một Custom Hook `useFadeIn`:
@@ -1611,7 +1611,7 @@ html, body { min-height: 300px; }
-You could keep the `useFadeIn` code as is, but you could also refactor it more. For example, you could extract the logic for setting up the animation loop out of `useFadeIn` into a custom `useAnimationLoop` Hook:
+Bạn có thể giữ code `useFadeIn` như hiện tại, nhưng bạn cũng có thể tái cấu trúc nó nhiều hơn. Ví dụ: bạn có thể trích xuất logic để thiết lập vòng lặp hoạt ảnh ra khỏi `useFadeIn` vào một Hook `useAnimationLoop` tùy chỉnh:
@@ -1715,7 +1715,7 @@ html, body { min-height: 300px; }
-However, you didn't *have to* do that. As with regular functions, ultimately you decide where to draw the boundaries between different parts of your code. You could also take a very different approach. Instead of keeping the logic in the Effect, you could move most of the imperative logic inside a JavaScript [class:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes)
+Tuy nhiên, bạn không *bắt buộc* phải làm điều đó. Như với các hàm thông thường, cuối cùng bạn quyết định nơi vẽ ranh giới giữa các phần khác nhau của code của bạn. Bạn cũng có thể thực hiện một cách tiếp cận rất khác. Thay vì giữ logic trong Effect, bạn có thể di chuyển hầu hết logic mệnh lệnh bên trong một [class:](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) JavaScript:
@@ -1813,9 +1813,9 @@ html, body { min-height: 300px; }
-Effects let you connect React to external systems. The more coordination between Effects is needed (for example, to chain multiple animations), the more it makes sense to extract that logic out of Effects and Hooks *completely* like in the sandbox above. Then, the code you extracted *becomes* the "external system". This lets your Effects stay simple because they only need to send messages to the system you've moved outside React.
+Effect cho phép bạn kết nối React với các hệ thống bên ngoài. Càng cần nhiều sự phối hợp giữa các Effect (ví dụ: để xâu chuỗi nhiều hoạt ảnh), thì càng có ý nghĩa khi trích xuất logic đó ra khỏi Effect và Hook *hoàn toàn* như trong sandbox ở trên. Sau đó, code bạn đã trích xuất *trở thành* "hệ thống bên ngoài". Điều này cho phép Effect của bạn luôn đơn giản vì chúng chỉ cần gửi tin nhắn đến hệ thống bạn đã di chuyển ra ngoài React.
-The examples above assume that the fade-in logic needs to be written in JavaScript. However, this particular fade-in animation is both simpler and much more efficient to implement with a plain [CSS Animation:](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations)
+Các ví dụ trên giả định rằng logic mờ dần cần được viết bằng JavaScript. Tuy nhiên, hoạt ảnh mờ dần cụ thể này vừa đơn giản hơn vừa hiệu quả hơn nhiều để triển khai với một [Hoạt ảnh CSS:](https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Animations/Using_CSS_animations) đơn giản:
@@ -1870,27 +1870,27 @@ html, body { min-height: 300px; }
-Sometimes, you don't even need a Hook!
+Đôi khi, bạn thậm chí không cần một Hook!
-- Custom Hooks let you share logic between components.
-- Custom Hooks must be named starting with `use` followed by a capital letter.
-- Custom Hooks only share stateful logic, not state itself.
-- You can pass reactive values from one Hook to another, and they stay up-to-date.
-- All Hooks re-run every time your component re-renders.
-- The code of your custom Hooks should be pure, like your component's code.
-- Wrap event handlers received by custom Hooks into Effect Events.
-- Don't create custom Hooks like `useMount`. Keep their purpose specific.
-- It's up to you how and where to choose the boundaries of your code.
+- Custom Hooks cho phép bạn chia sẻ logic giữa các component.
+- Custom Hooks phải được đặt tên bắt đầu bằng `use` theo sau là một chữ cái viết hoa.
+- Custom Hooks chỉ chia sẻ logic có trạng thái, không phải bản thân trạng thái.
+- Bạn có thể truyền các giá trị phản ứng từ Hook này sang Hook khác và chúng luôn được cập nhật.
+- Tất cả các Hook chạy lại mỗi khi component của bạn re-render.
+- Code của custom Hooks của bạn phải thuần khiết, giống như code của component của bạn.
+- Bọc các trình xử lý sự kiện nhận được bởi custom Hooks vào Effect Events.
+- Không tạo custom Hooks như `useMount`. Giữ cho mục đích của chúng cụ thể.
+- Tùy thuộc vào bạn cách và nơi chọn ranh giới code của bạn.
-#### Extract a `useCounter` Hook {/*extract-a-usecounter-hook*/}
+#### Trích xuất một Hook `useCounter` {/*extract-a-usecounter-hook*/}
-This component uses a state variable and an Effect to display a number that increments every second. Extract this logic into a custom Hook called `useCounter`. Your goal is to make the `Counter` component implementation look exactly like this:
+Component này sử dụng một biến trạng thái và một Effect để hiển thị một số tăng lên mỗi giây. Trích xuất logic này vào một custom Hook có tên là `useCounter`. Mục tiêu của bạn là làm cho việc triển khai component `Counter` trông giống hệt như sau:
```js
export default function Counter() {
@@ -1899,7 +1899,7 @@ export default function Counter() {
}
```
-You'll need to write your custom Hook in `useCounter.js` and import it into the `App.js` file.
+Bạn sẽ cần viết custom Hook của mình trong `useCounter.js` và import nó vào file `App.js`.
@@ -1919,14 +1919,14 @@ export default function Counter() {
```
```js src/useCounter.js
-// Write your custom Hook in this file!
+// Viết custom Hook của bạn trong file này!
```
-Your code should look like this:
+Code của bạn sẽ trông như thế này:
@@ -1956,13 +1956,13 @@ export function useCounter() {
-Notice that `App.js` doesn't need to import `useState` or `useEffect` anymore.
+Lưu ý rằng `App.js` không cần import `useState` hoặc `useEffect` nữa.
-#### Make the counter delay configurable {/*make-the-counter-delay-configurable*/}
+#### Làm cho độ trễ của bộ đếm có thể cấu hình được {/*make-the-counter-delay-configurable*/}
-In this example, there is a `delay` state variable controlled by a slider, but its value is not used. Pass the `delay` value to your custom `useCounter` Hook, and change the `useCounter` Hook to use the passed `delay` instead of hardcoding `1000` ms.
+Trong ví dụ này, có một biến trạng thái `delay` được điều khiển bởi một thanh trượt, nhưng giá trị của nó không được sử dụng. Truyền giá trị `delay` cho custom Hook `useCounter` của bạn và thay đổi Hook `useCounter` để sử dụng `delay` đã truyền thay vì mã hóa cứng `1000` ms.
@@ -2012,7 +2012,7 @@ export function useCounter() {
-Pass the `delay` to your Hook with `useCounter(delay)`. Then, inside the Hook, use `delay` instead of the hardcoded `1000` value. You'll need to add `delay` to your Effect's dependencies. This ensures that a change in `delay` will reset the interval.
+Truyền `delay` cho Hook của bạn với `useCounter(delay)`. Sau đó, bên trong Hook, sử dụng `delay` thay vì giá trị `1000` được mã hóa cứng. Bạn sẽ cần thêm `delay` vào các dependency của Effect của bạn. Điều này đảm bảo rằng một thay đổi trong `delay` sẽ reset interval.
@@ -2062,9 +2062,9 @@ export function useCounter(delay) {
-#### Extract `useInterval` out of `useCounter` {/*extract-useinterval-out-of-usecounter*/}
+#### Trích xuất `useInterval` ra khỏi `useCounter` {/*extract-useinterval-out-of-usecounter*/}
-Currently, your `useCounter` Hook does two things. It sets up an interval, and it also increments a state variable on every interval tick. Split out the logic that sets up the interval into a separate Hook called `useInterval`. It should take two arguments: the `onTick` callback, and the `delay`. After this change, your `useCounter` implementation should look like this:
+Hiện tại, Hook `useCounter` của bạn thực hiện hai việc. Nó thiết lập một interval và nó cũng tăng một biến trạng thái trên mỗi tick của interval. Chia logic thiết lập interval thành một Hook riêng biệt có tên là `useInterval`. Nó sẽ nhận hai đối số: callback `onTick` và `delay`. Sau thay đổi này, việc triển khai `useCounter` của bạn sẽ trông như thế này:
```js
export function useCounter(delay) {
@@ -2076,7 +2076,7 @@ export function useCounter(delay) {
}
```
-Write `useInterval` in the `useInterval.js` file and import it into the `useCounter.js` file.
+Viết `useInterval` trong file `useInterval.js` và import nó vào file `useCounter.js`.
@@ -2106,14 +2106,14 @@ export function useCounter(delay) {
```
```js src/useInterval.js
-// Write your Hook here!
+// Viết Hook của bạn ở đây!
```
-The logic inside `useInterval` should set up and clear the interval. It doesn't need to do anything else.
+Logic bên trong `useInterval` sẽ thiết lập và xóa interval. Nó không cần phải làm bất cứ điều gì khác.
@@ -2137,51 +2137,51 @@ export function useCounter(delay) {
}, delay);
return count;
}
-```
-
```js src/useInterval.js active
import { useEffect } from 'react';
+import { experimental_useEffectEvent as useEffectEvent } from 'react';
-export function useInterval(onTick, delay) {
+export function useInterval(callback, delay) {
+ const onTick = useEffectEvent(callback);
useEffect(() => {
const id = setInterval(onTick, delay);
return () => clearInterval(id);
- }, [onTick, delay]);
+ }, [delay]);
}
```
-Note that there is a bit of a problem with this solution, which you'll solve in the next challenge.
+Lưu ý rằng có một chút vấn đề với giải pháp này, bạn sẽ giải quyết nó trong thử thách tiếp theo.
-#### Fix a resetting interval {/*fix-a-resetting-interval*/}
+#### Sửa lỗi interval bị reset {/*fix-a-resetting-interval*/}
-In this example, there are *two* separate intervals.
+Trong ví dụ này, có *hai* interval riêng biệt.
-The `App` component calls `useCounter`, which calls `useInterval` to update the counter every second. But the `App` component *also* calls `useInterval` to randomly update the page background color every two seconds.
+Component `App` gọi `useCounter`, cái mà gọi `useInterval` để cập nhật bộ đếm mỗi giây. Nhưng component `App` *cũng* gọi `useInterval` để cập nhật ngẫu nhiên màu nền trang mỗi hai giây.
-For some reason, the callback that updates the page background never runs. Add some logs inside `useInterval`:
+Vì một vài lý do, callback mà cập nhật màu nền trang không bao giờ chạy. Thêm một vài log bên trong `useInterval`:
```js {2,5}
useEffect(() => {
- console.log('✅ Setting up an interval with delay ', delay)
+ console.log('✅ Thiết lập một interval với độ trễ ', delay)
const id = setInterval(onTick, delay);
return () => {
- console.log('❌ Clearing an interval with delay ', delay)
+ console.log('❌ Xóa một interval với độ trễ ', delay)
clearInterval(id);
};
}, [onTick, delay]);
```
-Do the logs match what you expect to happen? If some of your Effects seem to re-synchronize unnecessarily, can you guess which dependency is causing that to happen? Is there some way to [remove that dependency](/learn/removing-effect-dependencies) from your Effect?
+Các log có khớp với những gì bạn mong đợi xảy ra không? Nếu một vài Effect của bạn có vẻ như đồng bộ hóa lại một cách không cần thiết, bạn có thể đoán dependency nào gây ra điều đó không? Có cách nào để [xóa dependency đó](/learn/removing-effect-dependencies) khỏi Effect của bạn không?
-After you fix the issue, you should expect the page background to update every two seconds.
+Sau khi bạn sửa lỗi, bạn nên mong đợi màu nền trang cập nhật mỗi hai giây.
-It looks like your `useInterval` Hook accepts an event listener as an argument. Can you think of some way to wrap that event listener so that it doesn't need to be a dependency of your Effect?
+Có vẻ như Hook `useInterval` của bạn chấp nhận một trình xử lý sự kiện làm đối số. Bạn có thể nghĩ ra cách nào để bọc trình xử lý sự kiện đó để nó không cần phải là một dependency của Effect của bạn không?
@@ -2250,11 +2250,11 @@ export function useInterval(onTick, delay) {
-Inside `useInterval`, wrap the tick callback into an Effect Event, as you did [earlier on this page.](/learn/reusing-logic-with-custom-hooks#passing-event-handlers-to-custom-hooks)
+Bên trong `useInterval`, bọc callback tick vào một Effect Event, như bạn đã làm [trước đó trên trang này.](/learn/reusing-logic-with-custom-hooks#passing-event-handlers-to-custom-hooks)
-This will allow you to omit `onTick` from dependencies of your Effect. The Effect won't re-synchronize on every re-render of the component, so the page background color change interval won't get reset every second before it has a chance to fire.
+Điều này sẽ cho phép bạn bỏ qua `onTick` khỏi các dependency của Effect của bạn. Effect sẽ không đồng bộ hóa lại trên mỗi lần re-render của component, vì vậy interval thay đổi màu nền trang sẽ không bị reset mỗi giây trước khi nó có cơ hội kích hoạt.
-With this change, both intervals work as expected and don't interfere with each other:
+Với thay đổi này, cả hai interval hoạt động như mong đợi và không can thiệp lẫn nhau:
@@ -2321,21 +2321,21 @@ export function useInterval(callback, delay) {
-#### Implement a staggering movement {/*implement-a-staggering-movement*/}
+#### Triển khai một chuyển động so le {/*implement-a-staggering-movement*/}
-In this example, the `usePointerPosition()` Hook tracks the current pointer position. Try moving your cursor or your finger over the preview area and see the red dot follow your movement. Its position is saved in the `pos1` variable.
+Trong ví dụ này, Hook `usePointerPosition()` theo dõi vị trí con trỏ hiện tại. Hãy thử di chuyển con trỏ hoặc ngón tay của bạn trên khu vực xem trước và xem dấu chấm màu đỏ theo dõi chuyển động của bạn. Vị trí của nó được lưu trong biến `pos1`.
-In fact, there are five (!) different red dots being rendered. You don't see them because currently they all appear at the same position. This is what you need to fix. What you want to implement instead is a "staggered" movement: each dot should "follow" the previous dot's path. For example, if you quickly move your cursor, the first dot should follow it immediately, the second dot should follow the first dot with a small delay, the third dot should follow the second dot, and so on.
+Trên thực tế, có năm (!) dấu chấm màu đỏ khác nhau đang được hiển thị. Bạn không nhìn thấy chúng vì hiện tại tất cả chúng đều xuất hiện ở cùng một vị trí. Đây là những gì bạn cần sửa. Thay vào đó, những gì bạn muốn triển khai là một chuyển động "so le": mỗi dấu chấm sẽ "theo dõi" đường đi của dấu chấm trước đó. Ví dụ: nếu bạn nhanh chóng di chuyển con trỏ, dấu chấm đầu tiên sẽ theo dõi nó ngay lập tức, dấu chấm thứ hai sẽ theo dõi dấu chấm đầu tiên với một độ trễ nhỏ, dấu chấm thứ ba sẽ theo dõi dấu chấm thứ hai, v.v.
-You need to implement the `useDelayedValue` custom Hook. Its current implementation returns the `value` provided to it. Instead, you want to return the value back from `delay` milliseconds ago. You might need some state and an Effect to do this.
+Bạn cần triển khai Hook tùy chỉnh `useDelayedValue`. Triển khai hiện tại của nó trả về `value` được cung cấp cho nó. Thay vào đó, bạn muốn trả về giá trị từ `delay` mili giây trước đó. Bạn có thể cần một số state và Effect để làm điều này.
-After you implement `useDelayedValue`, you should see the dots move following one another.
+Sau khi bạn triển khai `useDelayedValue`, bạn sẽ thấy các dấu chấm di chuyển theo nhau.
-You'll need to store the `delayedValue` as a state variable inside your custom Hook. When the `value` changes, you'll want to run an Effect. This Effect should update `delayedValue` after the `delay`. You might find it helpful to call `setTimeout`.
+Bạn sẽ cần lưu trữ `delayedValue` làm một biến state bên trong Hook tùy chỉnh của bạn. Khi `value` thay đổi, bạn sẽ muốn chạy một Effect. Effect này sẽ cập nhật `delayedValue` sau `delay`. Bạn có thể thấy hữu ích khi gọi `setTimeout`.
-Does this Effect need cleanup? Why or why not?
+Effect này có cần cleanup không? Tại sao có và tại sao không?
@@ -2345,7 +2345,7 @@ Does this Effect need cleanup? Why or why not?
import { usePointerPosition } from './usePointerPosition.js';
function useDelayedValue(value, delay) {
- // TODO: Implement this Hook
+ // TODO: Triển khai Hook này
return value;
}
@@ -2408,7 +2408,7 @@ body { min-height: 300px; }
-Here is a working version. You keep the `delayedValue` as a state variable. When `value` updates, your Effect schedules a timeout to update the `delayedValue`. This is why the `delayedValue` always "lags behind" the actual `value`.
+Đây là một phiên bản đang hoạt động. Bạn giữ `delayedValue` làm một biến state. Khi `value` cập nhật, Effect của bạn lên lịch một timeout để cập nhật `delayedValue`. Đây là lý do tại sao `delayedValue` luôn "tụt hậu" so với `value` thực tế.
@@ -2485,7 +2485,7 @@ body { min-height: 300px; }
-Note that this Effect *does not* need cleanup. If you called `clearTimeout` in the cleanup function, then each time the `value` changes, it would reset the already scheduled timeout. To keep the movement continuous, you want all the timeouts to fire.
+Lưu ý rằng Effect này *không* cần cleanup. Nếu bạn gọi `clearTimeout` trong hàm cleanup, thì mỗi khi `value` thay đổi, nó sẽ reset timeout đã được lên lịch. Để giữ cho chuyển động liên tục, bạn muốn tất cả các timeout được kích hoạt.
diff --git a/src/content/learn/setup.md b/src/content/learn/setup.md
index 2c46ee148..690759dcb 100644
--- a/src/content/learn/setup.md
+++ b/src/content/learn/setup.md
@@ -1,28 +1,28 @@
---
-title: Setup
+title: Thiết lập
---
-React integrates with tools like editors, TypeScript, browser extensions, and compilers. This section will help you get your environment set up.
+React tích hợp với các công cụ như trình soạn thảo, TypeScript, tiện ích mở rộng trình duyệt và trình biên dịch. Phần này sẽ giúp bạn thiết lập môi trường của mình.
-## Editor Setup {/*editor-setup*/}
+## Thiết lập trình soạn thảo {/*editor-setup*/}
-See our [recommended editors](/learn/editor-setup) and learn how to set them up to work with React.
+Xem [các trình soạn thảo được đề xuất](/learn/editor-setup) của chúng tôi và tìm hiểu cách thiết lập chúng để làm việc với React.
-## Using TypeScript {/*using-typescript*/}
+## Sử dụng TypeScript {/*using-typescript*/}
-TypeScript is a popular way to add type definitions to JavaScript codebases. [Learn how to integrate TypeScript into your React projects](/learn/typescript).
+TypeScript là một cách phổ biến để thêm định nghĩa kiểu vào các codebase JavaScript. [Tìm hiểu cách tích hợp TypeScript vào các dự án React của bạn](/learn/typescript).
-## React Developer Tools {/*react-developer-tools*/}
+## Công cụ dành cho nhà phát triển React {/*react-developer-tools*/}
-React Developer Tools is a browser extension that can inspect React components, edit props and state, and identify performance problems. Learn how to install it [here](learn/react-developer-tools).
+Công cụ dành cho nhà phát triển React là một tiện ích mở rộng của trình duyệt có thể kiểm tra các thành phần React, chỉnh sửa đạo cụ và trạng thái, đồng thời xác định các vấn đề về hiệu suất. Tìm hiểu cách cài đặt nó [tại đây](learn/react-developer-tools).
-## React Compiler {/*react-compiler*/}
+## Trình biên dịch React {/*react-compiler*/}
-React Compiler is a tool that automatically optimizes your React app. [Learn more](/learn/react-compiler).
+Trình biên dịch React là một công cụ tự động tối ưu hóa ứng dụng React của bạn. [Tìm hiểu thêm](/learn/react-compiler).
-## Next steps {/*next-steps*/}
+## Các bước tiếp theo {/*next-steps*/}
-Head to the [Quick Start](/learn) guide for a tour of the most important React concepts you will encounter every day.
+Đi tới hướng dẫn [Bắt đầu nhanh](/learn) để tham quan các khái niệm React quan trọng nhất mà bạn sẽ gặp hàng ngày.
diff --git a/src/content/learn/sharing-state-between-components.md b/src/content/learn/sharing-state-between-components.md
index 52eaf28f8..4885e3440 100644
--- a/src/content/learn/sharing-state-between-components.md
+++ b/src/content/learn/sharing-state-between-components.md
@@ -1,31 +1,31 @@
---
-title: Sharing State Between Components
+title: Chia sẻ State giữa các Component
---
-Sometimes, you want the state of two components to always change together. To do it, remove state from both of them, move it to their closest common parent, and then pass it down to them via props. This is known as *lifting state up,* and it's one of the most common things you will do writing React code.
+Đôi khi, bạn muốn state của hai component luôn thay đổi cùng nhau. Để làm điều đó, hãy loại bỏ state khỏi cả hai component, di chuyển nó lên component cha chung gần nhất của chúng, và sau đó truyền nó xuống cho chúng thông qua props. Điều này được gọi là *nâng state lên,* và nó là một trong những điều phổ biến nhất bạn sẽ làm khi viết code React.
-- How to share state between components by lifting it up
-- What are controlled and uncontrolled components
+- Cách chia sẻ state giữa các component bằng cách nâng nó lên
+- Component được kiểm soát và không được kiểm soát là gì
-## Lifting state up by example {/*lifting-state-up-by-example*/}
+## Nâng state lên bằng ví dụ {/*lifting-state-up-by-example*/}
-In this example, a parent `Accordion` component renders two separate `Panel`s:
+Trong ví dụ này, một component `Accordion` cha hiển thị hai `Panel` riêng biệt:
* `Accordion`
- `Panel`
- `Panel`
-Each `Panel` component has a boolean `isActive` state that determines whether its content is visible.
+Mỗi component `Panel` có một state `isActive` kiểu boolean để xác định xem nội dung của nó có hiển thị hay không.
-Press the Show button for both panels:
+Nhấn nút Show cho cả hai panel:
@@ -73,59 +73,59 @@ h3, p { margin: 5px 0px; }
-Notice how pressing one panel's button does not affect the other panel--they are independent.
+Lưu ý rằng việc nhấn nút của một panel không ảnh hưởng đến panel còn lại - chúng độc lập với nhau.
-
+
-Initially, each `Panel`'s `isActive` state is `false`, so they both appear collapsed
+Ban đầu, state `isActive` của mỗi `Panel` là `false`, vì vậy cả hai đều xuất hiện ở trạng thái thu gọn
-
+
-Clicking either `Panel`'s button will only update that `Panel`'s `isActive` state alone
+Nhấp vào nút của `Panel` nào sẽ chỉ cập nhật state `isActive` của riêng `Panel` đó
-**But now let's say you want to change it so that only one panel is expanded at any given time.** With that design, expanding the second panel should collapse the first one. How would you do that?
+**Nhưng bây giờ giả sử bạn muốn thay đổi nó sao cho chỉ một panel được mở rộng tại bất kỳ thời điểm nào.** Với thiết kế đó, việc mở rộng panel thứ hai sẽ thu gọn panel đầu tiên. Bạn sẽ làm điều đó như thế nào?
-To coordinate these two panels, you need to "lift their state up" to a parent component in three steps:
+Để phối hợp hai panel này, bạn cần "nâng state của chúng lên" một component cha theo ba bước:
-1. **Remove** state from the child components.
-2. **Pass** hardcoded data from the common parent.
-3. **Add** state to the common parent and pass it down together with the event handlers.
+1. **Loại bỏ** state khỏi các component con.
+2. **Truyền** dữ liệu được mã hóa cứng từ component cha chung.
+3. **Thêm** state vào component cha chung và truyền nó xuống cùng với các trình xử lý sự kiện.
-This will allow the `Accordion` component to coordinate both `Panel`s and only expand one at a time.
+Điều này sẽ cho phép component `Accordion` điều phối cả hai `Panel` và chỉ mở rộng một `Panel` tại một thời điểm.
-### Step 1: Remove state from the child components {/*step-1-remove-state-from-the-child-components*/}
+### Bước 1: Loại bỏ state khỏi các component con {/*step-1-remove-state-from-the-child-components*/}
-You will give control of the `Panel`'s `isActive` to its parent component. This means that the parent component will pass `isActive` to `Panel` as a prop instead. Start by **removing this line** from the `Panel` component:
+Bạn sẽ cung cấp quyền kiểm soát `isActive` của `Panel` cho component cha của nó. Điều này có nghĩa là component cha sẽ truyền `isActive` cho `Panel` dưới dạng một prop. Bắt đầu bằng cách **xóa dòng này** khỏi component `Panel`:
```js
const [isActive, setIsActive] = useState(false);
```
-And instead, add `isActive` to the `Panel`'s list of props:
+Và thay vào đó, hãy thêm `isActive` vào danh sách các prop của `Panel`:
```js
function Panel({ title, children, isActive }) {
```
-Now the `Panel`'s parent component can *control* `isActive` by [passing it down as a prop.](/learn/passing-props-to-a-component) Conversely, the `Panel` component now has *no control* over the value of `isActive`--it's now up to the parent component!
+Bây giờ component cha của `Panel` có thể *kiểm soát* `isActive` bằng cách [truyền nó xuống dưới dạng một prop.](/learn/passing-props-to-a-component) Ngược lại, component `Panel` bây giờ *không có quyền kiểm soát* đối với giá trị của `isActive` - bây giờ nó phụ thuộc vào component cha!
-### Step 2: Pass hardcoded data from the common parent {/*step-2-pass-hardcoded-data-from-the-common-parent*/}
+### Bước 2: Truyền dữ liệu được mã hóa cứng từ component cha chung {/*step-2-pass-hardcoded-data-from-the-common-parent*/}
-To lift state up, you must locate the closest common parent component of *both* of the child components that you want to coordinate:
+Để nâng state lên, bạn phải xác định vị trí component cha chung gần nhất của *cả hai* component con mà bạn muốn phối hợp:
-* `Accordion` *(closest common parent)*
+* `Accordion` *(component cha chung gần nhất)*
- `Panel`
- `Panel`
-In this example, it's the `Accordion` component. Since it's above both panels and can control their props, it will become the "source of truth" for which panel is currently active. Make the `Accordion` component pass a hardcoded value of `isActive` (for example, `true`) to both panels:
+Trong ví dụ này, đó là component `Accordion`. Vì nó nằm trên cả hai panel và có thể kiểm soát các prop của chúng, nó sẽ trở thành "nguồn sự thật" cho panel nào hiện đang hoạt động. Làm cho component `Accordion` truyền một giá trị được mã hóa cứng của `isActive` (ví dụ: `true`) cho cả hai panel:
@@ -172,21 +172,21 @@ h3, p { margin: 5px 0px; }
-Try editing the hardcoded `isActive` values in the `Accordion` component and see the result on the screen.
+Hãy thử chỉnh sửa các giá trị `isActive` được mã hóa cứng trong component `Accordion` và xem kết quả trên màn hình.
-### Step 3: Add state to the common parent {/*step-3-add-state-to-the-common-parent*/}
+### Bước 3: Thêm state vào component cha chung {/*step-3-add-state-to-the-common-parent*/}
-Lifting state up often changes the nature of what you're storing as state.
+Việc nâng state lên thường thay đổi bản chất của những gì bạn đang lưu trữ dưới dạng state.
-In this case, only one panel should be active at a time. This means that the `Accordion` common parent component needs to keep track of *which* panel is the active one. Instead of a `boolean` value, it could use a number as the index of the active `Panel` for the state variable:
+Trong trường hợp này, chỉ một panel sẽ hoạt động tại một thời điểm. Điều này có nghĩa là component cha chung `Accordion` cần theo dõi *panel nào* đang hoạt động. Thay vì một giá trị `boolean`, nó có thể sử dụng một số làm chỉ mục của `Panel` đang hoạt động cho biến state:
```js
const [activeIndex, setActiveIndex] = useState(0);
```
-When the `activeIndex` is `0`, the first panel is active, and when it's `1`, it's the second one.
+Khi `activeIndex` là `0`, panel đầu tiên đang hoạt động và khi nó là `1`, panel thứ hai đang hoạt động.
-Clicking the "Show" button in either `Panel` needs to change the active index in `Accordion`. A `Panel` can't set the `activeIndex` state directly because it's defined inside the `Accordion`. The `Accordion` component needs to *explicitly allow* the `Panel` component to change its state by [passing an event handler down as a prop](/learn/responding-to-events#passing-event-handlers-as-props):
+Việc nhấp vào nút "Show" trong một trong hai `Panel` cần thay đổi chỉ mục hoạt động trong `Accordion`. Một `Panel` không thể đặt state `activeIndex` trực tiếp vì nó được xác định bên trong `Accordion`. Component `Accordion` cần *cho phép rõ ràng* component `Panel` thay đổi state của nó bằng cách [truyền một trình xử lý sự kiện xuống dưới dạng một prop](/learn/responding-to-events#passing-event-handlers-as-props):
```js
<>
@@ -205,7 +205,7 @@ Clicking the "Show" button in either `Panel` needs to change the active index in
>
```
-The `` inside the `Panel` will now use the `onShow` prop as its click event handler:
+`` bên trong `Panel` bây giờ sẽ sử dụng prop `onShow` làm trình xử lý sự kiện nhấp chuột của nó:
@@ -266,19 +266,19 @@ h3, p { margin: 5px 0px; }
-This completes lifting state up! Moving state into the common parent component allowed you to coordinate the two panels. Using the active index instead of two "is shown" flags ensured that only one panel is active at a given time. And passing down the event handler to the child allowed the child to change the parent's state.
+Điều này hoàn thành việc nâng state lên! Việc di chuyển state vào component cha chung cho phép bạn điều phối hai panel. Sử dụng chỉ mục hoạt động thay vì hai cờ "is shown" đảm bảo rằng chỉ một panel hoạt động tại một thời điểm. Và việc truyền trình xử lý sự kiện xuống cho con cho phép con thay đổi state của cha.
-
+
-Initially, `Accordion`'s `activeIndex` is `0`, so the first `Panel` receives `isActive = true`
+Ban đầu, `activeIndex` của `Accordion` là `0`, vì vậy `Panel` đầu tiên nhận được `isActive = true`
-
+
-When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receives `isActive = true` instead
+Khi state `activeIndex` của `Accordion` thay đổi thành `1`, `Panel` thứ hai sẽ nhận được `isActive = true` thay thế
@@ -286,48 +286,48 @@ When `Accordion`'s `activeIndex` state changes to `1`, the second `Panel` receiv
-#### Controlled and uncontrolled components {/*controlled-and-uncontrolled-components*/}
+#### Component được kiểm soát và không được kiểm soát {/*controlled-and-uncontrolled-components*/}
-It is common to call a component with some local state "uncontrolled". For example, the original `Panel` component with an `isActive` state variable is uncontrolled because its parent cannot influence whether the panel is active or not.
+Người ta thường gọi một component có một số state cục bộ là "không được kiểm soát". Ví dụ: component `Panel` ban đầu với một biến state `isActive` là không được kiểm soát vì cha của nó không thể ảnh hưởng đến việc panel có hoạt động hay không.
-In contrast, you might say a component is "controlled" when the important information in it is driven by props rather than its own local state. This lets the parent component fully specify its behavior. The final `Panel` component with the `isActive` prop is controlled by the `Accordion` component.
+Ngược lại, bạn có thể nói một component là "được kiểm soát" khi thông tin quan trọng trong đó được điều khiển bởi props thay vì state cục bộ của chính nó. Điều này cho phép component cha chỉ định đầy đủ hành vi của nó. Component `Panel` cuối cùng với prop `isActive` được kiểm soát bởi component `Accordion`.
-Uncontrolled components are easier to use within their parents because they require less configuration. But they're less flexible when you want to coordinate them together. Controlled components are maximally flexible, but they require the parent components to fully configure them with props.
+Các component không được kiểm soát dễ sử dụng hơn trong cha của chúng vì chúng yêu cầu ít cấu hình hơn. Nhưng chúng kém linh hoạt hơn khi bạn muốn phối hợp chúng với nhau. Các component được kiểm soát có tính linh hoạt tối đa, nhưng chúng yêu cầu các component cha định cấu hình chúng đầy đủ bằng props.
-In practice, "controlled" and "uncontrolled" aren't strict technical terms--each component usually has some mix of both local state and props. However, this is a useful way to talk about how components are designed and what capabilities they offer.
+Trong thực tế, "được kiểm soát" và "không được kiểm soát" không phải là các thuật ngữ kỹ thuật nghiêm ngặt - mỗi component thường có một số kết hợp giữa state cục bộ và props. Tuy nhiên, đây là một cách hữu ích để nói về cách các component được thiết kế và những khả năng mà chúng cung cấp.
-When writing a component, consider which information in it should be controlled (via props), and which information should be uncontrolled (via state). But you can always change your mind and refactor later.
+Khi viết một component, hãy xem xét thông tin nào trong đó nên được kiểm soát (thông qua props) và thông tin nào nên không được kiểm soát (thông qua state). Nhưng bạn luôn có thể thay đổi ý định và tái cấu trúc sau này.
-## A single source of truth for each state {/*a-single-source-of-truth-for-each-state*/}
+## Một nguồn sự thật duy nhất cho mỗi state {/*a-single-source-of-truth-for-each-state*/}
-In a React application, many components will have their own state. Some state may "live" close to the leaf components (components at the bottom of the tree) like inputs. Other state may "live" closer to the top of the app. For example, even client-side routing libraries are usually implemented by storing the current route in the React state, and passing it down by props!
+Trong một ứng dụng React, nhiều component sẽ có state riêng của chúng. Một số state có thể "sống" gần các component lá (các component ở dưới cùng của cây) như các input. Các state khác có thể "sống" gần đầu ứng dụng hơn. Ví dụ: ngay cả các thư viện định tuyến phía máy khách thường được triển khai bằng cách lưu trữ tuyến đường hiện tại trong state React và truyền nó xuống bằng props!
-**For each unique piece of state, you will choose the component that "owns" it.** This principle is also known as having a ["single source of truth".](https://en.wikipedia.org/wiki/Single_source_of_truth) It doesn't mean that all state lives in one place--but that for _each_ piece of state, there is a _specific_ component that holds that piece of information. Instead of duplicating shared state between components, *lift it up* to their common shared parent, and *pass it down* to the children that need it.
+**Đối với mỗi phần state duy nhất, bạn sẽ chọn component "sở hữu" nó.** Nguyên tắc này còn được gọi là có một ["nguồn sự thật duy nhất".](https://en.wikipedia.org/wiki/Single_source_of_truth) Nó không có nghĩa là tất cả state đều sống ở một nơi - nhưng đối với _mỗi_ phần state, có một component _cụ thể_ giữ phần thông tin đó. Thay vì sao chép state được chia sẻ giữa các component, hãy *nâng nó lên* component cha được chia sẻ chung của chúng và *truyền nó xuống* cho các con cần nó.
-Your app will change as you work on it. It is common that you will move state down or back up while you're still figuring out where each piece of the state "lives". This is all part of the process!
+Ứng dụng của bạn sẽ thay đổi khi bạn làm việc trên nó. Thông thường, bạn sẽ di chuyển state xuống hoặc trở lại khi bạn vẫn đang tìm hiểu xem mỗi phần state "sống" ở đâu. Đây là tất cả một phần của quá trình!
-To see what this feels like in practice with a few more components, read [Thinking in React.](/learn/thinking-in-react)
+Để xem điều này cảm thấy như thế nào trong thực tế với một vài component khác, hãy đọc [Tư duy trong React.](/learn/thinking-in-react)
-* When you want to coordinate two components, move their state to their common parent.
-* Then pass the information down through props from their common parent.
-* Finally, pass the event handlers down so that the children can change the parent's state.
-* It's useful to consider components as "controlled" (driven by props) or "uncontrolled" (driven by state).
+* Khi bạn muốn điều phối hai component, hãy di chuyển state của chúng đến cha chung của chúng.
+* Sau đó, truyền thông tin xuống thông qua props từ cha chung của chúng.
+* Cuối cùng, truyền các trình xử lý sự kiện xuống để các con có thể thay đổi state của cha.
+* Thật hữu ích khi xem xét các component là "được kiểm soát" (được điều khiển bởi props) hoặc "không được kiểm soát" (được điều khiển bởi state).
-#### Synced inputs {/*synced-inputs*/}
+#### Các input được đồng bộ hóa {/*synced-inputs*/}
-These two inputs are independent. Make them stay in sync: editing one input should update the other input with the same text, and vice versa.
+Hai input này độc lập với nhau. Làm cho chúng luôn đồng bộ: việc chỉnh sửa một input sẽ cập nhật input còn lại bằng cùng một văn bản và ngược lại.
-You'll need to lift their state up into the parent component.
+Bạn sẽ cần nâng state của chúng lên component cha.
@@ -374,7 +374,7 @@ label { display: block; }
-Move the `text` state variable into the parent component along with the `handleChange` handler. Then pass them down as props to both of the `Input` components. This will keep them in sync.
+Di chuyển biến state `text` vào component cha cùng với trình xử lý `handleChange`. Sau đó, truyền chúng xuống dưới dạng props cho cả hai component `Input`. Điều này sẽ giữ cho chúng đồng bộ.
@@ -427,17 +427,17 @@ label { display: block; }
-#### Filtering a list {/*filtering-a-list*/}
+#### Lọc một danh sách {/*filtering-a-list*/}
-In this example, the `SearchBar` has its own `query` state that controls the text input. Its parent `FilterableList` component displays a `List` of items, but it doesn't take the search query into account.
+Trong ví dụ này, `SearchBar` có state `query` riêng để kiểm soát input văn bản. Component `FilterableList` cha của nó hiển thị một `List` các mục, nhưng nó không tính đến truy vấn tìm kiếm.
-Use the `filterItems(foods, query)` function to filter the list according to the search query. To test your changes, verify that typing "s" into the input filters down the list to "Sushi", "Shish kebab", and "Dim sum".
+Sử dụng hàm `filterItems(foods, query)` để lọc danh sách theo truy vấn tìm kiếm. Để kiểm tra các thay đổi của bạn, hãy xác minh rằng việc nhập "s" vào input sẽ lọc danh sách xuống còn "Sushi", "Shish kebab" và "Dim sum".
-Note that `filterItems` is already implemented and imported so you don't need to write it yourself!
+Lưu ý rằng `filterItems` đã được triển khai và nhập, vì vậy bạn không cần phải tự viết nó!
-You will want to remove the `query` state and the `handleChange` handler from the `SearchBar`, and move them to the `FilterableList`. Then pass them down to `SearchBar` as `query` and `onChange` props.
+Bạn sẽ muốn xóa state `query` và trình xử lý `handleChange` khỏi `SearchBar` và di chuyển chúng đến `FilterableList`. Sau đó, truyền chúng xuống `SearchBar` dưới dạng các prop `query` và `onChange`.
@@ -528,7 +528,7 @@ export const foods = [{
-Lift the `query` state up into the `FilterableList` component. Call `filterItems(foods, query)` to get the filtered list and pass it down to the `List`. Now changing the query input is reflected in the list:
+Nâng state `query` lên component `FilterableList`. Gọi `filterItems(foods, query)` để lấy danh sách đã lọc và truyền nó xuống `List`. Bây giờ, việc thay đổi input truy vấn được phản ánh trong danh sách:
diff --git a/src/content/learn/typescript.md b/src/content/learn/typescript.md
index 7edf8eb6e..713927b04 100644
--- a/src/content/learn/typescript.md
+++ b/src/content/learn/typescript.md
@@ -1,73 +1,73 @@
---
-title: Using TypeScript
+title: Sử dụng TypeScript
re: https://github.com/reactjs/react.dev/issues/5960
---
-TypeScript is a popular way to add type definitions to JavaScript codebases. Out of the box, TypeScript [supports JSX](/learn/writing-markup-with-jsx) and you can get full React Web support by adding [`@types/react`](https://www.npmjs.com/package/@types/react) and [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) to your project.
+TypeScript là một cách phổ biến để thêm định nghĩa kiểu vào các codebase JavaScript. Ngay khi xuất xưởng, TypeScript [hỗ trợ JSX](/learn/writing-markup-with-jsx) và bạn có thể nhận được hỗ trợ đầy đủ cho React Web bằng cách thêm [`@types/react`](https://www.npmjs.com/package/@types/react) và [`@types/react-dom`](https://www.npmjs.com/package/@types/react-dom) vào dự án của bạn.
-* [TypeScript with React Components](/learn/typescript#typescript-with-react-components)
-* [Examples of typing with Hooks](/learn/typescript#example-hooks)
-* [Common types from `@types/react`](/learn/typescript/#useful-types)
-* [Further learning locations](/learn/typescript/#further-learning)
+* [TypeScript với React Components](/learn/typescript#typescript-with-react-components)
+* [Ví dụ về cách gõ với Hooks](/learn/typescript#example-hooks)
+* [Các kiểu phổ biến từ `@types/react`](/learn/typescript/#useful-types)
+* [Các địa điểm học tập thêm](/learn/typescript/#further-learning)
-## Installation {/*installation*/}
+## Cài đặt {/*installation*/}
-All [production-grade React frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) offer support for using TypeScript. Follow the framework specific guide for installation:
+Tất cả [các framework React cấp production](/learn/start-a-new-react-project#production-grade-react-frameworks) đều cung cấp hỗ trợ sử dụng TypeScript. Làm theo hướng dẫn cụ thể của framework để cài đặt:
- [Next.js](https://nextjs.org/docs/app/building-your-application/configuring/typescript)
- [Remix](https://remix.run/docs/en/1.19.2/guides/typescript)
- [Gatsby](https://www.gatsbyjs.com/docs/how-to/custom-configuration/typescript/)
- [Expo](https://docs.expo.dev/guides/typescript/)
-### Adding TypeScript to an existing React project {/*adding-typescript-to-an-existing-react-project*/}
+### Thêm TypeScript vào một dự án React hiện có {/*adding-typescript-to-an-existing-react-project*/}
-To install the latest version of React's type definitions:
+Để cài đặt phiên bản mới nhất của các định nghĩa kiểu React:
npm install @types/react @types/react-dom
-The following compiler options need to be set in your `tsconfig.json`:
+Các tùy chọn trình biên dịch sau đây cần được đặt trong `tsconfig.json` của bạn:
-1. `dom` must be included in [`lib`](https://www.typescriptlang.org/tsconfig/#lib) (Note: If no `lib` option is specified, `dom` is included by default).
-1. [`jsx`](https://www.typescriptlang.org/tsconfig/#jsx) must be set to one of the valid options. `preserve` should suffice for most applications.
- If you're publishing a library, consult the [`jsx` documentation](https://www.typescriptlang.org/tsconfig/#jsx) on what value to choose.
+1. `dom` phải được bao gồm trong [`lib`](https://www.typescriptlang.org/tsconfig/#lib) (Lưu ý: Nếu không có tùy chọn `lib` nào được chỉ định, `dom` sẽ được bao gồm theo mặc định).
+2. [`jsx`](https://www.typescriptlang.org/tsconfig/#jsx) phải được đặt thành một trong các tùy chọn hợp lệ. `preserve` sẽ đủ cho hầu hết các ứng dụng.
+ Nếu bạn đang xuất bản một thư viện, hãy tham khảo [`jsx` documentation](https://www.typescriptlang.org/tsconfig/#jsx) về giá trị cần chọn.
-## TypeScript with React Components {/*typescript-with-react-components*/}
+## TypeScript với React Components {/*typescript-with-react-components*/}
-Every file containing JSX must use the `.tsx` file extension. This is a TypeScript-specific extension that tells TypeScript that this file contains JSX.
+Mọi tệp chứa JSX phải sử dụng phần mở rộng tệp `.tsx`. Đây là một phần mở rộng dành riêng cho TypeScript cho TypeScript biết rằng tệp này chứa JSX.
-Writing TypeScript with React is very similar to writing JavaScript with React. The key difference when working with a component is that you can provide types for your component's props. These types can be used for correctness checking and providing inline documentation in editors.
+Viết TypeScript với React rất giống với viết JavaScript với React. Sự khác biệt chính khi làm việc với một component là bạn có thể cung cấp các kiểu cho các props của component đó. Các kiểu này có thể được sử dụng để kiểm tra tính chính xác và cung cấp tài liệu nội tuyến trong trình soạn thảo.
-Taking the [`MyButton` component](/learn#components) from the [Quick Start](/learn) guide, we can add a type describing the `title` for the button:
+Lấy [`MyButton` component](/learn#components) từ hướng dẫn [Quick Start](/learn), chúng ta có thể thêm một kiểu mô tả `title` cho nút:
```tsx src/App.tsx active
function MyButton({ title }: { title: string }) {
return (
- {title}
+ {title}
);
}
export default function MyApp() {
return (
-
-
Welcome to my app
-
-
+
+
Chào mừng đến với ứng dụng của tôi
+
+
);
}
```
@@ -80,34 +80,34 @@ export default App = AppTSX;
-These sandboxes can handle TypeScript code, but they do not run the type-checker. This means you can amend the TypeScript sandboxes to learn, but you won't get any type errors or warnings. To get type-checking, you can use the [TypeScript Playground](https://www.typescriptlang.org/play) or use a more fully-featured online sandbox.
+Các sandbox này có thể xử lý mã TypeScript, nhưng chúng không chạy trình kiểm tra kiểu. Điều này có nghĩa là bạn có thể sửa đổi các sandbox TypeScript để học, nhưng bạn sẽ không nhận được bất kỳ lỗi hoặc cảnh báo kiểu nào. Để nhận được kiểm tra kiểu, bạn có thể sử dụng [TypeScript Playground](https://www.typescriptlang.org/play) hoặc sử dụng một sandbox trực tuyến đầy đủ tính năng hơn.
-This inline syntax is the simplest way to provide types for a component, though once you start to have a few fields to describe it can become unwieldy. Instead, you can use an `interface` or `type` to describe the component's props:
+Cú pháp nội tuyến này là cách đơn giản nhất để cung cấp các kiểu cho một component, mặc dù khi bạn bắt đầu có một vài trường để mô tả, nó có thể trở nên khó sử dụng. Thay vào đó, bạn có thể sử dụng `interface` hoặc `type` để mô tả các props của component:
```tsx src/App.tsx active
interface MyButtonProps {
- /** The text to display inside the button */
+ /** Văn bản để hiển thị bên trong nút */
title: string;
- /** Whether the button can be interacted with */
+ /** Cho dù nút có thể tương tác được hay không */
disabled: boolean;
}
function MyButton({ title, disabled }: MyButtonProps) {
return (
- {title}
+ {title}
);
}
export default function MyApp() {
return (
-
-
Welcome to my app
-
-
+
+
Chào mừng đến với ứng dụng của tôi
+
+
);
}
```
@@ -119,32 +119,31 @@ export default App = AppTSX;
-The type describing your component's props can be as simple or as complex as you need, though they should be an object type described with either a `type` or `interface`. You can learn about how TypeScript describes objects in [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) but you may also be interested in using [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) to describe a prop that can be one of a few different types and the [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) guide for more advanced use cases.
+Kiểu mô tả các props của component của bạn có thể đơn giản hoặc phức tạp tùy theo nhu cầu của bạn, mặc dù chúng phải là một kiểu đối tượng được mô tả bằng `type` hoặc `interface`. Bạn có thể tìm hiểu về cách TypeScript mô tả các đối tượng trong [Object Types](https://www.typescriptlang.org/docs/handbook/2/objects.html) nhưng bạn cũng có thể quan tâm đến việc sử dụng [Union Types](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html#union-types) để mô tả một prop có thể là một trong một vài kiểu khác nhau và hướng dẫn [Creating Types from Types](https://www.typescriptlang.org/docs/handbook/2/types-from-types.html) cho các trường hợp sử dụng nâng cao hơn.
+## Ví dụ Hooks {/*example-hooks*/}
-## Example Hooks {/*example-hooks*/}
+Các định nghĩa kiểu từ `@types/react` bao gồm các kiểu cho các Hook tích hợp, vì vậy bạn có thể sử dụng chúng trong các component của mình mà không cần bất kỳ thiết lập bổ sung nào. Chúng được xây dựng để tính đến mã bạn viết trong component của mình, vì vậy bạn sẽ nhận được [các kiểu được suy luận](https://www.typescriptlang.org/docs/handbook/type-inference.html) rất nhiều và lý tưởng nhất là không cần xử lý các chi tiết nhỏ của việc cung cấp các kiểu.
-The type definitions from `@types/react` include types for the built-in Hooks, so you can use them in your components without any additional setup. They are built to take into account the code you write in your component, so you will get [inferred types](https://www.typescriptlang.org/docs/handbook/type-inference.html) a lot of the time and ideally do not need to handle the minutiae of providing the types.
-
-However, we can look at a few examples of how to provide types for Hooks.
+Tuy nhiên, chúng ta có thể xem xét một vài ví dụ về cách cung cấp các kiểu cho Hooks.
### `useState` {/*typing-usestate*/}
-The [`useState` Hook](/reference/react/useState) will re-use the value passed in as the initial state to determine what the type of the value should be. For example:
+[`useState` Hook](/reference/react/useState) sẽ sử dụng lại giá trị được truyền vào làm trạng thái ban đầu để xác định kiểu của giá trị đó. Ví dụ:
```ts
-// Infer the type as "boolean"
+// Suy luận kiểu là "boolean"
const [enabled, setEnabled] = useState(false);
```
-This will assign the type of `boolean` to `enabled`, and `setEnabled` will be a function accepting either a `boolean` argument, or a function that returns a `boolean`. If you want to explicitly provide a type for the state, you can do so by providing a type argument to the `useState` call:
+Điều này sẽ gán kiểu `boolean` cho `enabled` và `setEnabled` sẽ là một hàm chấp nhận một đối số `boolean` hoặc một hàm trả về một `boolean`. Nếu bạn muốn cung cấp rõ ràng một kiểu cho trạng thái, bạn có thể làm như vậy bằng cách cung cấp một đối số kiểu cho lệnh gọi `useState`:
-```ts
-// Explicitly set the type to "boolean"
+```ts
+// Đặt rõ ràng kiểu thành "boolean"
const [enabled, setEnabled] = useState(false);
```
-This isn't very useful in this case, but a common case where you may want to provide a type is when you have a union type. For example, `status` here can be one of a few different strings:
+Điều này không hữu ích lắm trong trường hợp này, nhưng một trường hợp phổ biến mà bạn có thể muốn cung cấp một kiểu là khi bạn có một kiểu union. Ví dụ: `status` ở đây có thể là một trong một vài chuỗi khác nhau:
```ts
type Status = "idle" | "loading" | "success" | "error";
@@ -152,7 +151,7 @@ type Status = "idle" | "loading" | "success" | "error";
const [status, setStatus] = useState("idle");
```
-Or, as recommended in [Principles for structuring state](/learn/choosing-the-state-structure#principles-for-structuring-state), you can group related state as an object and describe the different possibilities via object types:
+Hoặc, như được khuyến nghị trong [Principles for structuring state](/learn/choosing-the-state-structure#principles-for-structuring-state), bạn có thể nhóm trạng thái liên quan thành một đối tượng và mô tả các khả năng khác nhau thông qua các kiểu đối tượng:
```ts
type RequestState =
@@ -166,7 +165,7 @@ const [requestState, setRequestState] = useState({ status: 'idle'
### `useReducer` {/*typing-usereducer*/}
-The [`useReducer` Hook](/reference/react/useReducer) is a more complex Hook that takes a reducer function and an initial state. The types for the reducer function are inferred from the initial state. You can optionally provide a type argument to the `useReducer` call to provide a type for the state, but it is often better to set the type on the initial state instead:
+[`useReducer` Hook](/reference/react/useReducer) là một Hook phức tạp hơn, lấy một hàm reducer và một trạng thái ban đầu. Các kiểu cho hàm reducer được suy luận từ trạng thái ban đầu. Bạn có thể tùy chọn cung cấp một đối số kiểu cho lệnh gọi `useReducer` để cung cấp một kiểu cho trạng thái, nhưng thường tốt hơn là đặt kiểu trên trạng thái ban đầu thay thế:
@@ -174,7 +173,7 @@ The [`useReducer` Hook](/reference/react/useReducer) is a more complex Hook that
import {useReducer} from 'react';
interface State {
- count: number
+ count: number
};
type CounterAction =
@@ -185,12 +184,12 @@ const initialState: State = { count: 0 };
function stateReducer(state: State, action: CounterAction): State {
switch (action.type) {
- case "reset":
- return initialState;
- case "setCount":
- return { ...state, count: action.value };
- default:
- throw new Error("Unknown action");
+ case "reset":
+ return initialState;
+ case "setCount":
+ return { ...state, count: action.value };
+ default:
+ throw new Error("Unknown action");
}
}
@@ -201,13 +200,13 @@ export default function App() {
const reset = () => dispatch({ type: "reset" });
return (
-
-
Welcome to my counter
+
+
Chào mừng đến với bộ đếm của tôi
-
Count: {state.count}
-
Add 5
-
Reset
-
+
Đếm: {state.count}
+
Thêm 5
+
Đặt lại
+
);
}
@@ -220,15 +219,14 @@ export default App = AppTSX;
+Chúng ta đang sử dụng TypeScript ở một vài nơi quan trọng:
-We are using TypeScript in a few key places:
-
- - `interface State` describes the shape of the reducer's state.
- - `type CounterAction` describes the different actions which can be dispatched to the reducer.
- - `const initialState: State` provides a type for the initial state, and also the type which is used by `useReducer` by default.
- - `stateReducer(state: State, action: CounterAction): State` sets the types for the reducer function's arguments and return value.
+ - `interface State` mô tả hình dạng của trạng thái của reducer.
+ - `type CounterAction` mô tả các hành động khác nhau có thể được gửi đến reducer.
+ - `const initialState: State` cung cấp một kiểu cho trạng thái ban đầu và cũng là kiểu được sử dụng bởi `useReducer` theo mặc định.
+ - `stateReducer(state: State, action: CounterAction): State` đặt các kiểu cho các đối số và giá trị trả về của hàm reducer.
-A more explicit alternative to setting the type on `initialState` is to provide a type argument to `useReducer`:
+Một giải pháp thay thế rõ ràng hơn cho việc đặt kiểu trên `initialState` là cung cấp một đối số kiểu cho `useReducer`:
```ts
import { stateReducer, State } from './your-reducer-implementation';
@@ -242,9 +240,9 @@ export default function App() {
### `useContext` {/*typing-usecontext*/}
-The [`useContext` Hook](/reference/react/useContext) is a technique for passing data down the component tree without having to pass props through components. It is used by creating a provider component and often by creating a Hook to consume the value in a child component.
+[`useContext` Hook](/reference/react/useContext) là một kỹ thuật để truyền dữ liệu xuống cây component mà không cần phải truyền các props thông qua các component. Nó được sử dụng bằng cách tạo một component provider và thường bằng cách tạo một Hook để sử dụng giá trị trong một component con.
-The type of the value provided by the context is inferred from the value passed to the `createContext` call:
+Kiểu của giá trị được cung cấp bởi context được suy luận từ giá trị được truyền cho lệnh gọi `createContext`:
@@ -260,9 +258,9 @@ export default function MyApp() {
const [theme, setTheme] = useState('light');
return (
-
-
-
+
+
+
)
}
@@ -270,9 +268,9 @@ function MyComponent() {
const theme = useGetTheme();
return (
-
-
Current theme: {theme}
-
+
+
Chủ đề hiện tại: {theme}
+
)
}
```
@@ -284,25 +282,25 @@ export default App = AppTSX;
-This technique works when you have a default value which makes sense - but there are occasionally cases when you do not, and in those cases `null` can feel reasonable as a default value. However, to allow the type-system to understand your code, you need to explicitly set `ContextShape | null` on the `createContext`.
+Kỹ thuật này hoạt động khi bạn có một giá trị mặc định có ý nghĩa - nhưng đôi khi có những trường hợp bạn không có và trong những trường hợp đó, `null` có thể cảm thấy hợp lý như một giá trị mặc định. Tuy nhiên, để cho phép hệ thống kiểu hiểu mã của bạn, bạn cần đặt rõ ràng `ContextShape | null` trên `createContext`.
-This causes the issue that you need to eliminate the `| null` in the type for context consumers. Our recommendation is to have the Hook do a runtime check for it's existence and throw an error when not present:
+Điều này gây ra vấn đề là bạn cần loại bỏ `| null` trong kiểu cho người tiêu dùng context. Đề xuất của chúng tôi là để Hook thực hiện kiểm tra thời gian chạy về sự tồn tại của nó và đưa ra lỗi khi không có:
```js {5, 16-20}
import { createContext, useContext, useState, useMemo } from 'react';
-// This is a simpler example, but you can imagine a more complex object here
+// Đây là một ví dụ đơn giản hơn, nhưng bạn có thể tưởng tượng một đối tượng phức tạp hơn ở đây
type ComplexObject = {
kind: string
};
-// The context is created with `| null` in the type, to accurately reflect the default value.
+// Context được tạo với `| null` trong kiểu, để phản ánh chính xác giá trị mặc định.
const Context = createContext(null);
-// The `| null` will be removed via the check in the Hook.
+// `| null` sẽ bị xóa thông qua kiểm tra trong Hook.
const useGetComplexObject = () => {
const object = useContext(Context);
- if (!object) { throw new Error("useGetComplexObject must be used within a Provider") }
+ if (!object) { throw new Error("useGetComplexObject phải được sử dụng trong một Provider") }
return object;
}
@@ -310,9 +308,9 @@ export default function MyApp() {
const object = useMemo(() => ({ kind: "complex" }), []);
return (
-
-
-
+
+
+
)
}
@@ -320,27 +318,25 @@ function MyComponent() {
const object = useGetComplexObject();
return (
-
-
Current object: {object.kind}
-
+
+
Đối tượng hiện tại: {object.kind}
+
)
}
```
### `useMemo` {/*typing-usememo*/}
-The [`useMemo`](/reference/react/useMemo) Hooks will create/re-access a memorized value from a function call, re-running the function only when dependencies passed as the 2nd parameter are changed. The result of calling the Hook is inferred from the return value from the function in the first parameter. You can be more explicit by providing a type argument to the Hook.
+[`useMemo`](/reference/react/useMemo) Hooks sẽ tạo/truy cập lại một giá trị được ghi nhớ từ một lệnh gọi hàm, chạy lại hàm chỉ khi các phụ thuộc được truyền làm tham số thứ 2 bị thay đổi. Kết quả của việc gọi Hook được suy luận từ giá trị trả về từ hàm trong tham số đầu tiên. Bạn có thể rõ ràng hơn bằng cách cung cấp một đối số kiểu cho Hook.
```ts
-// The type of visibleTodos is inferred from the return value of filterTodos
+// Kiểu của visibleTodos được suy luận từ giá trị trả về của filterTodos
const visibleTodos = useMemo(() => filterTodos(todos, tab), [todos, tab]);
```
-
### `useCallback` {/*typing-usecallback*/}
-The [`useCallback`](/reference/react/useCallback) provide a stable reference to a function as long as the dependencies passed into the second parameter are the same. Like `useMemo`, the function's type is inferred from the return value of the function in the first parameter, and you can be more explicit by providing a type argument to the Hook.
-
+[`useCallback`](/reference/react/useCallback) cung cấp một tham chiếu ổn định đến một hàm miễn là các phụ thuộc được truyền vào tham số thứ hai giống nhau. Giống như `useMemo`, kiểu của hàm được suy luận từ giá trị trả về của hàm trong tham số đầu tiên và bạn có thể rõ ràng hơn bằng cách cung cấp một đối số kiểu cho Hook.
```ts
const handleClick = useCallback(() => {
@@ -348,36 +344,36 @@ const handleClick = useCallback(() => {
}, [todos]);
```
-When working in TypeScript strict mode `useCallback` requires adding types for the parameters in your callback. This is because the type of the callback is inferred from the return value of the function, and without parameters the type cannot be fully understood.
+Khi làm việc ở chế độ nghiêm ngặt của TypeScript, `useCallback` yêu cầu thêm các kiểu cho các tham số trong callback của bạn. Điều này là do kiểu của callback được suy luận từ giá trị trả về của hàm và nếu không có tham số, kiểu không thể được hiểu đầy đủ.
-Depending on your code-style preferences, you could use the `*EventHandler` functions from the React types to provide the type for the event handler at the same time as defining the callback:
+Tùy thuộc vào tùy chọn kiểu mã của bạn, bạn có thể sử dụng các hàm `*EventHandler` từ các kiểu React để cung cấp kiểu cho trình xử lý sự kiện đồng thời xác định callback:
```ts
import { useState, useCallback } from 'react';
export default function Form() {
- const [value, setValue] = useState("Change me");
+ const [value, setValue] = useState("Thay đổi tôi");
const handleChange = useCallback>((event) => {
- setValue(event.currentTarget.value);
+ setValue(event.currentTarget.value);
}, [setValue])
return (
- <>
-
- Value: {value}
- >
+ <>
+
+ Giá trị: {value}
+ >
);
}
```
-## Useful Types {/*useful-types*/}
+## Các kiểu hữu ích {/*useful-types*/}
-There is quite an expansive set of types which come from the `@types/react` package, it is worth a read when you feel comfortable with how React and TypeScript interact. You can find them [in React's folder in DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts). We will cover a few of the more common types here.
+Có một tập hợp các kiểu khá mở rộng đến từ gói `@types/react`, rất đáng để đọc khi bạn cảm thấy thoải mái với cách React và TypeScript tương tác. Bạn có thể tìm thấy chúng [trong thư mục React trong DefinitelyTyped](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/react/index.d.ts). Chúng ta sẽ đề cập đến một vài kiểu phổ biến hơn ở đây.
-### DOM Events {/*typing-dom-events*/}
+### Sự kiện DOM {/*typing-dom-events*/}
-When working with DOM events in React, the type of the event can often be inferred from the event handler. However, when you want to extract a function to be passed to an event handler, you will need to explicitly set the type of the event.
+Khi làm việc với các sự kiện DOM trong React, kiểu của sự kiện thường có thể được suy luận từ trình xử lý sự kiện. Tuy nhiên, khi bạn muốn trích xuất một hàm để được truyền cho một trình xử lý sự kiện, bạn sẽ cần đặt rõ ràng kiểu của sự kiện.
@@ -385,17 +381,17 @@ When working with DOM events in React, the type of the event can often be inferr
import { useState } from 'react';
export default function Form() {
- const [value, setValue] = useState("Change me");
+ const [value, setValue] = useState("Thay đổi tôi");
function handleChange(event: React.ChangeEvent) {
- setValue(event.currentTarget.value);
+ setValue(event.currentTarget.value);
}
return (
- <>
-
- Value: {value}
- >
+ <>
+
+ Giá trị: {value}
+ >
);
}
```
@@ -407,15 +403,15 @@ export default App = AppTSX;
-There are many types of events provided in the React types - the full list can be found [here](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) which is based on the [most popular events from the DOM](https://developer.mozilla.org/en-US/docs/Web/Events).
+Có nhiều loại sự kiện được cung cấp trong các kiểu React - danh sách đầy đủ có thể được tìm thấy [ở đây](https://github.com/DefinitelyTyped/DefinitelyTyped/blob/b580df54c0819ec9df62b0835a315dd48b8594a9/types/react/index.d.ts#L1247C1-L1373) dựa trên [các sự kiện phổ biến nhất từ DOM](https://developer.mozilla.org/en-US/docs/Web/Events).
-When determining the type you are looking for you can first look at the hover information for the event handler you are using, which will show the type of the event.
+Khi xác định kiểu bạn đang tìm kiếm, trước tiên bạn có thể xem thông tin di chuột cho trình xử lý sự kiện bạn đang sử dụng, thông tin này sẽ hiển thị kiểu của sự kiện.
-If you need to use an event that is not included in this list, you can use the `React.SyntheticEvent` type, which is the base type for all events.
+Nếu bạn cần sử dụng một sự kiện không có trong danh sách này, bạn có thể sử dụng kiểu `React.SyntheticEvent`, đây là kiểu cơ sở cho tất cả các sự kiện.
### Children {/*typing-children*/}
-There are two common paths to describing the children of a component. The first is to use the `React.ReactNode` type, which is a union of all the possible types that can be passed as children in JSX:
+Có hai đường dẫn phổ biến để mô tả các children của một component. Đầu tiên là sử dụng kiểu `React.ReactNode`, đây là một union của tất cả các kiểu có thể được truyền làm children trong JSX:
```ts
interface ModalRendererProps {
@@ -424,7 +420,7 @@ interface ModalRendererProps {
}
```
-This is a very broad definition of children. The second is to use the `React.ReactElement` type, which is only JSX elements and not JavaScript primitives like strings or numbers:
+Đây là một định nghĩa rất rộng về children. Thứ hai là sử dụng kiểu `React.ReactElement`, đây chỉ là các phần tử JSX và không phải là các nguyên thủy JavaScript như chuỗi hoặc số:
```ts
interface ModalRendererProps {
@@ -433,13 +429,13 @@ interface ModalRendererProps {
}
```
-Note, that you cannot use TypeScript to describe that the children are a certain type of JSX elements, so you cannot use the type-system to describe a component which only accepts `` children.
+Lưu ý rằng bạn không thể sử dụng TypeScript để mô tả rằng các children là một loại phần tử JSX nhất định, vì vậy bạn không thể sử dụng hệ thống kiểu để mô tả một component chỉ chấp nhận các children ` `.
-You can see an example of both `React.ReactNode` and `React.ReactElement` with the type-checker in [this TypeScript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA).
+Bạn có thể xem một ví dụ về cả `React.ReactNode` và `React.ReactElement` với trình kiểm tra kiểu trong [TypeScript playground này](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAJQKYEMDG8BmUIjgIilQ3wChSB6CxYmAOmXRgDkIATJOdNJMGAZzgwAFpxAR+8YADswAVwGkZMJFEzpOjDKw4AFHGEEBvUnDhphwADZsi0gFw0mDWjqQBuUgF9yaCNMlENzgAXjgACjADfkctFnYkfQhDAEpQgD44AB42YAA3dKMo5P46C2tbJGkvLIpcgt9-QLi3AEEwMFCItJDMrPTTbIQ3dKywdIB5aU4kKyQQKpha8drhhIGzLLWODbNs3b3s8YAxKBQAcwXpAThMaGWDvbH0gFloGbmrgQfBzYpd1YjQZbEYARkB6zMwO2SHSAAlZlYIBCdtCRkZpHIrFYahQYQD8UYYFA5EhcfjyGYqHAXnJAsIUHlOOUbHYhMIIHJzsI0Qk4P9SLUBuRqXEXEwAKKfRZcNA8PiCfxWACecAAUgBlAAacFm80W-CU11U6h4TgwUv11yShjgJjMLMqDnN9Dilq+nh8pD8AXgCHdMrCkWisVoAet0R6fXqhWKhjKllZVVxMcavpd4Zg7U6Qaj+2hmdG4zeRF10uu-Aeq0LBfLMEe-V+T2L7zLVu+FBWLdLeq+lc7DYFf39deFVOotMCACNOCh1dq219a+30uC8YWoZsRyuEdjkevR8uvoVMdjyTWt4WiSSydXD4NqZP4AymeZE072ZzuUeZQKheQgA).
### Style Props {/*typing-style-props*/}
-When using inline styles in React, you can use `React.CSSProperties` to describe the object passed to the `style` prop. This type is a union of all the possible CSS properties, and is a good way to ensure you are passing valid CSS properties to the `style` prop, and to get auto-complete in your editor.
+Khi sử dụng các kiểu nội tuyến trong React, bạn có thể sử dụng `React.CSSProperties` để mô tả đối tượng được truyền cho prop `style`. Kiểu này là một union của tất cả các thuộc tính CSS có thể và là một cách tốt để đảm bảo bạn đang truyền các thuộc tính CSS hợp lệ cho prop `style` và để nhận được tự động hoàn thành trong trình soạn thảo của bạn.
```ts
interface MyComponentProps {
@@ -447,17 +443,17 @@ interface MyComponentProps {
}
```
-## Further learning {/*further-learning*/}
+## Học thêm {/*further-learning*/}
-This guide has covered the basics of using TypeScript with React, but there is a lot more to learn.
-Individual API pages on the docs may contain more in-depth documentation on how to use them with TypeScript.
+Hướng dẫn này đã đề cập đến những điều cơ bản về sử dụng TypeScript với React, nhưng vẫn còn rất nhiều điều để học.
+Các trang API riêng lẻ trên tài liệu có thể chứa tài liệu chuyên sâu hơn về cách sử dụng chúng với TypeScript.
-We recommend the following resources:
+Chúng tôi khuyên dùng các tài nguyên sau:
- - [The TypeScript handbook](https://www.typescriptlang.org/docs/handbook/) is the official documentation for TypeScript, and covers most key language features.
+ - [Sổ tay TypeScript](https://www.typescriptlang.org/docs/handbook/) là tài liệu chính thức cho TypeScript và bao gồm hầu hết các tính năng ngôn ngữ chính.
- - [The TypeScript release notes](https://devblogs.microsoft.com/typescript/) cover new features in depth.
+ - [Các ghi chú phát hành TypeScript](https://devblogs.microsoft.com/typescript/) bao gồm các tính năng mới một cách chuyên sâu.
- - [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/) is a community-maintained cheatsheet for using TypeScript with React, covering a lot of useful edge cases and providing more breadth than this document.
+ - [React TypeScript Cheatsheet](https://react-typescript-cheatsheet.netlify.app/) là một cheatsheet do cộng đồng duy trì để sử dụng TypeScript với React, bao gồm rất nhiều trường hợp hữu ích và cung cấp độ rộng hơn tài liệu này.
- - [TypeScript Community Discord](https://discord.com/invite/typescript) is a great place to ask questions and get help with TypeScript and React issues.
+ - [TypeScript Community Discord](https://discord.com/invite/typescript) là một nơi tuyệt vời để đặt câu hỏi và nhận trợ giúp về các vấn đề TypeScript và React.
diff --git a/src/content/learn/understanding-your-ui-as-a-tree.md b/src/content/learn/understanding-your-ui-as-a-tree.md
index 2abf7affc..7bf6e7e36 100644
--- a/src/content/learn/understanding-your-ui-as-a-tree.md
+++ b/src/content/learn/understanding-your-ui-as-a-tree.md
@@ -1,41 +1,41 @@
---
-title: Understanding Your UI as a Tree
+title: Hiểu Giao Diện Người Dùng của Bạn như một Cây
---
-Your React app is taking shape with many components being nested within each other. How does React keep track of your app's component structure?
+Ứng dụng React của bạn đang hình thành với nhiều component được lồng vào nhau. Làm thế nào React theo dõi cấu trúc component của ứng dụng của bạn?
-React, and many other UI libraries, model UI as a tree. Thinking of your app as a tree is useful for understanding the relationship between components. This understanding will help you debug future concepts like performance and state management.
+React, và nhiều thư viện UI khác, mô hình hóa UI như một cây. Suy nghĩ về ứng dụng của bạn như một cây rất hữu ích để hiểu mối quan hệ giữa các component. Sự hiểu biết này sẽ giúp bạn gỡ lỗi các khái niệm trong tương lai như hiệu suất và quản lý trạng thái.
-* How React "sees" component structures
-* What a render tree is and what it is useful for
-* What a module dependency tree is and what it is useful for
+* Cách React "nhìn thấy" cấu trúc component
+* Cây render là gì và nó hữu ích cho việc gì
+* Cây phụ thuộc module là gì và nó hữu ích cho việc gì
-## Your UI as a tree {/*your-ui-as-a-tree*/}
+## Giao Diện Người Dùng của Bạn như một Cây {/*your-ui-as-a-tree*/}
-Trees are a relationship model between items and UI is often represented using tree structures. For example, browsers use tree structures to model HTML ([DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction)) and CSS ([CSSOM](https://developer.mozilla.org/docs/Web/API/CSS_Object_Model)). Mobile platforms also use trees to represent their view hierarchy.
+Cây là một mô hình quan hệ giữa các mục và UI thường được biểu diễn bằng cấu trúc cây. Ví dụ: trình duyệt sử dụng cấu trúc cây để mô hình hóa HTML ([DOM](https://developer.mozilla.org/docs/Web/API/Document_Object_Model/Introduction)) và CSS ([CSSOM](https://developer.mozilla.org/docs/Web/API/CSS_Object_Model)). Các nền tảng di động cũng sử dụng cây để biểu diễn hệ thống phân cấp chế độ xem của chúng.
-React creates a UI tree from your components. In this example, the UI tree is then used to render to the DOM.
+React tạo một cây UI từ các component của bạn. Trong ví dụ này, cây UI sau đó được sử dụng để render ra DOM.
-Like browsers and mobile platforms, React also uses tree structures to manage and model the relationship between components in a React app. These trees are useful tools to understand how data flows through a React app and how to optimize rendering and app size.
+Giống như trình duyệt và nền tảng di động, React cũng sử dụng cấu trúc cây để quản lý và mô hình hóa mối quan hệ giữa các component trong một ứng dụng React. Những cây này là công cụ hữu ích để hiểu cách dữ liệu chảy qua một ứng dụng React và cách tối ưu hóa việc render và kích thước ứng dụng.
-## The Render Tree {/*the-render-tree*/}
+## Cây Render {/*the-render-tree*/}
-A major feature of components is the ability to compose components of other components. As we [nest components](/learn/your-first-component#nesting-and-organizing-components), we have the concept of parent and child components, where each parent component may itself be a child of another component.
+Một tính năng chính của component là khả năng kết hợp các component của các component khác. Khi chúng ta [lồng các component](/learn/your-first-component#nesting-and-organizing-components), chúng ta có khái niệm về component cha và component con, trong đó mỗi component cha có thể là một component con của một component khác.
-When we render a React app, we can model this relationship in a tree, known as the render tree.
+Khi chúng ta render một ứng dụng React, chúng ta có thể mô hình hóa mối quan hệ này trong một cây, được gọi là cây render.
-Here is a React app that renders inspirational quotes.
+Đây là một ứng dụng React render các câu trích dẫn truyền cảm hứng.
@@ -120,32 +120,31 @@ export default [
-React creates a *render tree*, a UI tree, composed of the rendered components.
-
+React tạo ra một *cây render*, một cây UI, bao gồm các component được render.
-From the example app, we can construct the above render tree.
+Từ ứng dụng ví dụ, chúng ta có thể xây dựng cây render ở trên.
-The tree is composed of nodes, each of which represents a component. `App`, `FancyText`, `Copyright`, to name a few, are all nodes in our tree.
+Cây bao gồm các node, mỗi node đại diện cho một component. `App`, `FancyText`, `Copyright`, là một vài node trong cây của chúng ta.
-The root node in a React render tree is the [root component](/learn/importing-and-exporting-components#the-root-component-file) of the app. In this case, the root component is `App` and it is the first component React renders. Each arrow in the tree points from a parent component to a child component.
+Node gốc trong một cây render React là [component gốc](/learn/importing-and-exporting-components#the-root-component-file) của ứng dụng. Trong trường hợp này, component gốc là `App` và nó là component đầu tiên React render. Mỗi mũi tên trong cây trỏ từ một component cha đến một component con.
-#### Where are the HTML tags in the render tree? {/*where-are-the-html-elements-in-the-render-tree*/}
+#### Các thẻ HTML ở đâu trong cây render? {/*where-are-the-html-elements-in-the-render-tree*/}
-You'll notice in the above render tree, there is no mention of the HTML tags that each component renders. This is because the render tree is only composed of React [components](learn/your-first-component#components-ui-building-blocks).
+Bạn sẽ nhận thấy trong cây render ở trên, không có đề cập đến các thẻ HTML mà mỗi component render. Điều này là do cây render chỉ bao gồm các [component](learn/your-first-component#components-ui-building-blocks) React.
-React, as a UI framework, is platform agnostic. On react.dev, we showcase examples that render to the web, which uses HTML markup as its UI primitives. But a React app could just as likely render to a mobile or desktop platform, which may use different UI primitives like [UIView](https://developer.apple.com/documentation/uikit/uiview) or [FrameworkElement](https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement?view=windowsdesktop-7.0).
+React, với tư cách là một framework UI, không phụ thuộc vào nền tảng. Trên react.dev, chúng tôi giới thiệu các ví dụ render lên web, sử dụng đánh dấu HTML làm các primitive UI của nó. Nhưng một ứng dụng React cũng có thể render lên một nền tảng di động hoặc máy tính để bàn, có thể sử dụng các primitive UI khác nhau như [UIView](https://developer.apple.com/documentation/uikit/uiview) hoặc [FrameworkElement](https://learn.microsoft.com/en-us/dotnet/api/system.windows.frameworkelement?view=windowsdesktop-7.0).
-These platform UI primitives are not a part of React. React render trees can provide insight to our React app regardless of what platform your app renders to.
+Các primitive UI nền tảng này không phải là một phần của React. Cây render React có thể cung cấp cái nhìn sâu sắc về ứng dụng React của chúng ta bất kể ứng dụng của bạn render lên nền tảng nào.
-A render tree represents a single render pass of a React application. With [conditional rendering](/learn/conditional-rendering), a parent component may render different children depending on the data passed.
+Một cây render đại diện cho một lần render duy nhất của một ứng dụng React. Với [render có điều kiện](/learn/conditional-rendering), một component cha có thể render các component con khác nhau tùy thuộc vào dữ liệu được truyền vào.
-We can update the app to conditionally render either an inspirational quote or color.
+Chúng ta có thể cập nhật ứng dụng để render có điều kiện một câu trích dẫn truyền cảm hứng hoặc màu sắc.
@@ -247,53 +246,53 @@ export default [
-With conditional rendering, across different renders, the render tree may render different components.
+Với render có điều kiện, trên các lần render khác nhau, cây render có thể render các component khác nhau.
-In this example, depending on what `inspiration.type` is, we may render `` or ``. The render tree may be different for each render pass.
+Trong ví dụ này, tùy thuộc vào `inspiration.type` là gì, chúng ta có thể render `` hoặc ``. Cây render có thể khác nhau cho mỗi lần render.
-Although render trees may differ across render passes, these trees are generally helpful for identifying what the *top-level* and *leaf components* are in a React app. Top-level components are the components nearest to the root component and affect the rendering performance of all the components beneath them and often contain the most complexity. Leaf components are near the bottom of the tree and have no child components and are often frequently re-rendered.
+Mặc dù cây render có thể khác nhau giữa các lần render, nhưng những cây này thường hữu ích để xác định *component cấp cao nhất* và *component lá* trong một ứng dụng React. Các component cấp cao nhất là các component gần component gốc nhất và ảnh hưởng đến hiệu suất render của tất cả các component bên dưới chúng và thường chứa độ phức tạp cao nhất. Các component lá nằm gần cuối cây và không có component con và thường được render lại thường xuyên.
-Identifying these categories of components are useful for understanding data flow and performance of your app.
+Xác định các loại component này rất hữu ích để hiểu luồng dữ liệu và hiệu suất của ứng dụng của bạn.
-## The Module Dependency Tree {/*the-module-dependency-tree*/}
+## Cây Phụ Thuộc Module {/*the-module-dependency-tree*/}
-Another relationship in a React app that can be modeled with a tree are an app's module dependencies. As we [break up our components](/learn/importing-and-exporting-components#exporting-and-importing-a-component) and logic into separate files, we create [JS modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) where we may export components, functions, or constants.
+Một mối quan hệ khác trong một ứng dụng React có thể được mô hình hóa bằng một cây là các phụ thuộc module của ứng dụng. Khi chúng ta [chia nhỏ các component](/learn/importing-and-exporting-components#exporting-and-importing-a-component) và logic của chúng ta thành các tệp riêng biệt, chúng ta tạo ra [module JS](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules) nơi chúng ta có thể xuất các component, hàm hoặc hằng số.
-Each node in a module dependency tree is a module and each branch represents an `import` statement in that module.
+Mỗi node trong một cây phụ thuộc module là một module và mỗi nhánh đại diện cho một câu lệnh `import` trong module đó.
-If we take the previous Inspirations app, we can build a module dependency tree, or dependency tree for short.
+Nếu chúng ta lấy ứng dụng Inspirations trước đó, chúng ta có thể xây dựng một cây phụ thuộc module, hoặc cây phụ thuộc cho ngắn gọn.
-The module dependency tree for the Inspirations app.
+Cây phụ thuộc module cho ứng dụng Inspirations.
-The root node of the tree is the root module, also known as the entrypoint file. It often is the module that contains the root component.
+Node gốc của cây là module gốc, còn được gọi là tệp điểm vào. Nó thường là module chứa component gốc.
-Comparing to the render tree of the same app, there are similar structures but some notable differences:
+So sánh với cây render của cùng một ứng dụng, có các cấu trúc tương tự nhưng một số khác biệt đáng chú ý:
-* The nodes that make-up the tree represent modules, not components.
-* Non-component modules, like `inspirations.js`, are also represented in this tree. The render tree only encapsulates components.
-* `Copyright.js` appears under `App.js` but in the render tree, `Copyright`, the component, appears as a child of `InspirationGenerator`. This is because `InspirationGenerator` accepts JSX as [children props](/learn/passing-props-to-a-component#passing-jsx-as-children), so it renders `Copyright` as a child component but does not import the module.
+* Các node tạo nên cây đại diện cho các module, không phải component.
+* Các module không phải component, như `inspirations.js`, cũng được biểu diễn trong cây này. Cây render chỉ bao gồm các component.
+* `Copyright.js` xuất hiện bên dưới `App.js` nhưng trong cây render, `Copyright`, component, xuất hiện như một component con của `InspirationGenerator`. Điều này là do `InspirationGenerator` chấp nhận JSX làm [children props](/learn/passing-props-to-a-component#passing-jsx-as-children), vì vậy nó render `Copyright` như một component con nhưng không import module.
-Dependency trees are useful to determine what modules are necessary to run your React app. When building a React app for production, there is typically a build step that will bundle all the necessary JavaScript to ship to the client. The tool responsible for this is called a [bundler](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview#the_modern_tooling_ecosystem), and bundlers will use the dependency tree to determine what modules should be included.
+Cây phụ thuộc rất hữu ích để xác định những module nào là cần thiết để chạy ứng dụng React của bạn. Khi xây dựng một ứng dụng React cho production, thường có một bước build sẽ gói tất cả JavaScript cần thiết để gửi đến client. Công cụ chịu trách nhiệm cho việc này được gọi là [bundler](https://developer.mozilla.org/en-US/docs/Learn/Tools_and_testing/Understanding_client-side_tools/Overview#the_modern_tooling_ecosystem), và bundler sẽ sử dụng cây phụ thuộc để xác định những module nào nên được bao gồm.
-As your app grows, often the bundle size does too. Large bundle sizes are expensive for a client to download and run. Large bundle sizes can delay the time for your UI to get drawn. Getting a sense of your app's dependency tree may help with debugging these issues.
+Khi ứng dụng của bạn phát triển, kích thước bundle thường cũng tăng lên. Kích thước bundle lớn tốn kém cho client để tải xuống và chạy. Kích thước bundle lớn có thể trì hoãn thời gian để UI của bạn được vẽ. Nhận biết về cây phụ thuộc của ứng dụng của bạn có thể giúp gỡ lỗi các vấn đề này.
[comment]: <> (perhaps we should also deep dive on conditional imports)
-* Trees are a common way to represent the relationship between entities. They are often used to model UI.
-* Render trees represent the nested relationship between React components across a single render.
-* With conditional rendering, the render tree may change across different renders. With different prop values, components may render different children components.
-* Render trees help identify what the top-level and leaf components are. Top-level components affect the rendering performance of all components beneath them and leaf components are often re-rendered frequently. Identifying them is useful for understanding and debugging rendering performance.
-* Dependency trees represent the module dependencies in a React app.
-* Dependency trees are used by build tools to bundle the necessary code to ship an app.
-* Dependency trees are useful for debugging large bundle sizes that slow time to paint and expose opportunities for optimizing what code is bundled.
+* Cây là một cách phổ biến để biểu diễn mối quan hệ giữa các thực thể. Chúng thường được sử dụng để mô hình hóa UI.
+* Cây render biểu diễn mối quan hệ lồng nhau giữa các component React trên một lần render duy nhất.
+* Với render có điều kiện, cây render có thể thay đổi trên các lần render khác nhau. Với các giá trị prop khác nhau, các component có thể render các component con khác nhau.
+* Cây render giúp xác định component cấp cao nhất và component lá là gì. Các component cấp cao nhất ảnh hưởng đến hiệu suất render của tất cả các component bên dưới chúng và các component lá thường được render lại thường xuyên. Xác định chúng rất hữu ích để hiểu và gỡ lỗi hiệu suất render.
+* Cây phụ thuộc biểu diễn các phụ thuộc module trong một ứng dụng React.
+* Cây phụ thuộc được sử dụng bởi các công cụ build để gói mã cần thiết để gửi một ứng dụng.
+* Cây phụ thuộc rất hữu ích để gỡ lỗi kích thước bundle lớn làm chậm thời gian vẽ và phơi bày các cơ hội để tối ưu hóa những gì mã được gói.
diff --git a/src/content/learn/you-might-not-need-an-effect.md b/src/content/learn/you-might-not-need-an-effect.md
index a009793ab..afc596b5d 100644
--- a/src/content/learn/you-might-not-need-an-effect.md
+++ b/src/content/learn/you-might-not-need-an-effect.md
@@ -1,45 +1,45 @@
---
-title: 'You Might Not Need an Effect'
+title: 'Có Thể Bạn Không Cần Effect'
---
-Effects are an escape hatch from the React paradigm. They let you "step outside" of React and synchronize your components with some external system like a non-React widget, network, or the browser DOM. If there is no external system involved (for example, if you want to update a component's state when some props or state change), you shouldn't need an Effect. Removing unnecessary Effects will make your code easier to follow, faster to run, and less error-prone.
+Effect là một lối thoát khỏi mô hình React. Chúng cho phép bạn "bước ra ngoài" React và đồng bộ hóa các component của bạn với một số hệ thống bên ngoài như một widget không phải React, mạng hoặc DOM của trình duyệt. Nếu không có hệ thống bên ngoài nào liên quan (ví dụ: nếu bạn muốn cập nhật state của một component khi một số prop hoặc state thay đổi), bạn không nên cần đến Effect. Loại bỏ các Effect không cần thiết sẽ giúp code của bạn dễ theo dõi hơn, chạy nhanh hơn và ít bị lỗi hơn.
-* Why and how to remove unnecessary Effects from your components
-* How to cache expensive computations without Effects
-* How to reset and adjust component state without Effects
-* How to share logic between event handlers
-* Which logic should be moved to event handlers
-* How to notify parent components about changes
+* Tại sao và làm thế nào để loại bỏ các Effect không cần thiết khỏi component của bạn
+* Cách lưu trữ các phép tính tốn kém mà không cần Effect
+* Cách đặt lại và điều chỉnh state của component mà không cần Effect
+* Cách chia sẻ logic giữa các trình xử lý sự kiện
+* Logic nào nên được chuyển sang trình xử lý sự kiện
+* Cách thông báo cho các component cha về các thay đổi
-## How to remove unnecessary Effects {/*how-to-remove-unnecessary-effects*/}
+## Làm thế nào để loại bỏ các Effect không cần thiết {/*how-to-remove-unnecessary-effects*/}
-There are two common cases in which you don't need Effects:
+Có hai trường hợp phổ biến mà bạn không cần Effect:
-* **You don't need Effects to transform data for rendering.** For example, let's say you want to filter a list before displaying it. You might feel tempted to write an Effect that updates a state variable when the list changes. However, this is inefficient. When you update the state, React will first call your component functions to calculate what should be on the screen. Then React will ["commit"](/learn/render-and-commit) these changes to the DOM, updating the screen. Then React will run your Effects. If your Effect *also* immediately updates the state, this restarts the whole process from scratch! To avoid the unnecessary render passes, transform all the data at the top level of your components. That code will automatically re-run whenever your props or state change.
-* **You don't need Effects to handle user events.** For example, let's say you want to send an `/api/buy` POST request and show a notification when the user buys a product. In the Buy button click event handler, you know exactly what happened. By the time an Effect runs, you don't know *what* the user did (for example, which button was clicked). This is why you'll usually handle user events in the corresponding event handlers.
+* **Bạn không cần Effect để chuyển đổi dữ liệu để hiển thị.** Ví dụ: giả sử bạn muốn lọc một danh sách trước khi hiển thị nó. Bạn có thể cảm thấy muốn viết một Effect để cập nhật một biến state khi danh sách thay đổi. Tuy nhiên, điều này không hiệu quả. Khi bạn cập nhật state, React sẽ gọi các hàm component của bạn để tính toán những gì sẽ hiển thị trên màn hình. Sau đó, React sẽ ["commit"](/learn/render-and-commit) những thay đổi này vào DOM, cập nhật màn hình. Sau đó, React sẽ chạy các Effect của bạn. Nếu Effect của bạn *cũng* ngay lập tức cập nhật state, điều này sẽ khởi động lại toàn bộ quá trình từ đầu! Để tránh các lần render không cần thiết, hãy chuyển đổi tất cả dữ liệu ở cấp cao nhất của component của bạn. Code đó sẽ tự động chạy lại bất cứ khi nào prop hoặc state của bạn thay đổi.
+* **Bạn không cần Effect để xử lý các sự kiện của người dùng.** Ví dụ: giả sử bạn muốn gửi một yêu cầu POST `/api/buy` và hiển thị một thông báo khi người dùng mua một sản phẩm. Trong trình xử lý sự kiện click của nút Mua, bạn biết chính xác những gì đã xảy ra. Vào thời điểm Effect chạy, bạn không biết *người dùng* đã làm gì (ví dụ: nút nào đã được click). Đây là lý do tại sao bạn thường xử lý các sự kiện của người dùng trong các trình xử lý sự kiện tương ứng.
-You *do* need Effects to [synchronize](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events) with external systems. For example, you can write an Effect that keeps a jQuery widget synchronized with the React state. You can also fetch data with Effects: for example, you can synchronize the search results with the current search query. Keep in mind that modern [frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) provide more efficient built-in data fetching mechanisms than writing Effects directly in your components.
+Bạn *cần* Effect để [đồng bộ hóa](/learn/synchronizing-with-effects#what-are-effects-and-how-are-they-different-from-events) với các hệ thống bên ngoài. Ví dụ: bạn có thể viết một Effect để giữ cho một widget jQuery được đồng bộ hóa với state của React. Bạn cũng có thể tìm nạp dữ liệu bằng Effect: ví dụ: bạn có thể đồng bộ hóa kết quả tìm kiếm với truy vấn tìm kiếm hiện tại. Hãy nhớ rằng các [framework](/learn/start-a-new-react-project#production-grade-react-frameworks) hiện đại cung cấp các cơ chế tìm nạp dữ liệu tích hợp hiệu quả hơn so với việc viết Effect trực tiếp trong component của bạn.
-To help you gain the right intuition, let's look at some common concrete examples!
+Để giúp bạn có được trực giác đúng đắn, hãy xem một số ví dụ cụ thể phổ biến!
-### Updating state based on props or state {/*updating-state-based-on-props-or-state*/}
+### Cập nhật state dựa trên prop hoặc state {/*updating-state-based-on-props-or-state*/}
-Suppose you have a component with two state variables: `firstName` and `lastName`. You want to calculate a `fullName` from them by concatenating them. Moreover, you'd like `fullName` to update whenever `firstName` or `lastName` change. Your first instinct might be to add a `fullName` state variable and update it in an Effect:
+Giả sử bạn có một component với hai biến state: `firstName` và `lastName`. Bạn muốn tính toán một `fullName` từ chúng bằng cách nối chúng lại với nhau. Hơn nữa, bạn muốn `fullName` cập nhật bất cứ khi nào `firstName` hoặc `lastName` thay đổi. Bản năng đầu tiên của bạn có thể là thêm một biến state `fullName` và cập nhật nó trong một Effect:
```js {5-9}
function Form() {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
- // 🔴 Avoid: redundant state and unnecessary Effect
+ // 🔴 Tránh: state dư thừa và Effect không cần thiết
const [fullName, setFullName] = useState('');
useEffect(() => {
setFullName(firstName + ' ' + lastName);
@@ -48,29 +48,29 @@ function Form() {
}
```
-This is more complicated than necessary. It is inefficient too: it does an entire render pass with a stale value for `fullName`, then immediately re-renders with the updated value. Remove the state variable and the Effect:
+Điều này phức tạp hơn mức cần thiết. Nó cũng không hiệu quả: nó thực hiện một lần render hoàn chỉnh với một giá trị cũ cho `fullName`, sau đó ngay lập tức render lại với giá trị đã cập nhật. Loại bỏ biến state và Effect:
```js {4-5}
function Form() {
const [firstName, setFirstName] = useState('Taylor');
const [lastName, setLastName] = useState('Swift');
- // ✅ Good: calculated during rendering
+ // ✅ Tốt: được tính toán trong quá trình render
const fullName = firstName + ' ' + lastName;
// ...
}
```
-**When something can be calculated from the existing props or state, [don't put it in state.](/learn/choosing-the-state-structure#avoid-redundant-state) Instead, calculate it during rendering.** This makes your code faster (you avoid the extra "cascading" updates), simpler (you remove some code), and less error-prone (you avoid bugs caused by different state variables getting out of sync with each other). If this approach feels new to you, [Thinking in React](/learn/thinking-in-react#step-3-find-the-minimal-but-complete-representation-of-ui-state) explains what should go into state.
+**Khi một cái gì đó có thể được tính toán từ các prop hoặc state hiện có, [đừng đưa nó vào state.](/learn/choosing-the-state-structure#avoid-redundant-state) Thay vào đó, hãy tính toán nó trong quá trình render.** Điều này làm cho code của bạn nhanh hơn (bạn tránh được các cập nhật "xếp tầng" bổ sung), đơn giản hơn (bạn loại bỏ một số code) và ít bị lỗi hơn (bạn tránh được các lỗi do các biến state khác nhau bị lệch pha với nhau). Nếu cách tiếp cận này có vẻ mới đối với bạn, [Thinking in React](/learn/thinking-in-react#step-3-find-the-minimal-but-complete-representation-of-ui-state) giải thích những gì nên đưa vào state.
-### Caching expensive calculations {/*caching-expensive-calculations*/}
+### Lưu trữ các phép tính tốn kém {/*caching-expensive-calculations*/}
-This component computes `visibleTodos` by taking the `todos` it receives by props and filtering them according to the `filter` prop. You might feel tempted to store the result in state and update it from an Effect:
+Component này tính toán `visibleTodos` bằng cách lấy `todos` mà nó nhận được bằng prop và lọc chúng theo prop `filter`. Bạn có thể cảm thấy muốn lưu trữ kết quả trong state và cập nhật nó từ một Effect:
```js {4-8}
function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState('');
- // 🔴 Avoid: redundant state and unnecessary Effect
+ // 🔴 Tránh: state dư thừa và Effect không cần thiết
const [visibleTodos, setVisibleTodos] = useState([]);
useEffect(() => {
setVisibleTodos(getFilteredTodos(todos, filter));
@@ -80,20 +80,20 @@ function TodoList({ todos, filter }) {
}
```
-Like in the earlier example, this is both unnecessary and inefficient. First, remove the state and the Effect:
+Giống như trong ví dụ trước, điều này vừa không cần thiết vừa không hiệu quả. Đầu tiên, loại bỏ state và Effect:
```js {3-4}
function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState('');
- // ✅ This is fine if getFilteredTodos() is not slow.
+ // ✅ Điều này ổn nếu getFilteredTodos() không chậm.
const visibleTodos = getFilteredTodos(todos, filter);
// ...
}
```
-Usually, this code is fine! But maybe `getFilteredTodos()` is slow or you have a lot of `todos`. In that case you don't want to recalculate `getFilteredTodos()` if some unrelated state variable like `newTodo` has changed.
+Thông thường, đoạn code này vẫn ổn! Nhưng có thể `getFilteredTodos()` chạy chậm hoặc bạn có rất nhiều `todos`. Trong trường hợp đó, bạn không muốn tính toán lại `getFilteredTodos()` nếu một biến state không liên quan như `newTodo` đã thay đổi.
-You can cache (or ["memoize"](https://en.wikipedia.org/wiki/Memoization)) an expensive calculation by wrapping it in a [`useMemo`](/reference/react/useMemo) Hook:
+Bạn có thể lưu vào bộ nhớ cache (hoặc ["ghi nhớ"](https://en.wikipedia.org/wiki/Memoization)) một phép tính tốn kém bằng cách bọc nó trong một Hook [`useMemo`](/reference/react/useMemo):
```js {5-8}
import { useMemo, useState } from 'react';
@@ -101,35 +101,35 @@ import { useMemo, useState } from 'react';
function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState('');
const visibleTodos = useMemo(() => {
- // ✅ Does not re-run unless todos or filter change
+ // ✅ Không chạy lại trừ khi todos hoặc filter thay đổi
return getFilteredTodos(todos, filter);
}, [todos, filter]);
// ...
}
```
-Or, written as a single line:
+Hoặc, viết dưới dạng một dòng duy nhất:
```js {5-6}
import { useMemo, useState } from 'react';
function TodoList({ todos, filter }) {
const [newTodo, setNewTodo] = useState('');
- // ✅ Does not re-run getFilteredTodos() unless todos or filter change
+ // ✅ Không chạy lại getFilteredTodos() trừ khi todos hoặc filter thay đổi
const visibleTodos = useMemo(() => getFilteredTodos(todos, filter), [todos, filter]);
// ...
}
```
-**This tells React that you don't want the inner function to re-run unless either `todos` or `filter` have changed.** React will remember the return value of `getFilteredTodos()` during the initial render. During the next renders, it will check if `todos` or `filter` are different. If they're the same as last time, `useMemo` will return the last result it has stored. But if they are different, React will call the inner function again (and store its result).
+**Điều này cho React biết rằng bạn không muốn hàm bên trong chạy lại trừ khi `todos` hoặc `filter` đã thay đổi.** React sẽ ghi nhớ giá trị trả về của `getFilteredTodos()` trong quá trình render ban đầu. Trong quá trình render tiếp theo, nó sẽ kiểm tra xem `todos` hoặc `filter` có khác nhau hay không. Nếu chúng giống như lần trước, `useMemo` sẽ trả về kết quả cuối cùng mà nó đã lưu trữ. Nhưng nếu chúng khác nhau, React sẽ gọi lại hàm bên trong (và lưu trữ kết quả của nó).
-The function you wrap in [`useMemo`](/reference/react/useMemo) runs during rendering, so this only works for [pure calculations.](/learn/keeping-components-pure)
+Hàm bạn bọc trong [`useMemo`](/reference/react/useMemo) chạy trong quá trình render, vì vậy điều này chỉ hoạt động đối với [các phép tính thuần túy.](/learn/keeping-components-pure)
-#### How to tell if a calculation is expensive? {/*how-to-tell-if-a-calculation-is-expensive*/}
+#### Làm thế nào để biết một phép tính có tốn kém hay không? {/*how-to-tell-if-a-calculation-is-expensive*/}
-In general, unless you're creating or looping over thousands of objects, it's probably not expensive. If you want to get more confidence, you can add a console log to measure the time spent in a piece of code:
+Nói chung, trừ khi bạn đang tạo hoặc lặp qua hàng nghìn đối tượng, có lẽ nó không tốn kém. Nếu bạn muốn tự tin hơn, bạn có thể thêm một bản ghi console để đo thời gian dành cho một đoạn code:
```js {1,3}
console.time('filter array');
@@ -137,33 +137,33 @@ const visibleTodos = getFilteredTodos(todos, filter);
console.timeEnd('filter array');
```
-Perform the interaction you're measuring (for example, typing into the input). You will then see logs like `filter array: 0.15ms` in your console. If the overall logged time adds up to a significant amount (say, `1ms` or more), it might make sense to memoize that calculation. As an experiment, you can then wrap the calculation in `useMemo` to verify whether the total logged time has decreased for that interaction or not:
+Thực hiện tương tác bạn đang đo (ví dụ: nhập vào đầu vào). Sau đó, bạn sẽ thấy các bản ghi như `filter array: 0.15ms` trong bảng điều khiển của mình. Nếu tổng thời gian được ghi lại cộng lại thành một lượng đáng kể (ví dụ: `1ms` trở lên), thì có thể có ý nghĩa khi ghi nhớ phép tính đó. Như một thử nghiệm, sau đó bạn có thể bọc phép tính trong `useMemo` để xác minh xem tổng thời gian được ghi lại có giảm cho tương tác đó hay không:
```js
console.time('filter array');
const visibleTodos = useMemo(() => {
- return getFilteredTodos(todos, filter); // Skipped if todos and filter haven't changed
+ return getFilteredTodos(todos, filter); // Bỏ qua nếu todos và filter không thay đổi
}, [todos, filter]);
console.timeEnd('filter array');
```
-`useMemo` won't make the *first* render faster. It only helps you skip unnecessary work on updates.
+`useMemo` sẽ không làm cho quá trình render *đầu tiên* nhanh hơn. Nó chỉ giúp bạn bỏ qua các công việc không cần thiết khi cập nhật.
-Keep in mind that your machine is probably faster than your users' so it's a good idea to test the performance with an artificial slowdown. For example, Chrome offers a [CPU Throttling](https://developer.chrome.com/blog/new-in-devtools-61/#throttling) option for this.
+Hãy nhớ rằng máy của bạn có thể nhanh hơn máy của người dùng, vì vậy bạn nên kiểm tra hiệu suất với một sự chậm lại nhân tạo. Ví dụ: Chrome cung cấp tùy chọn [Điều chỉnh CPU](https://developer.chrome.com/blog/new-in-devtools-61/#throttling) cho việc này.
-Also note that measuring performance in development will not give you the most accurate results. (For example, when [Strict Mode](/reference/react/StrictMode) is on, you will see each component render twice rather than once.) To get the most accurate timings, build your app for production and test it on a device like your users have.
+Cũng lưu ý rằng việc đo hiệu suất trong quá trình phát triển sẽ không cung cấp cho bạn kết quả chính xác nhất. (Ví dụ: khi [Chế độ nghiêm ngặt](/reference/react/StrictMode) được bật, bạn sẽ thấy mỗi thành phần render hai lần thay vì một lần.) Để có được thời gian chính xác nhất, hãy xây dựng ứng dụng của bạn để sản xuất và kiểm tra nó trên một thiết bị như người dùng của bạn có.
-### Resetting all state when a prop changes {/*resetting-all-state-when-a-prop-changes*/}
+### Đặt lại tất cả trạng thái khi một prop thay đổi {/*resetting-all-state-when-a-prop-changes*/}
-This `ProfilePage` component receives a `userId` prop. The page contains a comment input, and you use a `comment` state variable to hold its value. One day, you notice a problem: when you navigate from one profile to another, the `comment` state does not get reset. As a result, it's easy to accidentally post a comment on a wrong user's profile. To fix the issue, you want to clear out the `comment` state variable whenever the `userId` changes:
+Thành phần `ProfilePage` này nhận một prop `userId`. Trang này chứa một đầu vào nhận xét và bạn sử dụng một biến state `comment` để giữ giá trị của nó. Một ngày nọ, bạn nhận thấy một vấn đề: khi bạn điều hướng từ hồ sơ này sang hồ sơ khác, trạng thái `comment` không được đặt lại. Do đó, rất dễ vô tình đăng nhận xét trên hồ sơ của người dùng sai. Để khắc phục sự cố, bạn muốn xóa biến state `comment` bất cứ khi nào `userId` thay đổi:
```js {4-7}
export default function ProfilePage({ userId }) {
const [comment, setComment] = useState('');
- // 🔴 Avoid: Resetting state on prop change in an Effect
+ // 🔴 Tránh: Đặt lại trạng thái khi thay đổi prop trong một Effect
useEffect(() => {
setComment('');
}, [userId]);
@@ -171,9 +171,9 @@ export default function ProfilePage({ userId }) {
}
```
-This is inefficient because `ProfilePage` and its children will first render with the stale value, and then render again. It is also complicated because you'd need to do this in *every* component that has some state inside `ProfilePage`. For example, if the comment UI is nested, you'd want to clear out nested comment state too.
+Điều này không hiệu quả vì `ProfilePage` và các thành phần con của nó sẽ render trước với giá trị cũ, sau đó render lại. Nó cũng phức tạp vì bạn cần phải làm điều này trong *mọi* thành phần có một số state bên trong `ProfilePage`. Ví dụ: nếu giao diện người dùng nhận xét được lồng nhau, bạn cũng muốn xóa state nhận xét lồng nhau.
-Instead, you can tell React that each user's profile is conceptually a _different_ profile by giving it an explicit key. Split your component in two and pass a `key` attribute from the outer component to the inner one:
+Thay vào đó, bạn có thể cho React biết rằng hồ sơ của mỗi người dùng về mặt khái niệm là một hồ sơ _khác nhau_ bằng cách cung cấp cho nó một khóa rõ ràng. Chia component của bạn thành hai và chuyển một thuộc tính `key` từ component bên ngoài sang component bên trong:
```js {5,11-12}
export default function ProfilePage({ userId }) {
@@ -186,28 +186,28 @@ export default function ProfilePage({ userId }) {
}
function Profile({ userId }) {
- // ✅ This and any other state below will reset on key change automatically
+ // ✅ Trạng thái này và bất kỳ trạng thái nào khác bên dưới sẽ tự động đặt lại khi thay đổi khóa
const [comment, setComment] = useState('');
// ...
}
```
-Normally, React preserves the state when the same component is rendered in the same spot. **By passing `userId` as a `key` to the `Profile` component, you're asking React to treat two `Profile` components with different `userId` as two different components that should not share any state.** Whenever the key (which you've set to `userId`) changes, React will recreate the DOM and [reset the state](/learn/preserving-and-resetting-state#option-2-resetting-state-with-a-key) of the `Profile` component and all of its children. Now the `comment` field will clear out automatically when navigating between profiles.
+Thông thường, React giữ nguyên state khi cùng một component được render ở cùng một vị trí. **Bằng cách chuyển `userId` làm `key` cho component `Profile`, bạn đang yêu cầu React coi hai component `Profile` có `userId` khác nhau là hai component khác nhau không được chia sẻ bất kỳ state nào.** Bất cứ khi nào khóa (mà bạn đã đặt thành `userId`) thay đổi, React sẽ tạo lại DOM và [đặt lại state](/learn/preserving-and-resetting-state#option-2-resetting-state-with-a-key) của component `Profile` và tất cả các component con của nó. Bây giờ trường `comment` sẽ tự động xóa khi điều hướng giữa các hồ sơ.
-Note that in this example, only the outer `ProfilePage` component is exported and visible to other files in the project. Components rendering `ProfilePage` don't need to pass the key to it: they pass `userId` as a regular prop. The fact `ProfilePage` passes it as a `key` to the inner `Profile` component is an implementation detail.
+Lưu ý rằng trong ví dụ này, chỉ component `ProfilePage` bên ngoài được xuất và hiển thị cho các tệp khác trong dự án. Các component render `ProfilePage` không cần phải chuyển khóa cho nó: chúng chuyển `userId` làm một prop thông thường. Việc `ProfilePage` chuyển nó làm `key` cho component `Profile` bên trong là một chi tiết triển khai.
-### Adjusting some state when a prop changes {/*adjusting-some-state-when-a-prop-changes*/}
+### Điều chỉnh một số trạng thái khi một prop thay đổi {/*adjusting-some-state-when-a-prop-changes*/}
-Sometimes, you might want to reset or adjust a part of the state on a prop change, but not all of it.
+Đôi khi, bạn có thể muốn đặt lại hoặc điều chỉnh một phần của state khi một prop thay đổi, nhưng không phải tất cả.
-This `List` component receives a list of `items` as a prop, and maintains the selected item in the `selection` state variable. You want to reset the `selection` to `null` whenever the `items` prop receives a different array:
+Component `List` này nhận một danh sách `items` làm một prop và duy trì mục đã chọn trong biến state `selection`. Bạn muốn đặt lại `selection` thành `null` bất cứ khi nào
```js {5-8}
function List({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selection, setSelection] = useState(null);
- // 🔴 Avoid: Adjusting state on prop change in an Effect
+ // 🔴 Tránh: Điều chỉnh trạng thái khi thay đổi prop trong một Effect
useEffect(() => {
setSelection(null);
}, [items]);
@@ -215,16 +215,16 @@ function List({ items }) {
}
```
-This, too, is not ideal. Every time the `items` change, the `List` and its child components will render with a stale `selection` value at first. Then React will update the DOM and run the Effects. Finally, the `setSelection(null)` call will cause another re-render of the `List` and its child components, restarting this whole process again.
+Điều này cũng không lý tưởng. Mỗi khi `items` thay đổi, `List` và các thành phần con của nó sẽ render với giá trị `selection` cũ trước. Sau đó, React sẽ cập nhật DOM và chạy các Effect. Cuối cùng, lệnh gọi `setSelection(null)` sẽ gây ra một lần render lại `List` và các thành phần con của nó, khởi động lại toàn bộ quá trình này.
-Start by deleting the Effect. Instead, adjust the state directly during rendering:
+Bắt đầu bằng cách xóa Effect. Thay vào đó, hãy điều chỉnh trạng thái trực tiếp trong quá trình render:
```js {5-11}
function List({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selection, setSelection] = useState(null);
- // Better: Adjust the state while rendering
+ // Tốt hơn: Điều chỉnh trạng thái trong khi render
const [prevItems, setPrevItems] = useState(items);
if (items !== prevItems) {
setPrevItems(items);
@@ -234,34 +234,34 @@ function List({ items }) {
}
```
-[Storing information from previous renders](/reference/react/useState#storing-information-from-previous-renders) like this can be hard to understand, but it’s better than updating the same state in an Effect. In the above example, `setSelection` is called directly during a render. React will re-render the `List` *immediately* after it exits with a `return` statement. React has not rendered the `List` children or updated the DOM yet, so this lets the `List` children skip rendering the stale `selection` value.
+[Lưu trữ thông tin từ các lần render trước](/reference/react/useState#storing-information-from-previous-renders) như thế này có thể khó hiểu, nhưng nó tốt hơn là cập nhật cùng một trạng thái trong một Effect. Trong ví dụ trên, `setSelection` được gọi trực tiếp trong quá trình render. React sẽ render lại `List` *ngay lập tức* sau khi nó thoát bằng một câu lệnh `return`. React chưa render các thành phần con `List` hoặc cập nhật DOM, vì vậy điều này cho phép các thành phần con `List` bỏ qua việc render giá trị `selection` cũ.
-When you update a component during rendering, React throws away the returned JSX and immediately retries rendering. To avoid very slow cascading retries, React only lets you update the *same* component's state during a render. If you update another component's state during a render, you'll see an error. A condition like `items !== prevItems` is necessary to avoid loops. You may adjust state like this, but any other side effects (like changing the DOM or setting timeouts) should stay in event handlers or Effects to [keep components pure.](/learn/keeping-components-pure)
+Khi bạn cập nhật một thành phần trong quá trình render, React sẽ loại bỏ JSX được trả về và thử lại render ngay lập tức. Để tránh các lần thử lại xếp tầng rất chậm, React chỉ cho phép bạn cập nhật trạng thái của *cùng* một thành phần trong quá trình render. Nếu bạn cập nhật trạng thái của một thành phần khác trong quá trình render, bạn sẽ thấy lỗi. Một điều kiện như `items !== prevItems` là cần thiết để tránh các vòng lặp. Bạn có thể điều chỉnh trạng thái như thế này, nhưng bất kỳ tác dụng phụ nào khác (như thay đổi DOM hoặc đặt thời gian chờ) nên ở trong các trình xử lý sự kiện hoặc Effect để [giữ cho các thành phần thuần túy.](/learn/keeping-components-pure)
-**Although this pattern is more efficient than an Effect, most components shouldn't need it either.** No matter how you do it, adjusting state based on props or other state makes your data flow more difficult to understand and debug. Always check whether you can [reset all state with a key](#resetting-all-state-when-a-prop-changes) or [calculate everything during rendering](#updating-state-based-on-props-or-state) instead. For example, instead of storing (and resetting) the selected *item*, you can store the selected *item ID:*
+**Mặc dù mẫu này hiệu quả hơn một Effect, nhưng hầu hết các thành phần cũng không cần nó.** Bất kể bạn làm điều đó như thế nào, việc điều chỉnh trạng thái dựa trên các prop hoặc trạng thái khác sẽ làm cho luồng dữ liệu của bạn khó hiểu và gỡ lỗi hơn. Luôn kiểm tra xem bạn có thể [đặt lại tất cả trạng thái bằng một khóa](#resetting-all-state-when-a-prop-changes) hoặc [tính toán mọi thứ trong quá trình render](#updating-state-based-on-props-or-state) hay không. Ví dụ: thay vì lưu trữ (và đặt lại) *mục* đã chọn, bạn có thể lưu trữ *ID mục* đã chọn:
```js {3-5}
function List({ items }) {
const [isReverse, setIsReverse] = useState(false);
const [selectedId, setSelectedId] = useState(null);
- // ✅ Best: Calculate everything during rendering
+ // ✅ Tốt nhất: Tính toán mọi thứ trong quá trình render
const selection = items.find(item => item.id === selectedId) ?? null;
// ...
}
```
-Now there is no need to "adjust" the state at all. If the item with the selected ID is in the list, it remains selected. If it's not, the `selection` calculated during rendering will be `null` because no matching item was found. This behavior is different, but arguably better because most changes to `items` preserve the selection.
+Bây giờ không cần phải "điều chỉnh" trạng thái nữa. Nếu mục có ID đã chọn nằm trong danh sách, nó vẫn được chọn. Nếu không, `selection` được tính toán trong quá trình render sẽ là `null` vì không tìm thấy mục phù hợp. Hành vi này khác, nhưng có thể tốt hơn vì hầu hết các thay đổi đối với `items` đều giữ nguyên lựa chọn.
-### Sharing logic between event handlers {/*sharing-logic-between-event-handlers*/}
+### Chia sẻ logic giữa các trình xử lý sự kiện {/*sharing-logic-between-event-handlers*/}
-Let's say you have a product page with two buttons (Buy and Checkout) that both let you buy that product. You want to show a notification whenever the user puts the product in the cart. Calling `showNotification()` in both buttons' click handlers feels repetitive so you might be tempted to place this logic in an Effect:
+Giả sử bạn có một trang sản phẩm với hai nút (Mua và Thanh toán) cho phép bạn mua sản phẩm đó. Bạn muốn hiển thị thông báo bất cứ khi nào người dùng đặt sản phẩm vào giỏ hàng. Gọi `showNotification()` trong cả hai trình xử lý nhấp của nút có vẻ lặp đi lặp lại, vì vậy bạn có thể muốn đặt logic này trong một Effect:
```js {2-7}
function ProductPage({ product, addToCart }) {
- // 🔴 Avoid: Event-specific logic inside an Effect
+ // 🔴 Tránh: Logic dành riêng cho sự kiện bên trong một Effect
useEffect(() => {
if (product.isInCart) {
- showNotification(`Added ${product.name} to the shopping cart!`);
+ showNotification(`Đã thêm ${product.name} vào giỏ hàng!`);
}
}, [product]);
@@ -277,16 +277,16 @@ function ProductPage({ product, addToCart }) {
}
```
-This Effect is unnecessary. It will also most likely cause bugs. For example, let's say that your app "remembers" the shopping cart between the page reloads. If you add a product to the cart once and refresh the page, the notification will appear again. It will keep appearing every time you refresh that product's page. This is because `product.isInCart` will already be `true` on the page load, so the Effect above will call `showNotification()`.
+Effect này là không cần thiết. Nó cũng rất có thể gây ra lỗi. Ví dụ: giả sử ứng dụng của bạn "ghi nhớ" giỏ hàng giữa các lần tải lại trang. Nếu bạn thêm một sản phẩm vào giỏ hàng một lần và làm mới trang, thông báo sẽ xuất hiện lại. Nó sẽ tiếp tục xuất hiện mỗi khi bạn làm mới trang sản phẩm đó. Điều này là do `product.isInCart` sẽ đã là `true` khi tải trang, vì vậy Effect trên sẽ gọi `showNotification()`.
-**When you're not sure whether some code should be in an Effect or in an event handler, ask yourself *why* this code needs to run. Use Effects only for code that should run *because* the component was displayed to the user.** In this example, the notification should appear because the user *pressed the button*, not because the page was displayed! Delete the Effect and put the shared logic into a function called from both event handlers:
+**Khi bạn không chắc chắn liệu một số mã nên nằm trong một Effect hay trong một trình xử lý sự kiện, hãy tự hỏi *tại sao* mã này cần chạy. Chỉ sử dụng Effect cho mã nên chạy *vì* thành phần đã được hiển thị cho người dùng.** Trong ví dụ này, thông báo sẽ xuất hiện vì người dùng *nhấn nút*, không phải vì trang đã được hiển thị! Xóa Effect và đặt logic được chia sẻ vào một hàm được gọi từ cả hai trình xử lý sự kiện:
```js {2-6,9,13}
function ProductPage({ product, addToCart }) {
- // ✅ Good: Event-specific logic is called from event handlers
+ // ✅ Tốt: Logic dành riêng cho sự kiện được gọi từ các trình xử lý sự kiện
function buyProduct() {
addToCart(product);
- showNotification(`Added ${product.name} to the shopping cart!`);
+ showNotification(`Đã thêm ${product.name} vào giỏ hàng!`);
}
function handleBuyClick() {
@@ -301,23 +301,23 @@ function ProductPage({ product, addToCart }) {
}
```
-This both removes the unnecessary Effect and fixes the bug.
+Điều này vừa loại bỏ Effect không cần thiết vừa sửa lỗi.
-### Sending a POST request {/*sending-a-post-request*/}
+### Gửi một yêu cầu POST {/*sending-a-post-request*/}
-This `Form` component sends two kinds of POST requests. It sends an analytics event when it mounts. When you fill in the form and click the Submit button, it will send a POST request to the `/api/register` endpoint:
+Thành phần `Form` này gửi hai loại yêu cầu POST. Nó gửi một sự kiện phân tích khi nó được gắn kết. Khi bạn điền vào biểu mẫu và nhấp vào nút Gửi, nó sẽ gửi một yêu cầu POST đến điểm cuối `/api/register`:
```js {5-8,10-16}
function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
- // ✅ Good: This logic should run because the component was displayed
+ // ✅ Tốt: Logic này sẽ chạy vì thành phần đã được hiển thị
useEffect(() => {
post('/analytics/event', { eventName: 'visit_form' });
}, []);
- // 🔴 Avoid: Event-specific logic inside an Effect
+ // 🔴 Tránh: Logic dành riêng cho sự kiện bên trong một Effect
const [jsonToSubmit, setJsonToSubmit] = useState(null);
useEffect(() => {
if (jsonToSubmit !== null) {
@@ -333,36 +333,36 @@ function Form() {
}
```
-Let's apply the same criteria as in the example before.
+Hãy áp dụng các tiêu chí tương tự như trong ví dụ trước.
-The analytics POST request should remain in an Effect. This is because the _reason_ to send the analytics event is that the form was displayed. (It would fire twice in development, but [see here](/learn/synchronizing-with-effects#sending-analytics) for how to deal with that.)
+Yêu cầu POST phân tích nên vẫn còn trong một Effect. Điều này là do _lý do_ để gửi sự kiện phân tích là biểu mẫu đã được hiển thị. (Nó sẽ kích hoạt hai lần trong quá trình phát triển, nhưng [xem tại đây](/learn/synchronizing-with-effects#sending-analytics) để biết cách xử lý điều đó.)
-However, the `/api/register` POST request is not caused by the form being _displayed_. You only want to send the request at one specific moment in time: when the user presses the button. It should only ever happen _on that particular interaction_. Delete the second Effect and move that POST request into the event handler:
+Tuy nhiên, yêu cầu POST `/api/register` không phải do biểu mẫu được _hiển thị_. Bạn chỉ muốn gửi yêu cầu vào một thời điểm cụ thể: khi người dùng nhấn nút. Nó sẽ chỉ xảy ra _trong tương tác cụ thể đó_. Xóa Effect thứ hai và di chuyển yêu cầu POST đó vào trình xử lý sự kiện:
```js {12-13}
function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
- // ✅ Good: This logic runs because the component was displayed
+ // ✅ Tốt: Logic này chạy vì thành phần đã được hiển thị
useEffect(() => {
post('/analytics/event', { eventName: 'visit_form' });
}, []);
function handleSubmit(e) {
e.preventDefault();
- // ✅ Good: Event-specific logic is in the event handler
+ // ✅ Tốt: Logic dành riêng cho sự kiện nằm trong trình xử lý sự kiện
post('/api/register', { firstName, lastName });
}
// ...
}
```
-When you choose whether to put some logic into an event handler or an Effect, the main question you need to answer is _what kind of logic_ it is from the user's perspective. If this logic is caused by a particular interaction, keep it in the event handler. If it's caused by the user _seeing_ the component on the screen, keep it in the Effect.
+Khi bạn chọn có nên đặt một số logic vào một trình xử lý sự kiện hay một Effect, câu hỏi chính bạn cần trả lời là _loại logic_ đó là gì từ quan điểm của người dùng. Nếu logic này được gây ra bởi một tương tác cụ thể, hãy giữ nó trong trình xử lý sự kiện. Nếu nó được gây ra bởi người dùng _nhìn thấy_ thành phần trên màn hình, hãy giữ nó trong Effect.
-### Chains of computations {/*chains-of-computations*/}
+### Chuỗi các phép tính {/*chains-of-computations*/}
-Sometimes you might feel tempted to chain Effects that each adjust a piece of state based on other state:
+Đôi khi bạn có thể cảm thấy muốn xâu chuỗi các Effect mà mỗi Effect điều chỉnh một phần của trạng thái dựa trên trạng thái khác:
```js {7-29}
function Game() {
@@ -371,7 +371,7 @@ function Game() {
const [round, setRound] = useState(1);
const [isGameOver, setIsGameOver] = useState(false);
- // 🔴 Avoid: Chains of Effects that adjust the state solely to trigger each other
+ // 🔴 Tránh: Chuỗi các Effect điều chỉnh trạng thái chỉ để kích hoạt lẫn nhau
useEffect(() => {
if (card !== null && card.gold) {
setGoldCardCount(c => c + 1);
@@ -406,13 +406,13 @@ function Game() {
// ...
```
-There are two problems with this code.
+Có hai vấn đề với đoạn code này.
-The first problem is that it is very inefficient: the component (and its children) have to re-render between each `set` call in the chain. In the example above, in the worst case (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) there are three unnecessary re-renders of the tree below.
+Vấn đề đầu tiên là nó rất kém hiệu quả: thành phần (và các thành phần con của nó) phải render lại giữa mỗi lệnh gọi `set` trong chuỗi. Trong ví dụ trên, trong trường hợp xấu nhất (`setCard` → render → `setGoldCardCount` → render → `setRound` → render → `setIsGameOver` → render) có ba lần render lại cây không cần thiết bên dưới.
-The second problem is that even if it weren't slow, as your code evolves, you will run into cases where the "chain" you wrote doesn't fit the new requirements. Imagine you are adding a way to step through the history of the game moves. You'd do it by updating each state variable to a value from the past. However, setting the `card` state to a value from the past would trigger the Effect chain again and change the data you're showing. Such code is often rigid and fragile.
+Vấn đề thứ hai là ngay cả khi nó không chậm, khi code của bạn phát triển, bạn sẽ gặp phải các trường hợp mà "chuỗi" bạn đã viết không phù hợp với các yêu cầu mới. Hãy tưởng tượng bạn đang thêm một cách để xem qua lịch sử các bước di chuyển của trò chơi. Bạn sẽ làm điều đó bằng cách cập nhật từng biến trạng thái thành một giá trị từ quá khứ. Tuy nhiên, việc đặt trạng thái `card` thành một giá trị từ quá khứ sẽ kích hoạt lại chuỗi Effect và thay đổi dữ liệu bạn đang hiển thị. Code như vậy thường cứng nhắc và dễ vỡ.
-In this case, it's better to calculate what you can during rendering, and adjust the state in the event handler:
+Trong trường hợp này, tốt hơn là tính toán những gì bạn có thể trong quá trình render và điều chỉnh trạng thái trong trình xử lý sự kiện:
```js {6-7,14-26}
function Game() {
@@ -420,7 +420,7 @@ function Game() {
const [goldCardCount, setGoldCardCount] = useState(0);
const [round, setRound] = useState(1);
- // ✅ Calculate what you can during rendering
+ // ✅ Tính toán những gì bạn có thể trong quá trình render
const isGameOver = round > 5;
function handlePlaceCard(nextCard) {
@@ -428,7 +428,7 @@ function Game() {
throw Error('Game already ended.');
}
- // ✅ Calculate all the next state in the event handler
+ // ✅ Tính toán tất cả trạng thái tiếp theo trong trình xử lý sự kiện
setCard(nextCard);
if (nextCard.gold) {
if (goldCardCount <= 3) {
@@ -446,21 +446,21 @@ function Game() {
// ...
```
-This is a lot more efficient. Also, if you implement a way to view game history, now you will be able to set each state variable to a move from the past without triggering the Effect chain that adjusts every other value. If you need to reuse logic between several event handlers, you can [extract a function](#sharing-logic-between-event-handlers) and call it from those handlers.
+Điều này hiệu quả hơn rất nhiều. Ngoài ra, nếu bạn triển khai một cách để xem lịch sử trò chơi, giờ đây bạn sẽ có thể đặt từng biến trạng thái thành một bước di chuyển từ quá khứ mà không kích hoạt chuỗi Effect điều chỉnh mọi giá trị khác. Nếu bạn cần sử dụng lại logic giữa một số trình xử lý sự kiện, bạn có thể [trích xuất một hàm](#sharing-logic-between-event-handlers) và gọi nó từ các trình xử lý đó.
-Remember that inside event handlers, [state behaves like a snapshot.](/learn/state-as-a-snapshot) For example, even after you call `setRound(round + 1)`, the `round` variable will reflect the value at the time the user clicked the button. If you need to use the next value for calculations, define it manually like `const nextRound = round + 1`.
+Hãy nhớ rằng bên trong các trình xử lý sự kiện, [trạng thái hoạt động như một ảnh chụp nhanh.](/learn/state-as-a-snapshot) Ví dụ: ngay cả sau khi bạn gọi `setRound(round + 1)`, biến `round` sẽ phản ánh giá trị tại thời điểm người dùng nhấp vào nút. Nếu bạn cần sử dụng giá trị tiếp theo cho các phép tính, hãy xác định nó theo cách thủ công như `const nextRound = round + 1`.
-In some cases, you *can't* calculate the next state directly in the event handler. For example, imagine a form with multiple dropdowns where the options of the next dropdown depend on the selected value of the previous dropdown. Then, a chain of Effects is appropriate because you are synchronizing with network.
+Trong một số trường hợp, bạn *không thể* tính toán trạng thái tiếp theo trực tiếp trong trình xử lý sự kiện. Ví dụ: hãy tưởng tượng một biểu mẫu có nhiều danh sách thả xuống, trong đó các tùy chọn của danh sách thả xuống tiếp theo phụ thuộc vào giá trị đã chọn của danh sách thả xuống trước đó. Sau đó, một chuỗi các Effect là phù hợp vì bạn đang đồng bộ hóa với mạng.
-### Initializing the application {/*initializing-the-application*/}
+### Khởi tạo ứng dụng {/*initializing-the-application*/}
-Some logic should only run once when the app loads.
+Một số logic chỉ nên chạy một lần khi ứng dụng tải.
-You might be tempted to place it in an Effect in the top-level component:
+Bạn có thể muốn đặt nó trong một Effect trong thành phần cấp cao nhất:
```js {2-6}
function App() {
- // 🔴 Avoid: Effects with logic that should only ever run once
+ // 🔴 Tránh: Effect với logic chỉ nên chạy một lần
useEffect(() => {
loadDataFromLocalStorage();
checkAuthToken();
@@ -469,9 +469,9 @@ function App() {
}
```
-However, you'll quickly discover that it [runs twice in development.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) This can cause issues--for example, maybe it invalidates the authentication token because the function wasn't designed to be called twice. In general, your components should be resilient to being remounted. This includes your top-level `App` component.
+Tuy nhiên, bạn sẽ nhanh chóng phát hiện ra rằng nó [chạy hai lần trong quá trình phát triển.](/learn/synchronizing-with-effects#how-to-handle-the-effect-firing-twice-in-development) Điều này có thể gây ra sự cố--ví dụ: có thể nó làm mất hiệu lực mã thông báo xác thực vì hàm không được thiết kế để được gọi hai lần. Nói chung, các thành phần của bạn nên có khả năng phục hồi khi được gắn lại. Điều này bao gồm thành phần `App` cấp cao nhất của bạn.
-Although it may not ever get remounted in practice in production, following the same constraints in all components makes it easier to move and reuse code. If some logic must run *once per app load* rather than *once per component mount*, add a top-level variable to track whether it has already executed:
+Mặc dù nó có thể không bao giờ được gắn lại trong thực tế trong quá trình sản xuất, nhưng việc tuân theo các ràng buộc tương tự trong tất cả các thành phần giúp bạn dễ dàng di chuyển và sử dụng lại code hơn. Nếu một số logic phải chạy *một lần cho mỗi lần tải ứng dụng* thay vì *một lần cho mỗi lần gắn kết thành phần*, hãy thêm một biến cấp cao nhất để theo dõi xem nó đã được thực thi hay chưa:
```js {1,5-6,10}
let didInit = false;
@@ -480,7 +480,7 @@ function App() {
useEffect(() => {
if (!didInit) {
didInit = true;
- // ✅ Only runs once per app load
+ // ✅ Chỉ chạy một lần cho mỗi lần tải ứng dụng
loadDataFromLocalStorage();
checkAuthToken();
}
@@ -489,11 +489,11 @@ function App() {
}
```
-You can also run it during module initialization and before the app renders:
+Bạn cũng có thể chạy nó trong quá trình khởi tạo mô-đun và trước khi ứng dụng render:
```js {1,5}
-if (typeof window !== 'undefined') { // Check if we're running in the browser.
- // ✅ Only runs once per app load
+if (typeof window !== 'undefined') { // Kiểm tra xem chúng ta có đang chạy trong trình duyệt hay không.
+ // ✅ Chỉ chạy một lần cho mỗi lần tải ứng dụng
checkAuthToken();
loadDataFromLocalStorage();
}
@@ -503,11 +503,11 @@ function App() {
}
```
-Code at the top level runs once when your component is imported--even if it doesn't end up being rendered. To avoid slowdown or surprising behavior when importing arbitrary components, don't overuse this pattern. Keep app-wide initialization logic to root component modules like `App.js` or in your application's entry point.
+Code ở cấp cao nhất chạy một lần khi thành phần của bạn được nhập--ngay cả khi nó không được render. Để tránh chậm trễ hoặc hành vi đáng ngạc nhiên khi nhập các thành phần tùy ý, đừng lạm dụng mẫu này. Giữ logic khởi tạo trên toàn ứng dụng cho các mô-đun thành phần gốc như `App.js` hoặc trong điểm nhập của ứng dụng của bạn.
-### Notifying parent components about state changes {/*notifying-parent-components-about-state-changes*/}
+### Thông báo cho các thành phần cha về các thay đổi trạng thái {/*notifying-parent-components-about-state-changes*/}
-Let's say you're writing a `Toggle` component with an internal `isOn` state which can be either `true` or `false`. There are a few different ways to toggle it (by clicking or dragging). You want to notify the parent component whenever the `Toggle` internal state changes, so you expose an `onChange` event and call it from an Effect:
+Giả sử bạn đang viết một thành phần `Toggle` với trạng thái `isOn` bên trong có thể là `true` hoặc `false`. Có một vài cách khác nhau để chuyển đổi nó (bằng cách nhấp hoặc kéo). Bạn muốn thông báo cho thành phần cha bất cứ khi nào trạng thái bên trong `Toggle` thay đổi, vì vậy bạn hiển thị một sự kiện `onChange` và gọi nó từ một Effect:
```js {4-7}
function Toggle({ onChange }) {
@@ -533,17 +533,16 @@ function Toggle({ onChange }) {
// ...
}
```
+Giống như trước đây, điều này không lý tưởng. `Toggle` cập nhật trạng thái của nó trước, và React cập nhật màn hình. Sau đó, React chạy Effect, gọi hàm `onChange` được truyền từ một thành phần cha. Bây giờ thành phần cha sẽ cập nhật trạng thái của chính nó, bắt đầu một lượt render khác. Sẽ tốt hơn nếu thực hiện mọi thứ trong một lượt duy nhất.
-Like earlier, this is not ideal. The `Toggle` updates its state first, and React updates the screen. Then React runs the Effect, which calls the `onChange` function passed from a parent component. Now the parent component will update its own state, starting another render pass. It would be better to do everything in a single pass.
-
-Delete the Effect and instead update the state of *both* components within the same event handler:
+Xóa Effect và thay vào đó cập nhật trạng thái của *cả hai* thành phần trong cùng một trình xử lý sự kiện:
```js {5-7,11,16,18}
function Toggle({ onChange }) {
const [isOn, setIsOn] = useState(false);
function updateToggle(nextIsOn) {
- // ✅ Good: Perform all updates during the event that caused them
+ // ✅ Tốt: Thực hiện tất cả các cập nhật trong sự kiện gây ra chúng
setIsOn(nextIsOn);
onChange(nextIsOn);
}
@@ -564,12 +563,12 @@ function Toggle({ onChange }) {
}
```
-With this approach, both the `Toggle` component and its parent component update their state during the event. React [batches updates](/learn/queueing-a-series-of-state-updates) from different components together, so there will only be one render pass.
+Với cách tiếp cận này, cả thành phần `Toggle` và thành phần cha của nó đều cập nhật trạng thái của chúng trong sự kiện. React [gom các cập nhật](/learn/queueing-a-series-of-state-updates) từ các thành phần khác nhau lại với nhau, vì vậy sẽ chỉ có một lượt render.
-You might also be able to remove the state altogether, and instead receive `isOn` from the parent component:
+Bạn cũng có thể loại bỏ hoàn toàn trạng thái và thay vào đó nhận `isOn` từ thành phần cha:
```js {1,2}
-// ✅ Also good: the component is fully controlled by its parent
+// ✅ Cũng tốt: thành phần được kiểm soát hoàn toàn bởi thành phần cha
function Toggle({ isOn, onChange }) {
function handleClick() {
onChange(!isOn);
@@ -587,11 +586,11 @@ function Toggle({ isOn, onChange }) {
}
```
-["Lifting state up"](/learn/sharing-state-between-components) lets the parent component fully control the `Toggle` by toggling the parent's own state. This means the parent component will have to contain more logic, but there will be less state overall to worry about. Whenever you try to keep two different state variables synchronized, try lifting state up instead!
+["Nâng trạng thái lên"](/learn/sharing-state-between-components) cho phép thành phần cha kiểm soát hoàn toàn `Toggle` bằng cách chuyển đổi trạng thái của chính thành phần cha. Điều này có nghĩa là thành phần cha sẽ phải chứa nhiều logic hơn, nhưng sẽ có ít trạng thái tổng thể hơn để lo lắng. Bất cứ khi nào bạn cố gắng giữ cho hai biến trạng thái khác nhau được đồng bộ hóa, hãy thử nâng trạng thái lên thay thế!
-### Passing data to the parent {/*passing-data-to-the-parent*/}
+### Truyền dữ liệu cho thành phần cha {/*passing-data-to-the-parent*/}
-This `Child` component fetches some data and then passes it to the `Parent` component in an Effect:
+Thành phần `Child` này tìm nạp một số dữ liệu và sau đó truyền nó cho thành phần `Parent` trong một Effect:
```js {9-14}
function Parent() {
@@ -602,7 +601,7 @@ function Parent() {
function Child({ onFetched }) {
const data = useSomeAPI();
- // 🔴 Avoid: Passing data to the parent in an Effect
+ // 🔴 Tránh: Truyền dữ liệu cho thành phần cha trong một Effect
useEffect(() => {
if (data) {
onFetched(data);
@@ -612,13 +611,13 @@ function Child({ onFetched }) {
}
```
-In React, data flows from the parent components to their children. When you see something wrong on the screen, you can trace where the information comes from by going up the component chain until you find which component passes the wrong prop or has the wrong state. When child components update the state of their parent components in Effects, the data flow becomes very difficult to trace. Since both the child and the parent need the same data, let the parent component fetch that data, and *pass it down* to the child instead:
+Trong React, dữ liệu chảy từ các thành phần cha xuống các thành phần con của chúng. Khi bạn thấy điều gì đó không đúng trên màn hình, bạn có thể theo dõi thông tin đến từ đâu bằng cách đi lên chuỗi thành phần cho đến khi bạn tìm thấy thành phần nào truyền sai prop hoặc có trạng thái sai. Khi các thành phần con cập nhật trạng thái của các thành phần cha của chúng trong Effects, luồng dữ liệu trở nên rất khó theo dõi. Vì cả thành phần con và thành phần cha đều cần cùng một dữ liệu, hãy để thành phần cha tìm nạp dữ liệu đó và *truyền nó xuống* cho thành phần con thay thế:
```js {4-5}
function Parent() {
const data = useSomeAPI();
// ...
- // ✅ Good: Passing data down to the child
+ // ✅ Tốt: Truyền dữ liệu xuống cho thành phần con
return ;
}
@@ -627,15 +626,15 @@ function Child({ data }) {
}
```
-This is simpler and keeps the data flow predictable: the data flows down from the parent to the child.
+Điều này đơn giản hơn và giữ cho luồng dữ liệu có thể dự đoán được: dữ liệu chảy xuống từ thành phần cha đến thành phần con.
-### Subscribing to an external store {/*subscribing-to-an-external-store*/}
+### Đăng ký vào một kho bên ngoài {/*subscribing-to-an-external-store*/}
-Sometimes, your components may need to subscribe to some data outside of the React state. This data could be from a third-party library or a built-in browser API. Since this data can change without React's knowledge, you need to manually subscribe your components to it. This is often done with an Effect, for example:
+Đôi khi, các thành phần của bạn có thể cần đăng ký vào một số dữ liệu bên ngoài trạng thái React. Dữ liệu này có thể đến từ một thư viện của bên thứ ba hoặc một API trình duyệt tích hợp. Vì dữ liệu này có thể thay đổi mà React không hề hay biết, bạn cần đăng ký thủ công các thành phần của mình vào nó. Điều này thường được thực hiện với một Effect, ví dụ:
```js {2-17}
function useOnlineStatus() {
- // Not ideal: Manual store subscription in an Effect
+ // Không lý tưởng: Đăng ký kho thủ công trong một Effect
const [isOnline, setIsOnline] = useState(true);
useEffect(() => {
function updateState() {
@@ -660,9 +659,9 @@ function ChatIndicator() {
}
```
-Here, the component subscribes to an external data store (in this case, the browser `navigator.onLine` API). Since this API does not exist on the server (so it can't be used for the initial HTML), initially the state is set to `true`. Whenever the value of that data store changes in the browser, the component updates its state.
+Ở đây, thành phần đăng ký vào một kho dữ liệu bên ngoài (trong trường hợp này, API `navigator.onLine` của trình duyệt). Vì API này không tồn tại trên máy chủ (vì vậy nó không thể được sử dụng cho HTML ban đầu), ban đầu trạng thái được đặt thành `true`. Bất cứ khi nào giá trị của kho dữ liệu đó thay đổi trong trình duyệt, thành phần sẽ cập nhật trạng thái của nó.
-Although it's common to use Effects for this, React has a purpose-built Hook for subscribing to an external store that is preferred instead. Delete the Effect and replace it with a call to [`useSyncExternalStore`](/reference/react/useSyncExternalStore):
+Mặc dù việc sử dụng Effects cho việc này là phổ biến, nhưng React có một Hook được xây dựng có mục đích để đăng ký vào một kho bên ngoài được ưu tiên hơn. Xóa Effect và thay thế nó bằng một lệnh gọi đến [`useSyncExternalStore`](/reference/react/useSyncExternalStore):
```js {11-16}
function subscribe(callback) {
@@ -675,11 +674,11 @@ function subscribe(callback) {
}
function useOnlineStatus() {
- // ✅ Good: Subscribing to an external store with a built-in Hook
+ // ✅ Tốt: Đăng ký vào một kho bên ngoài với một Hook tích hợp
return useSyncExternalStore(
- subscribe, // React won't resubscribe for as long as you pass the same function
- () => navigator.onLine, // How to get the value on the client
- () => true // How to get the value on the server
+ subscribe, // React sẽ không đăng ký lại miễn là bạn truyền cùng một hàm
+ () => navigator.onLine, // Cách lấy giá trị trên máy khách
+ () => true // Cách lấy giá trị trên máy chủ
);
}
@@ -689,11 +688,11 @@ function ChatIndicator() {
}
```
-This approach is less error-prone than manually syncing mutable data to React state with an Effect. Typically, you'll write a custom Hook like `useOnlineStatus()` above so that you don't need to repeat this code in the individual components. [Read more about subscribing to external stores from React components.](/reference/react/useSyncExternalStore)
+Cách tiếp cận này ít gây ra lỗi hơn so với việc đồng bộ hóa thủ công dữ liệu có thể thay đổi với trạng thái React bằng một Effect. Thông thường, bạn sẽ viết một Hook tùy chỉnh như `useOnlineStatus()` ở trên để bạn không cần lặp lại mã này trong các thành phần riêng lẻ. [Đọc thêm về đăng ký vào các kho bên ngoài từ các thành phần React.](/reference/react/useSyncExternalStore)
-### Fetching data {/*fetching-data*/}
+### Tìm nạp dữ liệu {/*fetching-data*/}
-Many apps use Effects to kick off data fetching. It is quite common to write a data fetching Effect like this:
+Nhiều ứng dụng sử dụng Effects để bắt đầu tìm nạp dữ liệu. Việc viết một Effect tìm nạp dữ liệu như thế này là khá phổ biến:
```js {5-10}
function SearchResults({ query }) {
@@ -701,7 +700,7 @@ function SearchResults({ query }) {
const [page, setPage] = useState(1);
useEffect(() => {
- // 🔴 Avoid: Fetching without cleanup logic
+ // 🔴 Tránh: Tìm nạp mà không có logic dọn dẹp
fetchResults(query, page).then(json => {
setResults(json);
});
@@ -714,15 +713,15 @@ function SearchResults({ query }) {
}
```
-You *don't* need to move this fetch to an event handler.
+Bạn *không* cần phải di chuyển quá trình tìm nạp này sang một trình xử lý sự kiện.
-This might seem like a contradiction with the earlier examples where you needed to put the logic into the event handlers! However, consider that it's not *the typing event* that's the main reason to fetch. Search inputs are often prepopulated from the URL, and the user might navigate Back and Forward without touching the input.
+Điều này có vẻ như một mâu thuẫn với các ví dụ trước đó, nơi bạn cần đặt logic vào các trình xử lý sự kiện! Tuy nhiên, hãy xem xét rằng không phải *sự kiện gõ* là lý do chính để tìm nạp. Các đầu vào tìm kiếm thường được điền trước từ URL và người dùng có thể điều hướng Quay lại và Chuyển tiếp mà không cần chạm vào đầu vào.
-It doesn't matter where `page` and `query` come from. While this component is visible, you want to keep `results` [synchronized](/learn/synchronizing-with-effects) with data from the network for the current `page` and `query`. This is why it's an Effect.
+Không quan trọng `page` và `query` đến từ đâu. Trong khi thành phần này hiển thị, bạn muốn giữ cho `results` được [đồng bộ hóa](/learn/synchronizing-with-effects) với dữ liệu từ mạng cho `page` và `query` hiện tại. Đây là lý do tại sao nó là một Effect.
-However, the code above has a bug. Imagine you type `"hello"` fast. Then the `query` will change from `"h"`, to `"he"`, `"hel"`, `"hell"`, and `"hello"`. This will kick off separate fetches, but there is no guarantee about which order the responses will arrive in. For example, the `"hell"` response may arrive *after* the `"hello"` response. Since it will call `setResults()` last, you will be displaying the wrong search results. This is called a ["race condition"](https://en.wikipedia.org/wiki/Race_condition): two different requests "raced" against each other and came in a different order than you expected.
+Tuy nhiên, mã trên có một lỗi. Hãy tưởng tượng bạn gõ `"hello"` nhanh. Sau đó, `query` sẽ thay đổi từ `"h"`, thành `"he"`, `"hel"`, `"hell"`, và `"hello"`. Điều này sẽ bắt đầu các quá trình tìm nạp riêng biệt, nhưng không có gì đảm bảo về thứ tự các phản hồi sẽ đến. Ví dụ: phản hồi `hell"` có thể đến *sau* phản hồi `"hello"`. Vì nó sẽ gọi `setResults()` cuối cùng, bạn sẽ hiển thị sai kết quả tìm kiếm. Điều này được gọi là một ["điều kiện cuộc đua"](https://en.wikipedia.org/wiki/Race_condition): hai yêu cầu khác nhau "chạy đua" với nhau và đến theo một thứ tự khác với những gì bạn mong đợi.
-**To fix the race condition, you need to [add a cleanup function](/learn/synchronizing-with-effects#fetching-data) to ignore stale responses:**
+**Để khắc phục điều kiện cuộc đua, bạn cần [thêm một hàm dọn dẹp](/learn/synchronizing-with-effects#fetching-data) để bỏ qua các phản hồi cũ:**
```js {5,7,9,11-13}
function SearchResults({ query }) {
@@ -747,13 +746,13 @@ function SearchResults({ query }) {
}
```
-This ensures that when your Effect fetches data, all responses except the last requested one will be ignored.
+Điều này đảm bảo rằng khi Effect của bạn tìm nạp dữ liệu, tất cả các phản hồi ngoại trừ phản hồi được yêu cầu cuối cùng sẽ bị bỏ qua.
-Handling race conditions is not the only difficulty with implementing data fetching. You might also want to think about caching responses (so that the user can click Back and see the previous screen instantly), how to fetch data on the server (so that the initial server-rendered HTML contains the fetched content instead of a spinner), and how to avoid network waterfalls (so that a child can fetch data without waiting for every parent).
+Xử lý các điều kiện cuộc đua không phải là khó khăn duy nhất khi triển khai tìm nạp dữ liệu. Bạn cũng có thể muốn nghĩ về việc lưu vào bộ nhớ cache các phản hồi (để người dùng có thể nhấp vào Quay lại và xem màn hình trước đó ngay lập tức), cách tìm nạp dữ liệu trên máy chủ (để HTML được hiển thị ban đầu trên máy chủ chứa nội dung đã tìm nạp thay vì một trình quay), và cách tránh các thác nước mạng (để một thành phần con có thể tìm nạp dữ liệu mà không cần chờ đợi mọi thành phần cha).
-**These issues apply to any UI library, not just React. Solving them is not trivial, which is why modern [frameworks](/learn/start-a-new-react-project#production-grade-react-frameworks) provide more efficient built-in data fetching mechanisms than fetching data in Effects.**
+**Những vấn đề này áp dụng cho bất kỳ thư viện giao diện người dùng nào, không chỉ React. Giải quyết chúng không phải là điều tầm thường, đó là lý do tại sao các [khung](/learn/start-a-new-react-project#production-grade-react-frameworks) hiện đại cung cấp các cơ chế tìm nạp dữ liệu tích hợp hiệu quả hơn so với việc tìm nạp dữ liệu trong Effects.**
-If you don't use a framework (and don't want to build your own) but would like to make data fetching from Effects more ergonomic, consider extracting your fetching logic into a custom Hook like in this example:
+Nếu bạn không sử dụng một khung (và không muốn xây dựng khung của riêng bạn) nhưng muốn làm cho việc tìm nạp dữ liệu từ Effects trở nên tiện dụng hơn, hãy cân nhắc trích xuất logic tìm nạp của bạn vào một Hook tùy chỉnh như trong ví dụ này:
```js {4}
function SearchResults({ query }) {
@@ -786,30 +785,30 @@ function useData(url) {
}
```
-You'll likely also want to add some logic for error handling and to track whether the content is loading. You can build a Hook like this yourself or use one of the many solutions already available in the React ecosystem. **Although this alone won't be as efficient as using a framework's built-in data fetching mechanism, moving the data fetching logic into a custom Hook will make it easier to adopt an efficient data fetching strategy later.**
+Bạn có thể cũng muốn thêm một số logic để xử lý lỗi và theo dõi xem nội dung có đang tải hay không. Bạn có thể xây dựng một Hook như thế này cho chính mình hoặc sử dụng một trong nhiều giải pháp đã có sẵn trong hệ sinh thái React. **Mặc dù điều này một mình sẽ không hiệu quả bằng việc sử dụng cơ chế tìm nạp dữ liệu tích hợp của một khung, nhưng việc di chuyển logic tìm nạp dữ liệu vào một Hook tùy chỉnh sẽ giúp bạn dễ dàng áp dụng một chiến lược tìm nạp dữ liệu hiệu quả hơn sau này.**
-In general, whenever you have to resort to writing Effects, keep an eye out for when you can extract a piece of functionality into a custom Hook with a more declarative and purpose-built API like `useData` above. The fewer raw `useEffect` calls you have in your components, the easier you will find to maintain your application.
+Nói chung, bất cứ khi nào bạn phải dùng đến việc viết Effects, hãy để ý đến khi nào bạn có thể trích xuất một phần chức năng vào một Hook tùy chỉnh với một API khai báo và có mục đích xây dựng hơn như `useData` ở trên. Càng ít lệnh gọi `useEffect` thô mà bạn có trong các thành phần của mình, bạn sẽ càng thấy dễ dàng hơn để bảo trì ứng dụng của mình.
-- If you can calculate something during render, you don't need an Effect.
-- To cache expensive calculations, add `useMemo` instead of `useEffect`.
-- To reset the state of an entire component tree, pass a different `key` to it.
-- To reset a particular bit of state in response to a prop change, set it during rendering.
-- Code that runs because a component was *displayed* should be in Effects, the rest should be in events.
-- If you need to update the state of several components, it's better to do it during a single event.
-- Whenever you try to synchronize state variables in different components, consider lifting state up.
-- You can fetch data with Effects, but you need to implement cleanup to avoid race conditions.
+- Nếu bạn có thể tính toán một cái gì đó trong quá trình render, bạn không cần một Effect.
+- Để lưu vào bộ nhớ cache các phép tính tốn kém, hãy thêm `useMemo` thay vì `useEffect`.
+- Để đặt lại trạng thái của toàn bộ cây thành phần, hãy truyền một `key` khác cho nó.
+- Để đặt lại một bit trạng thái cụ thể để đáp ứng với một thay đổi prop, hãy đặt nó trong quá trình render.
+- Mã chạy vì một thành phần đã được *hiển thị* nên nằm trong Effects, phần còn lại nên nằm trong các sự kiện.
+- Nếu bạn cần cập nhật trạng thái của một số thành phần, tốt hơn là thực hiện nó trong một sự kiện duy nhất.
+- Bất cứ khi nào bạn cố gắng đồng bộ hóa các biến trạng thái trong các thành phần khác nhau, hãy cân nhắc nâng trạng thái lên.
+- Bạn có thể tìm nạp dữ liệu với Effects, nhưng bạn cần triển khai dọn dẹp để tránh các điều kiện cuộc đua.
-#### Transform data without Effects {/*transform-data-without-effects*/}
+#### Chuyển đổi dữ liệu mà không cần Effects {/*transform-data-without-effects*/}
-The `TodoList` below displays a list of todos. When the "Show only active todos" checkbox is ticked, completed todos are not displayed in the list. Regardless of which todos are visible, the footer displays the count of todos that are not yet completed.
+`TodoList` bên dưới hiển thị một danh sách các todo. Khi hộp kiểm "Chỉ hiển thị các todo đang hoạt động" được đánh dấu, các todo đã hoàn thành sẽ không được hiển thị trong danh sách. Bất kể todo nào hiển thị, chân trang hiển thị số lượng todo chưa hoàn thành.
-Simplify this component by removing all the unnecessary state and Effects.
+Đơn giản hóa thành phần này bằng cách loại bỏ tất cả các trạng thái và Effects không cần thiết.
@@ -909,15 +908,15 @@ input { margin-top: 10px; }
-If you can calculate something during rendering, you don't need state or an Effect that updates it.
+Nếu bạn có thể tính toán một cái gì đó trong quá trình render, bạn không cần trạng thái hoặc một Effect để cập nhật nó.
-There are only two essential pieces of state in this example: the list of `todos` and the `showActive` state variable which represents whether the checkbox is ticked. All of the other state variables are [redundant](/learn/choosing-the-state-structure#avoid-redundant-state) and can be calculated during rendering instead. This includes the `footer` which you can move directly into the surrounding JSX.
+Chỉ có hai phần trạng thái thiết yếu trong ví dụ này: danh sách `todos` và biến trạng thái `showActive` đại diện cho việc hộp kiểm có được đánh dấu hay không. Tất cả các biến trạng thái khác đều [dư thừa](/learn/choosing-the-state-structure#avoid-redundant-state) và có thể được tính toán trong quá trình render thay thế. Điều này bao gồm cả `footer` mà bạn có thể di chuyển trực tiếp vào JSX xung quanh.
-Your result should end up looking like this:
+Kết quả của bạn sẽ trông như thế này:
@@ -1002,15 +1001,15 @@ input { margin-top: 10px; }
-#### Cache a calculation without Effects {/*cache-a-calculation-without-effects*/}
+#### Cache một phép tính mà không cần Effects {/*cache-a-calculation-without-effects*/}
-In this example, filtering the todos was extracted into a separate function called `getVisibleTodos()`. This function contains a `console.log()` call inside of it which helps you notice when it's being called. Toggle "Show only active todos" and notice that it causes `getVisibleTodos()` to re-run. This is expected because visible todos change when you toggle which ones to display.
+Trong ví dụ này, việc lọc các todo đã được trích xuất thành một hàm riêng biệt có tên là `getVisibleTodos()`. Hàm này chứa một lệnh gọi `console.log()` bên trong nó giúp bạn nhận thấy khi nào nó đang được gọi. Chuyển đổi "Chỉ hiển thị các todo đang hoạt động" và nhận thấy rằng nó khiến `getVisibleTodos()` chạy lại. Điều này là dự kiến vì các todo hiển thị thay đổi khi bạn chuyển đổi những todo nào sẽ hiển thị.
-Your task is to remove the Effect that recomputes the `visibleTodos` list in the `TodoList` component. However, you need to make sure that `getVisibleTodos()` does *not* re-run (and so does not print any logs) when you type into the input.
+Nhiệm vụ của bạn là loại bỏ Effect tính toán lại danh sách `visibleTodos` trong thành phần `TodoList`. Tuy nhiên, bạn cần đảm bảo rằng `getVisibleTodos()` *không* chạy lại (và do đó không in bất kỳ nhật ký nào) khi bạn nhập vào đầu vào.
-One solution is to add a `useMemo` call to cache the visible todos. There is also another, less obvious solution.
+Một giải pháp là thêm một lệnh gọi `useMemo` để lưu vào bộ nhớ cache các todo hiển thị. Ngoài ra còn có một giải pháp khác, ít rõ ràng hơn.
@@ -1096,7 +1095,7 @@ input { margin-top: 10px; }
-Remove the state variable and the Effect, and instead add a `useMemo` call to cache the result of calling `getVisibleTodos()`:
+Xóa biến trạng thái và Effect, và thay vào đó thêm một lệnh gọi `useMemo` để lưu vào bộ nhớ cache kết quả của việc gọi `getVisibleTodos()`:
@@ -1177,9 +1176,9 @@ input { margin-top: 10px; }
-With this change, `getVisibleTodos()` will be called only if `todos` or `showActive` change. Typing into the input only changes the `text` state variable, so it does not trigger a call to `getVisibleTodos()`.
+Với thay đổi này, `getVisibleTodos()` sẽ chỉ được gọi nếu `todos` hoặc `showActive` thay đổi. Nhập vào đầu vào chỉ thay đổi biến trạng thái `text`, vì vậy nó không kích hoạt một lệnh gọi đến `getVisibleTodos()`.
-There is also another solution which does not need `useMemo`. Since the `text` state variable can't possibly affect the list of todos, you can extract the `NewTodo` form into a separate component, and move the `text` state variable inside of it:
+Ngoài ra còn có một giải pháp khác không cần `useMemo`. Vì biến trạng thái `text` không thể ảnh hưởng đến danh sách các todo, bạn có thể trích xuất biểu mẫu `NewTodo` thành một thành phần riêng biệt và di chuyển biến trạng thái `text` vào bên trong nó:
@@ -1266,15 +1265,16 @@ input { margin-top: 10px; }
-This approach satisfies the requirements too. When you type into the input, only the `text` state variable updates. Since the `text` state variable is in the child `NewTodo` component, the parent `TodoList` component won't get re-rendered. This is why `getVisibleTodos()` doesn't get called when you type. (It would still be called if the `TodoList` re-renders for another reason.)
+Cách tiếp cận này cũng đáp ứng các yêu cầu. Khi bạn nhập vào đầu vào, chỉ biến trạng thái `text` được cập nhật. Vì biến trạng thái `text` nằm trong thành phần con `NewTodo`, thành phần `TodoList` cha sẽ không được render lại. Đây là lý do tại sao `getVisibleTodos()` không được gọi khi bạn nhập. (Nó vẫn sẽ được gọi nếu `TodoList` render lại vì một lý do khác.)
-#### Reset state without Effects {/*reset-state-without-effects*/}
+#### Đặt lại trạng thái mà không cần Effects {/*reset-state-without-effects*/}
+
+Thành phần `EditContact` này nhận một đối tượng liên hệ có dạng như `{ id, name, email }` làm prop `savedContact`. Hãy thử chỉnh sửa các trường nhập tên và email. Khi bạn nhấn Lưu, nút liên hệ phía trên biểu mẫu sẽ cập nhật theo tên đã chỉnh sửa. Khi bạn nhấn Đặt lại, mọi thay đổi đang chờ xử lý trong biểu mẫu sẽ bị loại bỏ. Hãy chơi với giao diện người dùng này để làm quen với nó.
-This `EditContact` component receives a contact object shaped like `{ id, name, email }` as the `savedContact` prop. Try editing the name and email input fields. When you press Save, the contact's button above the form updates to the edited name. When you press Reset, any pending changes in the form are discarded. Play around with this UI to get a feel for it.
+Khi bạn chọn một liên hệ bằng các nút ở trên cùng, biểu mẫu sẽ đặt lại để phản ánh chi tiết của liên hệ đó. Điều này được thực hiện bằng một Effect bên trong `EditContact.js`. Loại bỏ Effect này. Tìm một cách khác để đặt lại biểu mẫu khi `savedContact.id` thay đổi.
-When you select a contact with the buttons at the top, the form resets to reflect that contact's details. This is done with an Effect inside `EditContact.js`. Remove this Effect. Find another way to reset the form when `savedContact.id` changes.
@@ -1432,13 +1432,12 @@ button {
-It would be nice if there was a way to tell React that when `savedContact.id` is different, the `EditContact` form is conceptually a _different contact's form_ and should not preserve state. Do you recall any such way?
-
+Nếu có cách nào để báo cho React biết rằng khi `savedContact.id` khác, thì biểu mẫu `EditContact` về mặt khái niệm là _biểu mẫu của một liên hệ khác_ và không nên giữ lại trạng thái. Bạn có nhớ cách nào như vậy không?
-Split the `EditContact` component in two. Move all the form state into the inner `EditForm` component. Export the outer `EditContact` component, and make it pass `savedContact.id` as the `key` to the inner `EditForm` component. As a result, the inner `EditForm` component resets all of the form state and recreates the DOM whenever you select a different contact.
+Chia thành phần `EditContact` thành hai. Chuyển tất cả trạng thái biểu mẫu vào thành phần `EditForm` bên trong. Xuất thành phần `EditContact` bên ngoài và làm cho nó truyền `savedContact.id` làm `key` cho thành phần `EditForm` bên trong. Do đó, thành phần `EditForm` bên trong sẽ đặt lại tất cả trạng thái biểu mẫu và tạo lại DOM bất cứ khi nào bạn chọn một liên hệ khác.
@@ -1600,17 +1599,17 @@ button {
-#### Submit a form without Effects {/*submit-a-form-without-effects*/}
+#### Gửi biểu mẫu mà không cần Hiệu ứng {/*submit-a-form-without-effects*/}
-This `Form` component lets you send a message to a friend. When you submit the form, the `showForm` state variable is set to `false`. This triggers an Effect calling `sendMessage(message)`, which sends the message (you can see it in the console). After the message is sent, you see a "Thank you" dialog with an "Open chat" button that lets you get back to the form.
+Thành phần `Form` này cho phép bạn gửi tin nhắn cho một người bạn. Khi bạn gửi biểu mẫu, biến trạng thái `showForm` được đặt thành `false`. Điều này kích hoạt một Hiệu ứng gọi `sendMessage(message)`, để gửi tin nhắn (bạn có thể thấy nó trong bảng điều khiển). Sau khi tin nhắn được gửi, bạn sẽ thấy một hộp thoại "Cảm ơn" với nút "Mở trò chuyện" cho phép bạn quay lại biểu mẫu.
-Your app's users are sending way too many messages. To make chatting a little bit more difficult, you've decided to show the "Thank you" dialog *first* rather than the form. Change the `showForm` state variable to initialize to `false` instead of `true`. As soon as you make that change, the console will show that an empty message was sent. Something in this logic is wrong!
+Người dùng ứng dụng của bạn đang gửi quá nhiều tin nhắn. Để làm cho việc trò chuyện trở nên khó khăn hơn một chút, bạn đã quyết định hiển thị hộp thoại "Cảm ơn" *trước* thay vì biểu mẫu. Thay đổi biến trạng thái `showForm` để khởi tạo thành `false` thay vì `true`. Ngay sau khi bạn thực hiện thay đổi đó, bảng điều khiển sẽ hiển thị rằng một tin nhắn trống đã được gửi. Có gì đó không đúng trong logic này!
-What's the root cause of this problem? And how can you fix it?
+Đâu là nguyên nhân gốc rễ của vấn đề này? Và làm thế nào bạn có thể sửa nó?
-Should the message be sent _because_ the user saw the "Thank you" dialog? Or is it the other way around?
+Có phải tin nhắn được gửi _vì_ người dùng đã thấy hộp thoại "Cảm ơn"? Hay là ngược lại?
@@ -1675,7 +1674,7 @@ label, textarea { margin-bottom: 10px; display: block; }
-The `showForm` state variable determines whether to show the form or the "Thank you" dialog. However, you aren't sending the message because the "Thank you" dialog was _displayed_. You want to send the message because the user has _submitted the form._ Delete the misleading Effect and move the `sendMessage` call inside the `handleSubmit` event handler:
+Biến trạng thái `showForm` xác định xem có hiển thị biểu mẫu hay hộp thoại "Cảm ơn". Tuy nhiên, bạn không gửi tin nhắn vì hộp thoại "Cảm ơn" đã được _hiển thị_. Bạn muốn gửi tin nhắn vì người dùng đã _gửi biểu mẫu_. Xóa Hiệu ứng gây hiểu lầm và di chuyển lệnh gọi `sendMessage` vào bên trong trình xử lý sự kiện `handleSubmit`:
@@ -1731,7 +1730,7 @@ label, textarea { margin-bottom: 10px; display: block; }
-Notice how in this version, only _submitting the form_ (which is an event) causes the message to be sent. It works equally well regardless of whether `showForm` is initially set to `true` or `false`. (Set it to `false` and notice no extra console messages.)
+Lưu ý cách trong phiên bản này, chỉ _gửi biểu mẫu_ (đó là một sự kiện) mới khiến tin nhắn được gửi. Nó hoạt động tốt như nhau bất kể `showForm` ban đầu được đặt thành `true` hay `false`. (Đặt nó thành `false` và lưu ý không có thêm tin nhắn bảng điều khiển.)
diff --git a/src/content/reference/react-dom/client/createRoot.md b/src/content/reference/react-dom/client/createRoot.md
index adc6a8d37..6e33c9ad3 100644
--- a/src/content/reference/react-dom/client/createRoot.md
+++ b/src/content/reference/react-dom/client/createRoot.md
@@ -4,7 +4,7 @@ title: createRoot
-`createRoot` lets you create a root to display React components inside a browser DOM node.
+`createRoot` cho phép bạn tạo một gốc để hiển thị các thành phần React bên trong một nút DOM của trình duyệt.
```js
const root = createRoot(domNode, options?)
@@ -16,11 +16,11 @@ const root = createRoot(domNode, options?)
---
-## Reference {/*reference*/}
+## Tham khảo {/*reference*/}
### `createRoot(domNode, options?)` {/*createroot*/}
-Call `createRoot` to create a React root for displaying content inside a browser DOM element.
+Gọi `createRoot` để tạo một gốc React để hiển thị nội dung bên trong một phần tử DOM của trình duyệt.
```js
import { createRoot } from 'react-dom/client';
@@ -29,73 +29,73 @@ const domNode = document.getElementById('root');
const root = createRoot(domNode);
```
-React will create a root for the `domNode`, and take over managing the DOM inside it. After you've created a root, you need to call [`root.render`](#root-render) to display a React component inside of it:
+React sẽ tạo một gốc cho `domNode` và tiếp quản việc quản lý DOM bên trong nó. Sau khi bạn đã tạo một gốc, bạn cần gọi [`root.render`](#root-render) để hiển thị một thành phần React bên trong nó:
```js
root.render( );
```
-An app fully built with React will usually only have one `createRoot` call for its root component. A page that uses "sprinkles" of React for parts of the page may have as many separate roots as needed.
+Một ứng dụng được xây dựng hoàn toàn bằng React thường chỉ có một lệnh gọi `createRoot` cho thành phần gốc của nó. Một trang sử dụng "rắc" React cho các phần của trang có thể có nhiều gốc riêng biệt khi cần thiết.
-[See more examples below.](#usage)
+[Xem thêm các ví dụ bên dưới.](#usage)
-#### Parameters {/*parameters*/}
+#### Tham số {/*parameters*/}
-* `domNode`: A [DOM element.](https://developer.mozilla.org/en-US/docs/Web/API/Element) React will create a root for this DOM element and allow you to call functions on the root, such as `render` to display rendered React content.
+* `domNode`: Một [phần tử DOM.](https://developer.mozilla.org/en-US/docs/Web/API/Element) React sẽ tạo một gốc cho phần tử DOM này và cho phép bạn gọi các hàm trên gốc, chẳng hạn như `render` để hiển thị nội dung React đã được render.
-* **optional** `options`: An object with options for this React root.
+* **tùy chọn** `options`: Một đối tượng với các tùy chọn cho gốc React này.
- * **optional** `onCaughtError`: Callback called when React catches an error in an Error Boundary. Called with the `error` caught by the Error Boundary, and an `errorInfo` object containing the `componentStack`.
- * **optional** `onUncaughtError`: Callback called when an error is thrown and not caught by an Error Boundary. Called with the `error` that was thrown, and an `errorInfo` object containing the `componentStack`.
- * **optional** `onRecoverableError`: Callback called when React automatically recovers from errors. Called with an `error` React throws, and an `errorInfo` object containing the `componentStack`. Some recoverable errors may include the original error cause as `error.cause`.
- * **optional** `identifierPrefix`: A string prefix React uses for IDs generated by [`useId`.](/reference/react/useId) Useful to avoid conflicts when using multiple roots on the same page.
+ * **tùy chọn** `onCaughtError`: Callback được gọi khi React bắt được lỗi trong một Error Boundary. Được gọi với `error` bị bắt bởi Error Boundary và một đối tượng `errorInfo` chứa `componentStack`.
+ * **tùy chọn** `onUncaughtError`: Callback được gọi khi một lỗi được ném ra và không bị bắt bởi một Error Boundary. Được gọi với `error` đã được ném ra và một đối tượng `errorInfo` chứa `componentStack`.
+ * **tùy chọn** `onRecoverableError`: Callback được gọi khi React tự động phục hồi từ các lỗi. Được gọi với một `error` mà React ném ra và một đối tượng `errorInfo` chứa `componentStack`. Một số lỗi có thể phục hồi có thể bao gồm nguyên nhân gây ra lỗi ban đầu là `error.cause`.
+ * **tùy chọn** `identifierPrefix`: Một tiền tố chuỗi mà React sử dụng cho các ID được tạo bởi [`useId`.](/reference/react/useId) Hữu ích để tránh xung đột khi sử dụng nhiều gốc trên cùng một trang.
-#### Returns {/*returns*/}
+#### Trả về {/*returns*/}
-`createRoot` returns an object with two methods: [`render`](#root-render) and [`unmount`.](#root-unmount)
+`createRoot` trả về một đối tượng với hai phương thức: [`render`](#root-render) và [`unmount`.](#root-unmount)
-#### Caveats {/*caveats*/}
-* If your app is server-rendered, using `createRoot()` is not supported. Use [`hydrateRoot()`](/reference/react-dom/client/hydrateRoot) instead.
-* You'll likely have only one `createRoot` call in your app. If you use a framework, it might do this call for you.
-* When you want to render a piece of JSX in a different part of the DOM tree that isn't a child of your component (for example, a modal or a tooltip), use [`createPortal`](/reference/react-dom/createPortal) instead of `createRoot`.
+#### Lưu ý {/*caveats*/}
+* Nếu ứng dụng của bạn được render phía máy chủ, việc sử dụng `createRoot()` không được hỗ trợ. Sử dụng [`hydrateRoot()`](/reference/react-dom/client/hydrateRoot) thay thế.
+* Bạn có thể chỉ có một lệnh gọi `createRoot` trong ứng dụng của mình. Nếu bạn sử dụng một framework, nó có thể thực hiện lệnh gọi này cho bạn.
+* Khi bạn muốn render một đoạn JSX ở một phần khác của cây DOM mà không phải là con của thành phần của bạn (ví dụ: một modal hoặc một tooltip), hãy sử dụng [`createPortal`](/reference/react-dom/createPortal) thay vì `createRoot`.
---
### `root.render(reactNode)` {/*root-render*/}
-Call `root.render` to display a piece of [JSX](/learn/writing-markup-with-jsx) ("React node") into the React root's browser DOM node.
+Gọi `root.render` để hiển thị một đoạn [JSX](/learn/writing-markup-with-jsx) ("React node") vào nút DOM của trình duyệt của gốc React.
```js
root.render( );
```
-React will display ` ` in the `root`, and take over managing the DOM inside it.
+React sẽ hiển thị ` ` trong `root` và tiếp quản việc quản lý DOM bên trong nó.
-[See more examples below.](#usage)
+[Xem thêm các ví dụ bên dưới.](#usage)
-#### Parameters {/*root-render-parameters*/}
+#### Tham số {/*root-render-parameters*/}
-* `reactNode`: A *React node* that you want to display. This will usually be a piece of JSX like ` `, but you can also pass a React element constructed with [`createElement()`](/reference/react/createElement), a string, a number, `null`, or `undefined`.
+* `reactNode`: Một *React node* mà bạn muốn hiển thị. Đây thường sẽ là một đoạn JSX như ` `, nhưng bạn cũng có thể truyền một phần tử React được xây dựng bằng [`createElement()`](/reference/react/createElement), một chuỗi, một số, `null` hoặc `undefined`.
-#### Returns {/*root-render-returns*/}
+#### Trả về {/*root-render-returns*/}
-`root.render` returns `undefined`.
+`root.render` trả về `undefined`.
-#### Caveats {/*root-render-caveats*/}
+#### Lưu ý {/*root-render-caveats*/}
-* The first time you call `root.render`, React will clear all the existing HTML content inside the React root before rendering the React component into it.
+* Lần đầu tiên bạn gọi `root.render`, React sẽ xóa tất cả nội dung HTML hiện có bên trong gốc React trước khi render thành phần React vào đó.
-* If your root's DOM node contains HTML generated by React on the server or during the build, use [`hydrateRoot()`](/reference/react-dom/client/hydrateRoot) instead, which attaches the event handlers to the existing HTML.
+* Nếu nút DOM của gốc của bạn chứa HTML được tạo bởi React trên máy chủ hoặc trong quá trình xây dựng, hãy sử dụng [`hydrateRoot()`](/reference/react-dom/client/hydrateRoot) thay thế, nó sẽ đính kèm các trình xử lý sự kiện vào HTML hiện có.
-* If you call `render` on the same root more than once, React will update the DOM as necessary to reflect the latest JSX you passed. React will decide which parts of the DOM can be reused and which need to be recreated by ["matching it up"](/learn/preserving-and-resetting-state) with the previously rendered tree. Calling `render` on the same root again is similar to calling the [`set` function](/reference/react/useState#setstate) on the root component: React avoids unnecessary DOM updates.
+* Nếu bạn gọi `render` trên cùng một gốc nhiều lần, React sẽ cập nhật DOM khi cần thiết để phản ánh JSX mới nhất mà bạn đã truyền. React sẽ quyết định phần nào của DOM có thể được sử dụng lại và phần nào cần được tạo lại bằng cách ["ghép nó lại"](/learn/preserving-and-resetting-state) với cây đã được render trước đó. Gọi `render` trên cùng một gốc một lần nữa tương tự như gọi hàm [`set`](/reference/react/useState#setstate) trên thành phần gốc: React tránh các cập nhật DOM không cần thiết.
-* Although rendering is synchronous once it starts, `root.render(...)` is not. This means code after `root.render()` may run before any effects (`useLayoutEffect`, `useEffect`) of that specific render are fired. This is usually fine and rarely needs adjustment. In rare cases where effect timing matters, you can wrap `root.render(...)` in [`flushSync`](https://react.dev/reference/react-dom/client/flushSync) to ensure the initial render runs fully synchronously.
+* Mặc dù việc render là đồng bộ sau khi nó bắt đầu, `root.render(...)` thì không. Điều này có nghĩa là mã sau `root.render()` có thể chạy trước bất kỳ hiệu ứng nào (`useLayoutEffect`, `useEffect`) của quá trình render cụ thể đó được kích hoạt. Điều này thường ổn và hiếm khi cần điều chỉnh. Trong những trường hợp hiếm hoi mà thời gian hiệu ứng quan trọng, bạn có thể bọc `root.render(...)` trong [`flushSync`](https://react.dev/reference/react-dom/client/flushSync) để đảm bảo quá trình render ban đầu chạy hoàn toàn đồng bộ.
```js
const root = createRoot(document.getElementById('root'));
root.render( );
- // 🚩 The HTML will not include the rendered yet:
+ // 🚩 HTML sẽ không bao gồm đã được render:
console.log(document.body.innerHTML);
```
@@ -103,41 +103,41 @@ React will display ` ` in the `root`, and take over managing the DOM insid
### `root.unmount()` {/*root-unmount*/}
-Call `root.unmount` to destroy a rendered tree inside a React root.
+Gọi `root.unmount` để phá hủy một cây đã được render bên trong một gốc React.
```js
root.unmount();
```
-An app fully built with React will usually not have any calls to `root.unmount`.
+Một ứng dụng được xây dựng hoàn toàn bằng React thường sẽ không có bất kỳ lệnh gọi nào đến `root.unmount`.
-This is mostly useful if your React root's DOM node (or any of its ancestors) may get removed from the DOM by some other code. For example, imagine a jQuery tab panel that removes inactive tabs from the DOM. If a tab gets removed, everything inside it (including the React roots inside) would get removed from the DOM as well. In that case, you need to tell React to "stop" managing the removed root's content by calling `root.unmount`. Otherwise, the components inside the removed root won't know to clean up and free up global resources like subscriptions.
+Điều này chủ yếu hữu ích nếu nút DOM của gốc React của bạn (hoặc bất kỳ tổ tiên nào của nó) có thể bị xóa khỏi DOM bởi một số mã khác. Ví dụ: hãy tưởng tượng một bảng điều khiển tab jQuery loại bỏ các tab không hoạt động khỏi DOM. Nếu một tab bị xóa, mọi thứ bên trong nó (bao gồm cả các gốc React bên trong) cũng sẽ bị xóa khỏi DOM. Trong trường hợp đó, bạn cần báo cho React "dừng" quản lý nội dung của gốc đã bị xóa bằng cách gọi `root.unmount`. Nếu không, các thành phần bên trong gốc đã bị xóa sẽ không biết cách dọn dẹp và giải phóng các tài nguyên toàn cục như đăng ký.
-Calling `root.unmount` will unmount all the components in the root and "detach" React from the root DOM node, including removing any event handlers or state in the tree.
+Gọi `root.unmount` sẽ unmount tất cả các thành phần trong gốc và "tách" React khỏi nút DOM gốc, bao gồm cả việc xóa bất kỳ trình xử lý sự kiện hoặc trạng thái nào trong cây.
-#### Parameters {/*root-unmount-parameters*/}
+#### Tham số {/*root-unmount-parameters*/}
-`root.unmount` does not accept any parameters.
+`root.unmount` không chấp nhận bất kỳ tham số nào.
-#### Returns {/*root-unmount-returns*/}
+#### Trả về {/*root-unmount-returns*/}
-`root.unmount` returns `undefined`.
+`root.unmount` trả về `undefined`.
-#### Caveats {/*root-unmount-caveats*/}
+#### Lưu ý {/*root-unmount-caveats*/}
-* Calling `root.unmount` will unmount all the components in the tree and "detach" React from the root DOM node.
+* Gọi `root.unmount` sẽ unmount tất cả các thành phần trong cây và "tách" React khỏi nút DOM gốc.
-* Once you call `root.unmount` you cannot call `root.render` again on the same root. Attempting to call `root.render` on an unmounted root will throw a "Cannot update an unmounted root" error. However, you can create a new root for the same DOM node after the previous root for that node has been unmounted.
+* Sau khi bạn gọi `root.unmount`, bạn không thể gọi lại `root.render` trên cùng một gốc. Cố gắng gọi `root.render` trên một gốc đã unmount sẽ ném ra lỗi "Không thể cập nhật một gốc đã unmount". Tuy nhiên, bạn có thể tạo một gốc mới cho cùng một nút DOM sau khi gốc trước đó cho nút đó đã được unmount.
---
-## Usage {/*usage*/}
+## Cách sử dụng {/*usage*/}
-### Rendering an app fully built with React {/*rendering-an-app-fully-built-with-react*/}
+### Render một ứng dụng được xây dựng hoàn toàn bằng React {/*rendering-an-app-fully-built-with-react*/}
-If your app is fully built with React, create a single root for your entire app.
+Nếu ứng dụng của bạn được xây dựng hoàn toàn bằng React, hãy tạo một gốc duy nhất cho toàn bộ ứng dụng của bạn.
```js [[1, 3, "document.getElementById('root')"], [2, 4, " "]]
import { createRoot } from 'react-dom/client';
@@ -146,19 +146,19 @@ const root = createRoot(document.getElementById('root'));
root.render( );
```
-Usually, you only need to run this code once at startup. It will:
+Thông thường, bạn chỉ cần chạy mã này một lần khi khởi động. Nó sẽ:
-1. Find the browser DOM node defined in your HTML.
-2. Display the React component for your app inside.
+1. Tìm nút DOM của trình duyệt được xác định trong HTML của bạn.
+2. Hiển thị thành phần React cho ứng dụng của bạn bên trong.
```html public/index.html
- My app
+ Ứng dụng của tôi
-
+ {/* Đây là nút DOM */}
@@ -179,7 +179,7 @@ import { useState } from 'react';
export default function App() {
return (
<>
- Hello, world!
+ Xin chào, thế giới!
>
);
@@ -189,7 +189,7 @@ function Counter() {
const [count, setCount] = useState(0);
return (
setCount(count + 1)}>
- You clicked me {count} times
+ Bạn đã nhấp vào tôi {count} lần
);
}
@@ -197,46 +197,46 @@ function Counter() {
-**If your app is fully built with React, you shouldn't need to create any more roots, or to call [`root.render`](#root-render) again.**
+**Nếu ứng dụng của bạn được xây dựng hoàn toàn bằng React, bạn không cần tạo thêm bất kỳ gốc nào hoặc gọi lại [`root.render`](#root-render).**
-From this point on, React will manage the DOM of your entire app. To add more components, [nest them inside the `App` component.](/learn/importing-and-exporting-components) When you need to update the UI, each of your components can do this by [using state.](/reference/react/useState) When you need to display extra content like a modal or a tooltip outside the DOM node, [render it with a portal.](/reference/react-dom/createPortal)
+Từ thời điểm này trở đi, React sẽ quản lý DOM của toàn bộ ứng dụng của bạn. Để thêm nhiều thành phần hơn, [lồng chúng bên trong thành phần `App`.](/learn/importing-and-exporting-components) Khi bạn cần cập nhật UI, mỗi thành phần của bạn có thể thực hiện việc này bằng cách [sử dụng state.](/reference/react/useState) Khi bạn cần hiển thị nội dung bổ sung như modal hoặc tooltip bên ngoài nút DOM, [render nó bằng một portal.](/reference/react-dom/createPortal)
-When your HTML is empty, the user sees a blank page until the app's JavaScript code loads and runs:
+Khi HTML của bạn trống, người dùng sẽ thấy một trang trống cho đến khi mã JavaScript của ứng dụng tải và chạy:
```html
```
-This can feel very slow! To solve this, you can generate the initial HTML from your components [on the server or during the build.](/reference/react-dom/server) Then your visitors can read text, see images, and click links before any of the JavaScript code loads. We recommend [using a framework](/learn/start-a-new-react-project#production-grade-react-frameworks) that does this optimization out of the box. Depending on when it runs, this is called *server-side rendering (SSR)* or *static site generation (SSG).*
+Điều này có thể cảm thấy rất chậm! Để giải quyết vấn đề này, bạn có thể tạo HTML ban đầu từ các thành phần của mình [trên máy chủ hoặc trong quá trình xây dựng.](/reference/react-dom/server) Sau đó, khách truy cập của bạn có thể đọc văn bản, xem hình ảnh và nhấp vào liên kết trước khi bất kỳ mã JavaScript nào tải. Chúng tôi khuyên bạn nên [sử dụng một framework](/learn/start-a-new-react-project#production-grade-react-frameworks) thực hiện tối ưu hóa này ngay lập tức. Tùy thuộc vào thời điểm nó chạy, điều này được gọi là *server-side rendering (SSR)* hoặc *static site generation (SSG).*
-**Apps using server rendering or static generation must call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) instead of `createRoot`.** React will then *hydrate* (reuse) the DOM nodes from your HTML instead of destroying and re-creating them.
+**Các ứng dụng sử dụng server rendering hoặc static generation phải gọi [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) thay vì `createRoot`.** React sau đó sẽ *hydrate* (sử dụng lại) các nút DOM từ HTML của bạn thay vì phá hủy và tạo lại chúng.
---
-### Rendering a page partially built with React {/*rendering-a-page-partially-built-with-react*/}
+### Render một trang được xây dựng một phần bằng React {/*rendering-a-page-partially-built-with-react*/}
-If your page [isn't fully built with React](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page), you can call `createRoot` multiple times to create a root for each top-level piece of UI managed by React. You can display different content in each root by calling [`root.render`.](#root-render)
+Nếu trang của bạn [không được xây dựng hoàn toàn bằng React](/learn/add-react-to-an-existing-project#using-react-for-a-part-of-your-existing-page), bạn có thể gọi `createRoot` nhiều lần để tạo một gốc cho mỗi phần UI cấp cao nhất được quản lý bởi React. Bạn có thể hiển thị nội dung khác nhau trong mỗi gốc bằng cách gọi [`root.render`.](#root-render)
-Here, two different React components are rendered into two DOM nodes defined in the `index.html` file:
+Ở đây, hai thành phần React khác nhau được render vào hai nút DOM được xác định trong tệp `index.html`:
```html public/index.html
- My app
+ Ứng dụng của tôi
- This paragraph is not rendered by React (open index.html to verify).
+ Đoạn văn này không được render bởi React (mở index.html để xác minh).
@@ -261,8 +261,8 @@ commentRoot.render( );
export function Navigation() {
return (
- Home
- About
+ Trang chủ
+ Giới thiệu
);
}
@@ -278,9 +278,9 @@ function NavLink({ href, children }) {
export function Comments() {
return (
<>
- Comments
-
-
+ Bình luận
+
+
>
);
}
@@ -299,28 +299,28 @@ nav ul li { display: inline-block; margin-right: 20px; }
-You could also create a new DOM node with [`document.createElement()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement) and add it to the document manually.
+Bạn cũng có thể tạo một nút DOM mới bằng [`document.createElement()`](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement) và thêm nó vào tài liệu theo cách thủ công.
```js
const domNode = document.createElement('div');
const root = createRoot(domNode);
root.render( );
-document.body.appendChild(domNode); // You can add it anywhere in the document
+document.body.appendChild(domNode); // Bạn có thể thêm nó vào bất kỳ đâu trong tài liệu
```
-To remove the React tree from the DOM node and clean up all the resources used by it, call [`root.unmount`.](#root-unmount)
+Để xóa cây React khỏi nút DOM và dọn dẹp tất cả các tài nguyên được sử dụng bởi nó, hãy gọi [`root.unmount`.](#root-unmount)
```js
root.unmount();
```
-This is mostly useful if your React components are inside an app written in a different framework.
+Điều này chủ yếu hữu ích nếu các thành phần React của bạn nằm bên trong một ứng dụng được viết bằng một framework khác.
---
-### Updating a root component {/*updating-a-root-component*/}
+### Cập nhật một thành phần gốc {/*updating-a-root-component*/}
-You can call `render` more than once on the same root. As long as the component tree structure matches up with what was previously rendered, React will [preserve the state.](/learn/preserving-and-resetting-state) Notice how you can type in the input, which means that the updates from repeated `render` calls every second in this example are not destructive:
+Bạn có thể gọi `render` nhiều lần trên cùng một gốc. Miễn là cấu trúc cây thành phần khớp với những gì đã được render trước đó, React sẽ [giữ lại trạng thái.](/learn/preserving-and-resetting-state) Lưu ý cách bạn có thể nhập vào đầu vào, điều đó có nghĩa là các bản cập nhật từ các lệnh gọi `render` lặp đi lặp lại mỗi giây trong ví dụ này không mang tính phá hủy:
@@ -342,8 +342,8 @@ setInterval(() => {
export default function App({counter}) {
return (
<>
- Hello, world! {counter}
-
+ Xin chào, thế giới! {counter}
+
>
);
}
@@ -351,11 +351,11 @@ export default function App({counter}) {
-It is uncommon to call `render` multiple times. Usually, your components will [update state](/reference/react/useState) instead.
+Việc gọi `render` nhiều lần là không phổ biến. Thông thường, các thành phần của bạn sẽ [cập nhật state](/reference/react/useState) thay thế.
-### Error logging in production {/*error-logging-in-production*/}
+### Ghi nhật ký lỗi trong sản xuất {/*error-logging-in-production*/}
-By default, React will log all errors to the console. To implement your own error reporting, you can provide the optional error handler root options `onUncaughtError`, `onCaughtError` and `onRecoverableError`:
+Theo mặc định, React sẽ ghi tất cả các lỗi vào bảng điều khiển. Để triển khai báo cáo lỗi của riêng bạn, bạn có thể cung cấp các tùy chọn gốc trình xử lý lỗi tùy chọn `onUncaughtError`, `onCaughtError` và `onRecoverableError`:
```js [[1, 6, "onCaughtError"], [2, 6, "error", 1], [3, 6, "errorInfo"], [4, 10, "componentStack", 15]]
import { createRoot } from "react-dom/client";
@@ -374,19 +374,19 @@ const root = createRoot(container, {
});
```
-The onCaughtError option is a function called with two arguments:
+Tùy chọn onCaughtError là một hàm được gọi với hai đối số:
-1. The error that was thrown.
-2. An errorInfo object that contains the componentStack of the error.
+1. lỗi đã được ném ra.
+2. Một đối tượng errorInfo chứa componentStack của lỗi.
-Together with `onUncaughtError` and `onRecoverableError`, you can can implement your own error reporting system:
+Cùng với `onUncaughtError` và `onRecoverableError`, bạn có thể triển khai hệ thống báo cáo lỗi của riêng mình:
```js src/reportError.js
function reportError({ type, error, errorInfo }) {
- // The specific implementation is up to you.
- // `console.error()` is only used for demonstration purposes.
+ // Việc triển khai cụ thể là tùy thuộc vào bạn.
+ // `console.error()` chỉ được sử dụng cho mục đích trình diễn.
console.error(type, error, "Component Stack: ");
console.error("Component Stack: ", errorInfo.componentStack);
}
@@ -417,9 +417,9 @@ import {
const container = document.getElementById("root");
const root = createRoot(container, {
- // Keep in mind to remove these options in development to leverage
- // React's default handlers or implement your own overlay for development.
- // The handlers are only specfied unconditionally here for demonstration purposes.
+ // Hãy nhớ xóa các tùy chọn này trong quá trình phát triển để tận dụng
+ // các trình xử lý mặc định của React hoặc triển khai lớp phủ của riêng bạn để phát triển.
+ // Các trình xử lý chỉ được chỉ định vô điều kiện ở đây cho mục đích trình diễn.
onCaughtError: onCaughtErrorProd,
onRecoverableError: onRecoverableErrorProd,
onUncaughtError: onUncaughtErrorProd,
@@ -443,7 +443,7 @@ class ErrorBoundary extends Component {
render() {
if (this.state.hasError) {
- return Something went wrong. ;
+ return Đã xảy ra lỗi. ;
}
return this.props.children;
}
@@ -456,11 +456,11 @@ export default function App() {
return (
<>
settriggerUncaughtError(true)}>
- Trigger uncaught error
+ Kích hoạt lỗi không bị bắt
{triggerUncaughtError && }
setTriggerCaughtError(true)}>
- Trigger caught error
+ Kích hoạt lỗi bị bắt
{triggerCaughtError && (
@@ -474,11 +474,11 @@ export default function App() {
-## Troubleshooting {/*troubleshooting*/}
+## Khắc phục sự cố {/*troubleshooting*/}
-### I've created a root, but nothing is displayed {/*ive-created-a-root-but-nothing-is-displayed*/}
+### Tôi đã tạo một gốc, nhưng không có gì được hiển thị {/*ive-created-a-root-but-nothing-is-displayed*/}
-Make sure you haven't forgotten to actually *render* your app into the root:
+Đảm bảo rằng bạn không quên thực sự *render* ứng dụng của mình vào gốc:
```js {5}
import { createRoot } from 'react-dom/client';
@@ -488,37 +488,37 @@ const root = createRoot(document.getElementById('root'));
root.render( );
```
-Until you do that, nothing is displayed.
+Cho đến khi bạn làm điều đó, không có gì được hiển thị.
---
-### I'm getting an error: "You passed a second argument to root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/}
+### Tôi gặp lỗi: "Bạn đã truyền một đối số thứ hai cho root.render" {/*im-getting-an-error-you-passed-a-second-argument-to-root-render*/}
-A common mistake is to pass the options for `createRoot` to `root.render(...)`:
+Một lỗi phổ biến là truyền các tùy chọn cho `createRoot` cho `root.render(...)`:
-Warning: You passed a second argument to root.render(...) but it only accepts one argument.
+Cảnh báo: Bạn đã truyền một đối số thứ hai cho root.render(...) nhưng nó chỉ chấp nhận một đối số.
-To fix, pass the root options to `createRoot(...)`, not `root.render(...)`:
+Để sửa lỗi, hãy truyền các tùy chọn gốc cho `createRoot(...)`, không phải `root.render(...)`:
```js {2,5}
-// 🚩 Wrong: root.render only takes one argument.
+// 🚩 Sai: root.render chỉ nhận một đối số.
root.render(App, {onUncaughtError});
-// ✅ Correct: pass options to createRoot.
+// ✅ Đúng: truyền các tùy chọn cho createRoot.
const root = createRoot(container, {onUncaughtError});
root.render( );
```
---
-### I'm getting an error: "Target container is not a DOM element" {/*im-getting-an-error-target-container-is-not-a-dom-element*/}
+### Tôi gặp lỗi: "Target container is not a DOM element" {/*im-getting-an-error-target-container-is-not-a-dom-element*/}
-This error means that whatever you're passing to `createRoot` is not a DOM node.
+Lỗi này có nghĩa là bất cứ thứ gì bạn đang truyền cho `createRoot` không phải là một nút DOM.
-If you're not sure what's happening, try logging it:
+Nếu bạn không chắc chắn điều gì đang xảy ra, hãy thử ghi nhật ký nó:
```js {2}
const domNode = document.getElementById('root');
@@ -527,46 +527,46 @@ const root = createRoot(domNode);
root.render( );
```
-For example, if `domNode` is `null`, it means that [`getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) returned `null`. This will happen if there is no node in the document with the given ID at the time of your call. There may be a few reasons for it:
+Ví dụ: nếu `domNode` là `null`, điều đó có nghĩa là [`getElementById`](https://developer.mozilla.org/en-US/docs/Web/API/Document/getElementById) trả về `null`. Điều này sẽ xảy ra nếu không có nút nào trong tài liệu có ID đã cho tại thời điểm bạn gọi. Có thể có một vài lý do cho việc này:
-1. The ID you're looking for might differ from the ID you used in the HTML file. Check for typos!
-2. Your bundle's `
@@ -16,71 +16,71 @@ The [built-in browser `
```
-[See more examples below.](#usage)
+[Xem thêm các ví dụ bên dưới.](#usage)
#### Props {/*props*/}
-`
```
-On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
+Trên client, script bootstrap của bạn sẽ [hydrate toàn bộ `document` bằng một lệnh gọi đến `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
```js [[1, 4, " "]]
import { hydrateRoot } from 'react-dom/client';
@@ -133,15 +133,15 @@ import App from './App.js';
hydrateRoot(document, );
```
-This will attach event listeners to the server-generated HTML and make it interactive.
+Điều này sẽ đính kèm các trình xử lý sự kiện vào HTML được tạo từ server và làm cho nó có tính tương tác.
-#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/}
+#### Đọc các đường dẫn CSS và JS asset từ đầu ra bản dựng {/*reading-css-and-js-asset-paths-from-the-build-output*/}
-The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content.
+Các URL asset cuối cùng (như các tệp JavaScript và CSS) thường được băm sau khi bản dựng. Ví dụ: thay vì `styles.css`, bạn có thể kết thúc với `styles.123456.css`. Băm tên tệp asset tĩnh đảm bảo rằng mọi bản dựng riêng biệt của cùng một asset sẽ có một tên tệp khác nhau. Điều này rất hữu ích vì nó cho phép bạn bật bộ nhớ đệm dài hạn một cách an toàn cho các asset tĩnh: một tệp có một tên nhất định sẽ không bao giờ thay đổi nội dung.
-However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop:
+Tuy nhiên, nếu bạn không biết các URL asset cho đến sau bản dựng, bạn không có cách nào để đưa chúng vào mã nguồn. Ví dụ: mã hóa cứng `"/styles.css"` vào JSX như trước đây sẽ không hoạt động. Để giữ chúng bên ngoài mã nguồn của bạn, component root của bạn có thể đọc tên tệp thực từ một map được truyền dưới dạng một prop:
```js {1,6}
export default function App({ assetMap }) {
@@ -158,10 +158,10 @@ export default function App({ assetMap }) {
}
```
-On the server, render ` ` and pass your `assetMap` with the asset URLs:
+Trên server, kết xuất ` ` và truyền `assetMap` của bạn với các URL asset:
```js {1-5,8,9}
-// You'd need to get this JSON from your build tooling, e.g. read it from the build output.
+// Bạn sẽ cần lấy JSON này từ công cụ bản dựng của bạn, ví dụ: đọc nó từ đầu ra bản dựng.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -178,10 +178,10 @@ app.use('/', (request, response) => {
});
```
-Since your server is now rendering ` `, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this:
+Vì server của bạn hiện đang kết xuất ` `, bạn cần kết xuất nó với `assetMap` trên client để tránh các lỗi hydration. Bạn có thể tuần tự hóa và truyền `assetMap` cho client như thế này:
```js {9-10}
-// You'd need to get this JSON from your build tooling.
+// Bạn sẽ cần lấy JSON này từ công cụ bản dựng của bạn.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -189,7 +189,7 @@ const assetMap = {
app.use('/', (request, response) => {
const { pipe } = renderToPipeableStream( , {
- // Careful: It's safe to stringify() this because this data isn't user-generated.
+ // Cẩn thận: An toàn để stringify() cái này vì dữ liệu này không phải do người dùng tạo.
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['main.js']],
onShellReady() {
@@ -200,7 +200,7 @@ app.use('/', (request, response) => {
});
```
-In the example above, the `bootstrapScriptContent` option adds an extra inline `
```
-On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
+Trên máy khách, tập lệnh bootstrap của bạn sẽ [hydrate toàn bộ `document` bằng một lệnh gọi đến `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
```js [[1, 4, " "]]
import { hydrateRoot } from 'react-dom/client';
@@ -134,22 +134,22 @@ import App from './App.js';
hydrateRoot(document, );
```
-This will attach event listeners to the server-generated HTML and make it interactive.
+Điều này sẽ đính kèm các trình nghe sự kiện vào HTML được tạo từ máy chủ và làm cho nó có tính tương tác.
-#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/}
+#### Đọc đường dẫn CSS và JS asset từ đầu ra bản dựng {/*reading-css-and-js-asset-paths-from-the-build-output*/}
-The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content.
+Các URL asset cuối cùng (như tệp JavaScript và CSS) thường được băm sau khi xây dựng. Ví dụ: thay vì `styles.css`, bạn có thể kết thúc với `styles.123456.css`. Băm tên tệp asset tĩnh đảm bảo rằng mọi bản dựng riêng biệt của cùng một asset sẽ có một tên tệp khác nhau. Điều này rất hữu ích vì nó cho phép bạn bật bộ nhớ cache dài hạn một cách an toàn cho các asset tĩnh: một tệp có tên nhất định sẽ không bao giờ thay đổi nội dung.
-However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop:
+Tuy nhiên, nếu bạn không biết URL asset cho đến sau khi xây dựng, bạn không có cách nào để đưa chúng vào mã nguồn. Ví dụ: mã hóa cứng `"/styles.css"` vào JSX như trước đây sẽ không hoạt động. Để giữ chúng bên ngoài mã nguồn của bạn, thành phần gốc của bạn có thể đọc tên tệp thực từ một bản đồ được truyền dưới dạng một prop:
```js {1,6}
export default function App({ assetMap }) {
return (
- My app
+ Ứng dụng của tôi
...
@@ -158,10 +158,10 @@ export default function App({ assetMap }) {
}
```
-On the server, render ` ` and pass your `assetMap` with the asset URLs:
+Trên máy chủ, hiển thị ` ` và chuyển `assetMap` của bạn với các URL asset:
```js {1-5,8,9}
-// You'd need to get this JSON from your build tooling, e.g. read it from the build output.
+// Bạn cần lấy JSON này từ công cụ xây dựng của bạn, ví dụ: đọc nó từ đầu ra bản dựng.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -177,10 +177,10 @@ async function handler(request) {
}
```
-Since your server is now rendering ` `, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this:
+Vì máy chủ của bạn hiện đang hiển thị ` `, bạn cần hiển thị nó với `assetMap` trên máy khách để tránh lỗi hydration. Bạn có thể tuần tự hóa và chuyển `assetMap` cho máy khách như thế này:
```js {9-10}
-// You'd need to get this JSON from your build tooling.
+// Bạn cần lấy JSON này từ công cụ xây dựng của bạn.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -188,7 +188,7 @@ const assetMap = {
async function handler(request) {
const stream = await renderToReadableStream( , {
- // Careful: It's safe to stringify() this because this data isn't user-generated.
+ // Cẩn thận: An toàn để stringify() cái này vì dữ liệu này không phải do người dùng tạo.
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['/main.js']],
});
@@ -198,7 +198,7 @@ async function handler(request) {
}
```
-In the example above, the `bootstrapScriptContent` option adds an extra inline `
```
-On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
+Trên máy khách, tập lệnh bootstrap của bạn sẽ [hydrate toàn bộ `document` bằng một lệnh gọi đến `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
```js [[1, 4, " "]]
import { hydrateRoot } from 'react-dom/client';
@@ -139,22 +136,22 @@ import App from './App.js';
hydrateRoot(document, );
```
-This will attach event listeners to the static server-generated HTML and make it interactive.
+Điều này sẽ đính kèm trình nghe sự kiện vào HTML tĩnh do máy chủ tạo ra và làm cho nó có tính tương tác.
-#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/}
+#### Đọc đường dẫn tài sản CSS và JS từ đầu ra bản dựng {/*reading-css-and-js-asset-paths-from-the-build-output*/}
-The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content.
+Các URL tài sản cuối cùng (như tệp JavaScript và CSS) thường được băm sau khi xây dựng. Ví dụ: thay vì `styles.css`, bạn có thể kết thúc bằng `styles.123456.css`. Băm tên tệp tài sản tĩnh đảm bảo rằng mọi bản dựng riêng biệt của cùng một tài sản sẽ có một tên tệp khác nhau. Điều này rất hữu ích vì nó cho phép bạn bật bộ nhớ đệm dài hạn một cách an toàn cho các tài sản tĩnh: một tệp có tên nhất định sẽ không bao giờ thay đổi nội dung.
-However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop:
+Tuy nhiên, nếu bạn không biết URL tài sản cho đến sau khi xây dựng, bạn không có cách nào để đưa chúng vào mã nguồn. Ví dụ: mã hóa cứng `"/styles.css"` vào JSX như trước đây sẽ không hoạt động. Để giữ chúng bên ngoài mã nguồn của bạn, thành phần gốc của bạn có thể đọc tên tệp thực từ một bản đồ được truyền dưới dạng một prop:
```js {1,6}
export default function App({ assetMap }) {
return (
- My app
+ Ứng dụng của tôi
...
@@ -163,10 +160,10 @@ export default function App({ assetMap }) {
}
```
-On the server, render ` ` and pass your `assetMap` with the asset URLs:
+Trên máy chủ, kết xuất ` ` và truyền `assetMap` của bạn với các URL tài sản:
```js {1-5,8,9}
-// You'd need to get this JSON from your build tooling, e.g. read it from the build output.
+// Bạn sẽ cần lấy JSON này từ công cụ xây dựng của bạn, ví dụ: đọc nó từ đầu ra bản dựng.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -182,10 +179,10 @@ async function handler(request) {
}
```
-Since your server is now rendering ` `, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this:
+Vì máy chủ của bạn hiện đang kết xuất ` `, bạn cần kết xuất nó với `assetMap` trên máy khách để tránh lỗi hydration. Bạn có thể tuần tự hóa và truyền `assetMap` cho máy khách như thế này:
```js {9-10}
-// You'd need to get this JSON from your build tooling.
+// Bạn sẽ cần lấy JSON này từ công cụ xây dựng của bạn.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -193,7 +190,7 @@ const assetMap = {
async function handler(request) {
const {prelude} = await prerender( , {
- // Careful: It's safe to stringify() this because this data isn't user-generated.
+ // Cẩn thận: An toàn để stringify() dữ liệu này vì dữ liệu này không phải do người dùng tạo.
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['/main.js']],
});
@@ -203,7 +200,7 @@ async function handler(request) {
}
```
-In the example above, the `bootstrapScriptContent` option adds an extra inline `
```
-On the client, your bootstrap script should [hydrate the entire `document` with a call to `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
+Trên client, script bootstrap của bạn sẽ [hydrate toàn bộ `document` bằng một lệnh gọi đến `hydrateRoot`:](/reference/react-dom/client/hydrateRoot#hydrating-an-entire-document)
```js [[1, 4, " "]]
import { hydrateRoot } from 'react-dom/client';
@@ -138,22 +138,22 @@ import App from './App.js';
hydrateRoot(document, );
```
-This will attach event listeners to the static server-generated HTML and make it interactive.
+Điều này sẽ đính kèm các trình xử lý sự kiện vào HTML tĩnh được tạo từ server và làm cho nó có tính tương tác.
-#### Reading CSS and JS asset paths from the build output {/*reading-css-and-js-asset-paths-from-the-build-output*/}
+#### Đọc đường dẫn CSS và JS asset từ đầu ra bản dựng {/*reading-css-and-js-asset-paths-from-the-build-output*/}
-The final asset URLs (like JavaScript and CSS files) are often hashed after the build. For example, instead of `styles.css` you might end up with `styles.123456.css`. Hashing static asset filenames guarantees that every distinct build of the same asset will have a different filename. This is useful because it lets you safely enable long-term caching for static assets: a file with a certain name would never change content.
+Các URL asset cuối cùng (như các tệp JavaScript và CSS) thường được băm sau bản dựng. Ví dụ: thay vì `styles.css`, bạn có thể kết thúc với `styles.123456.css`. Băm tên tệp asset tĩnh đảm bảo rằng mọi bản dựng riêng biệt của cùng một asset sẽ có một tên tệp khác nhau. Điều này rất hữu ích vì nó cho phép bạn bật bộ nhớ cache dài hạn một cách an toàn cho các asset tĩnh: một tệp có tên nhất định sẽ không bao giờ thay đổi nội dung.
-However, if you don't know the asset URLs until after the build, there's no way for you to put them in the source code. For example, hardcoding `"/styles.css"` into JSX like earlier wouldn't work. To keep them out of your source code, your root component can read the real filenames from a map passed as a prop:
+Tuy nhiên, nếu bạn không biết URL asset cho đến sau bản dựng, bạn không có cách nào để đưa chúng vào mã nguồn. Ví dụ: việc mã hóa cứng `"/styles.css"` vào JSX như trước đây sẽ không hoạt động. Để giữ chúng bên ngoài mã nguồn của bạn, component root của bạn có thể đọc tên tệp thực từ một map được truyền dưới dạng một prop:
```js {1,6}
export default function App({ assetMap }) {
return (
- My app
+ Ứng dụng của tôi
...
@@ -162,10 +162,10 @@ export default function App({ assetMap }) {
}
```
-On the server, render ` ` and pass your `assetMap` with the asset URLs:
+Trên server, kết xuất ` ` và truyền `assetMap` của bạn với các URL asset:
```js {1-5,8,9}
-// You'd need to get this JSON from your build tooling, e.g. read it from the build output.
+// Bạn cần lấy JSON này từ công cụ bản dựng của bạn, ví dụ: đọc nó từ đầu ra bản dựng.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -181,10 +181,10 @@ app.use('/', async (request, response) => {
});
```
-Since your server is now rendering ` `, you need to render it with `assetMap` on the client too to avoid hydration errors. You can serialize and pass `assetMap` to the client like this:
+Vì server của bạn hiện đang kết xuất ` `, bạn cần kết xuất nó với `assetMap` trên client để tránh các lỗi hydration. Bạn có thể serialize và truyền `assetMap` cho client như sau:
```js {9-10}
-// You'd need to get this JSON from your build tooling.
+// Bạn cần lấy JSON này từ công cụ bản dựng của bạn.
const assetMap = {
'styles.css': '/styles.123456.css',
'main.js': '/main.123456.js'
@@ -192,7 +192,7 @@ const assetMap = {
app.use('/', async (request, response) => {
const { prelude } = await prerenderToNodeStream( , {
- // Careful: It's safe to stringify() this because this data isn't user-generated.
+ // Cẩn thận: An toàn để stringify() cái này vì dữ liệu này không phải do người dùng tạo.
bootstrapScriptContent: `window.assetMap = ${JSON.stringify(assetMap)};`,
bootstrapScripts: [assetMap['/main.js']],
});
@@ -202,7 +202,7 @@ app.use('/', async (request, response) => {
});
```
-In the example above, the `bootstrapScriptContent` option adds an extra inline `