Skip to content

feat: translate building your own hooks page #195

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Sep 15, 2021
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
67 changes: 34 additions & 33 deletions content/docs/hooks-custom.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@ next: hooks-reference.html
prev: hooks-rules.html
---

*Hooks* are a new addition in React 16.8. They let you use state and other React features without writing a class.
*Hooks* là một tính năng mới từ React 16.8. Nó cho phép sử dụng state và các tính năng khác của React mà không cần viết dưới dạng class.

Building your own Hooks lets you extract component logic into reusable functions.
Xây dựng Hook của riêng bạn cho phép bạn tách logic của component thành một hàm có thể sử dụng lại.

When we were learning about [using the Effect Hook](/docs/hooks-effect.html#example-using-hooks-1), we saw this component from a chat application that displays a message indicating whether a friend is online or offline:
Khi chúng ta học về [cách sử dụng Effect Hook](/docs/hooks-effect.html#example-using-hooks-1), chúng ta có thể thấy rằng component này sử dụng trong một ứng dụng nhắn tin, dùng để thể hiển tin nhắn khi một liên hệ đang trực tuyến hoặc ngoại tuyến:

```js{4-15}
import React, { useState, useEffect } from 'react';
Expand All @@ -36,7 +36,7 @@ function FriendStatus(props) {
}
```

Now let's say that our chat application also has a contact list, and we want to render names of online users with a green color. We could copy and paste similar logic above into our `FriendListItem` component but it wouldn't be ideal:
Hãy cho là ứng dụng nhắn tin của chúng ta cũng có một danh sách bao gồm các liên hệ, và chúng ta muốn hiển thị tên của những người đang trực tuyến bằng màu xanh. Chúng ta có thể sao chép và dán những logic tương tự như trên vào component `FriendListItem`, nhưng đây không phải là một cách lí tưởng:

```js{4-15}
import React, { useState, useEffect } from 'react';
Expand All @@ -63,15 +63,15 @@ function FriendListItem(props) {
}
```

Instead, we'd like to share this logic between `FriendStatus` and `FriendListItem`.
Thay vào đó, chúng ta sẽ chia sẻ logic giữa `FriendStatus` `FriendListItem`.

Traditionally in React, we've had two popular ways to share stateful logic between components: [render props](/docs/render-props.html) and [higher-order components](/docs/higher-order-components.html). We will now look at how Hooks solve many of the same problems without forcing you to add more components to the tree.
Thông thường ở React, chúng ta có hai cách thông dụng nhất để chia sẻ logic giữa các component: [render props](/docs/render-props.html) [higher-order components](/docs/higher-order-components.html). Hãy xem cách mà Hook giải quyết những vấn đề chung mà không bắt buộc bạn phải viết thêm component vào ứng dụng.

## Extracting a Custom Hook {#extracting-a-custom-hook}
## Tách logic thành một Hook {#extracting-a-custom-hook}

When we want to share logic between two JavaScript functions, we extract it to a third function. Both components and Hooks are functions, so this works for them too!
Khi chúng ta muốn chia sẻ logic giữa hai hàm JavaScript, chúng ta tách nó thành một hàm thứ ba. Có thể thấy component và hook đầu là những hàm, vậy nên điều nãy cũng áp dụng được!

**A custom Hook is a JavaScript function whose name starts with "`use`" and that may call other Hooks.** For example, `useFriendStatus` below is our first custom Hook:
**Hook là hàm JavaScript với tên được bắt đầu bằng "`use`" và nó có thể gọi tới những Hook khác.** Ví dụ như, `useFriendStatus` là một Hook:

```js{3}
import { useState, useEffect } from 'react';
Expand All @@ -94,11 +94,11 @@ function useFriendStatus(friendID) {
}
```

There's nothing new inside of it -- the logic is copied from the components above. Just like in a component, make sure to only call other Hooks unconditionally at the top level of your custom Hook.
Có thể thấy tất cả logic đều được sao chép từ các component trước đó. Cũng như trong component, hãy đảm bảo rằng việc sử dụng các Hook khác không nằm trong khối điều kiện nào và được dùng ở ngoài cùng của hook bạn tạo ra.

Unlike a React component, a custom Hook doesn't need to have a specific signature. We can decide what it takes as arguments, and what, if anything, it should return. In other words, it's just like a normal function. Its name should always start with `use` so that you can tell at a glance that the [rules of Hooks](/docs/hooks-rules.html) apply to it.
Không như React component, một Hook tùy chọn không cần thiết phải có những đặc tính cụ thể. Chúng ta có thể quyết định những gì sẽ là tham số, và cái gì sẽ được trả về. Theo một các nói khác, Hook chỉ như một hàm thông thường. Tên của một Hook luôn nên bắt đầu bằng `use` và bạn có thể khẳng định ngay [quy tắc của Hooks](/docs/hooks-rules.html) đã được áp dụng.

The purpose of our `useFriendStatus` Hook is to subscribe us to a friend's status. This is why it takes `friendID` as an argument, and returns whether this friend is online:
Chức năng chính của `useFriendStatus` Hook là theo dõi trạng thái của các liên hệ trong danh sách. Đây là lí do Hook nhận `friendID` là tham số, và trả về trạng thái của liên hệ khi có sự thay đổi

```js
function useFriendStatus(friendID) {
Expand All @@ -110,13 +110,13 @@ function useFriendStatus(friendID) {
}
```

Now let's see how we can use our custom Hook.
Hãy xem các cách chúng ta có thể sử dụng một Hook.

## Using a Custom Hook {#using-a-custom-hook}
## Cách sử dụng một Hook {#using-a-custom-hook}

In the beginning, our stated goal was to remove the duplicated logic from the `FriendStatus` and `FriendListItem` components. Both of them want to know whether a friend is online.
Ngay từ đầu, mục đích chính của một Hook là loại bỏ những logic bị lặp lại khỏi `FriendStatus` `FriendListItem` component. Cả hai component đều được dùng để hiện thị trạng thái của các liên hệ là trực tuyến hay ngoại tuyến.

Now that we've extracted this logic to a `useFriendStatus` hook, we can *just use it:*
Bây giờ chúng ta có thể tách logic này thành `useFriendStatus` hook, sau đó *chỉ cần sử dụng:*

```js{2}
function FriendStatus(props) {
Expand All @@ -141,19 +141,19 @@ function FriendListItem(props) {
}
```

**Is this code equivalent to the original examples?** Yes, it works in exactly the same way. If you look closely, you'll notice we didn't make any changes to the behavior. All we did was to extract some common code between two functions into a separate function. **Custom Hooks are a convention that naturally follows from the design of Hooks, rather than a React feature.**
**Đoạn mã này có tương đương với ví dụ gốc?** Có, nó hoạt động theo một cách hoàn toàn giống. Nếu bạn xem kĩ, bạn sẽ nhận ra chúng tôi không hề tạo ra bất kì sự thay đổi nào đối với cách hoạt động. Tất cả những gì chúng tôi làm chỉ là tách những đoạn mã chung giữa hai hàm thành 1 hàm tách biệt. **Các Hook là một quy ước mà chúng tuân theo thiết kế của Hook một cách tự nhiên, chứ không phải là một tính năng của React.**

**Do I have to name my custom Hooks starting with “`use`?** Please do. This convention is very important. Without it, we wouldn't be able to automatically check for violations of [rules of Hooks](/docs/hooks-rules.html) because we couldn't tell if a certain function contains calls to Hooks inside of it.
**Tôi có bắt buộc phải đặt tên Hook của mình bắt đầu bởi `use`?** Bạn nên làm vậy. Quy ước này rất quan trọng. Nếu không có quy ước này, chúng ta sẽ không thể tự động tìm các sự vi phạm đối với [quy tắc của Hooks](/docs/hooks-rules.html) bởi vì chúng tôi không thể biết liệu một hàm nào đó có chứa các lệnh gọi tới Hook bên trong nó hay không.

**Do two components using the same Hook share state?** No. Custom Hooks are a mechanism to reuse *stateful logic* (such as setting up a subscription and remembering the current value), but every time you use a custom Hook, all state and effects inside of it are fully isolated.
**Hai component cùng sử dụng một Hook có chia sẻ state với nhau không?** Không. Các Hook là những cơ chế để sử dụng lại *logic có trạng thái* (ví dụ như cài đặt một sự theo dõi và ghi nhớ giá trị), nhưng mỗi lần bạn sử dụng một Hook, tất cả state và effect bên trong sẽ hoàn toàn được cô lập.

**How does a custom Hook get isolated state?** Each *call* to a Hook gets isolated state. Because we call `useFriendStatus` directly, from React's point of view our component just calls `useState` and `useEffect`. And as we [learned](/docs/hooks-state.html#tip-using-multiple-state-variables) [earlier](/docs/hooks-effect.html#tip-use-multiple-effects-to-separate-concerns), we can call `useState` and `useEffect` many times in one component, and they will be completely independent.
Mỗi khi một Hook được *gọi* thì Hook sẽ nhận được state đã được cô lập. Bởi vì chúng ta gọi đến `useFriendStatus` một cách trực tiếp, từ góc nhìn của React, component của chúng ta chỉ gọi đến `useState` `useEffect`. Và như chúng ta [đã học](/docs/hooks-state.html#tip-using-multiple-state-variables) [trước đó](/docs/hooks-effect.html#tip-use-multiple-effects-to-separate-concerns), chúng ta có thể gọi đến `useState` `useEffect` nhiều lần trong một component, và chúng hoàn toàn độc lập với nhau.

### Tip: Pass Information Between Hooks {#tip-pass-information-between-hooks}
### Lời khuyên: Chuyển giao thông tin giữa các Hook {#tip-pass-information-between-hooks}

Since Hooks are functions, we can pass information between them.
Việc Hook là hàm, chúng ta có thể chuyển giao các giá trị giữa chúng.

To illustrate this, we'll use another component from our hypothetical chat example. This is a chat message recipient picker that displays whether the currently selected friend is online:
Để minh họa điều này, chúng ta sẽ dùng các component khác từ một ứng dụng nhắn tin giả định. Đây là một giao diện chọn người nhận tin nhắn dùng để hiện thị liên hệ đã chọn đang trực tuyến hay ngoại tuyến:

```js{8-9,13}
const friendList = [
Expand Down Expand Up @@ -184,24 +184,24 @@ function ChatRecipientPicker() {
}
```

We keep the currently chosen friend ID in the `recipientID` state variable, and update it if the user chooses a different friend in the `<select>` picker.
Chúng ta giữ ID của liên hệ hiện đang chọn vào `recipientID`, và cập nhật chúng nếu người dùng chọn một người khác trong giao diện chọn người nhận tin nhắn `<select>`.

Because the `useState` Hook call gives us the latest value of the `recipientID` state variable, we can pass it to our custom `useFriendStatus` Hook as an argument:
Bởi vì `useState` Hook được gọi và cho chúng ta giá trị mới nhất của `recipientID`, chúng ta có thể gửi giá trị đó vào `useFriendStatus` Hook dưới dạng một tham số:

```js
const [recipientID, setRecipientID] = useState(1);
const isRecipientOnline = useFriendStatus(recipientID);
```

This lets us know whether the *currently selected* friend is online. If we pick a different friend and update the `recipientID` state variable, our `useFriendStatus` Hook will unsubscribe from the previously selected friend, and subscribe to the status of the newly selected one.
Điều này cho chúng ta biết nếu *liên hệ đã được chọn* là trực tuyến hay ngoại tuyến. Nếu chúng ta chọn 1 liên hệ khác và cập nhật giá trị `recipientID`, `useFriendStatus` Hook sẽ ngưng theo dõi trạng thái của liên hệ đã được chọn trước đó, và theo dõi trạng thái của liên hệ vừa mới được chọn.

## `useYourImagination()` {#useyourimagination}

Custom Hooks offer the flexibility of sharing logic that wasn't possible in React components before. You can write custom Hooks that cover a wide range of use cases like form handling, animation, declarative subscriptions, timers, and probably many more we haven't considered. What's more, you can build Hooks that are just as easy to use as React's built-in features.
Hook cung cấp sự linh hoạt trong việc chia sẻ logic mà trước đó đây là điều không thể trong React component. Bạn có thể tạo ra một Hook giải quyết một lượng lớn các trường hợp như xử lí các giá trị trong biểu mẫu, hoạt cảnh, các dạng theo dõi giá trị, bộ đếm giờ, và rất nhiều trường hợp khác mà chúng ta chưa đề cập tới. Hơn nữa, chúng ta có thể xây dựng Hook mới dễ dàng như việc sử dụng một tính năng đã có sẵn từ React.

Try to resist adding abstraction too early. Now that function components can do more, it's likely that the average function component in your codebase will become longer. This is normal -- don't feel like you *have to* immediately split it into Hooks. But we also encourage you to start spotting cases where a custom Hook could hide complex logic behind a simple interface, or help untangle a messy component.
Cố gắng không thêm các nội dung mang tính trừu tượng quá sớm. Bây giờ function component có thể làm được nhiều thứ hơn, có vẻ như những hàm bình thường trong codebase sẽ trở nên dài hơn. Điều này hoàn toàn bình thường -- đừng cảm thấy bản thân *cần phải* tách logic thành các Hook ngay lúc này. Nhưng chúng tôi khuyến khích bạn nên bắt đầu xem xét những trường hợp mà Hook sẽ giúp ẩn bớt những logic phức tạp, hoặc giúp gỡ rối những component quá phức tạp.

For example, maybe you have a complex component that contains a lot of local state that is managed in an ad-hoc way. `useState` doesn't make centralizing the update logic any easier so you might prefer to write it as a [Redux](https://redux.js.org/) reducer:
Ví dụ như, có thể bạn có một component phức tạp bao gồm rất nhiều state nội bộ được tạo ra chỉ cho những trường hợp cụ thể cần giải quyết. `useState` không thể giúp tập trung hóa việc cập nhật logic dễ dàng hơn, vậy bạn có thể sẽ ưu tiện viết dưới dạng [Redux](https://redux.js.org/) reducer:

```js
function todosReducer(state, action) {
Expand All @@ -218,9 +218,10 @@ function todosReducer(state, action) {
}
```

Reducers are very convenient to test in isolation, and scale to express complex update logic. You can further break them apart into smaller reducers if necessary. However, you might also enjoy the benefits of using React local state, or might not want to install another library.
Các reducer rất tiện dụng cho việc kiểm thử độc lập, và có thể mở rộng hoặc thu hẹp quy mô tùy ý để thực hiện các cập nhật logic phức tạp. Bạn cũng có thể tách chúng thành những reducer nhỏ hơn nếu cần. Tuy nhiên, có thể bạn cũng sẽ thích những tiện ích mà state nội bộ của React mang lại, hoặc cũng có thể không muốn cài đặt thêm thư viện ngoài.

Vậy nếu chúng ta có thể viết một `useReducer` Hook giúp chúng ta quản lý *state nội bộ* của các component bằng reducer? Một phiên bản đơn giản của nó sẽ như sau:

So what if we could write a `useReducer` Hook that lets us manage the *local* state of our component with a reducer? A simplified version of it might look like this:

```js
function useReducer(reducer, initialState) {
Expand All @@ -235,7 +236,7 @@ function useReducer(reducer, initialState) {
}
```

Now we could use it in our component, and let the reducer drive its state management:
Bây giờ chúng ta có thể sử dụng chúng trong các component, và để cho các reducer quản lí state của chúng:

```js{2}
function Todos() {
Expand All @@ -249,4 +250,4 @@ function Todos() {
}
```

The need to manage local state with a reducer in a complex component is common enough that we've built the `useReducer` Hook right into React. You'll find it together with other built-in Hooks in the [Hooks API reference](/docs/hooks-reference.html).
Sự cần thiết của việc quản lí state nội bộ bằng reducer trong một component phức tạp là điều hiển nhiên nên chúng tôi đã tạo ra `useReducer` Hook và đưa vào React. Bạn có thể tìm thấy chúng cùng với những Hook khác ở [Hooks API reference](/docs/hooks-reference.html).