Cách đặt khoảng thời gian trong React (setInterval)(có ví dụ)
Tags: react, beginners, tutorial
Published: 2022-05-15 15:02:54

Bài viết được dịch từ:
https://devtrium.com/posts/set-interval-react

Sử dụng `setInterval` cho phép bạn thực thi một hàm trong những khoảng thời gian cụ thể. Nó thường rất hữu ích trong các ứng dụng React, chẳng hạn như để kiểm tra một điều kiện thường xuyên hoặc lấy dữ liệu thường xuyên.

### Code
Đây là cách bạn sử dụng setInterval trong một component:

```
· · ·
useEffect(() => {
  const interval = setInterval(() => {
    console.log('This will be called every 2 seconds');
  }, 2000);

  return () => clearInterval(interval);
}, []);
· · ·
```
Đọc phần còn lại của bài viết nếu bạn muốn lời giải thích về những gì đang xảy ra ở trên!

###Cách hoạt động của `setInterval`

Có ba câu hỏi được đặt ra:

1. Tại sao `setInterval` được gọi bên trong hook `useEffect`?
2. Tại sao gọi hàm `setInterval` lại trông như vậy?
3. Tại sao chúng ta trả lại một cái gì đó từ hook `useEffect`?

#### 1. Tại sao `setInterval` được gọi bên trong hook `useEffect`?

Theo tài liệu React, "Effect Hook cho phép bạn thực hiện các side-effect trong các thành phần chức năng". Và đó chính xác là những gì chúng tôi muốn làm ở đây.

Bạn có thể hỏi điều gì sẽ xảy ra nếu chúng ta khai báo nó trong chính component. Hãy xem điều đó với các ví dụ nổi tiếng nhất, một bộ đếm!

Giả sử chúng ta muốn một bộ đếm bắt đầu từ 0 và tăng lên 1 sau mỗi giây.

Cách triển khai bộ đếm này bằng cách sử dụng code ở đầu bài viết như sau:

```
import { useState, useEffect } from 'react';

export default function ExampleCounter() {
  const [counter, setCounter] = useState(0);

  useEffect(() => {
    const interval = setInterval(() => {
      setCounter((prevCounter) => prevCounter + 1);
    }, 1000);

    return () => clearInterval(interval);
  }, []);

  return (
    <div className="App">
      <h1>Counter: {counter}</h1>
    </div>
  );
}
```

Một functional component khá đơn giản giữ state trong bộ đếm. State được tăng lên mỗi giây nhờ `setInterval` được xác định trong `useEffect`. 

Bây giờ điều gì sẽ xảy ra nếu tôi loại bỏ hoàn toàn `useEffect`?

```
import { useState } from 'react';

export default function ExampleCounter() {
  const [counter, setCounter] = useState(0);

  setInterval(() => {
    setCounter((prevCounter) => prevCounter + 1);
  }, 1000);

  return (
    <div className="App">
      <h1>Counter: {counter}</h1>
    </div>
  );
}
```
Chà, điều này xảy ra:

![Image counter-crazy](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/87m18l0w0fcovzlrmr6a.gif)

Đúng là một bộ đếm điên rồ! bạn có thể đoán được chuyện gì đã xảy ra không?

Vì `setInterval` được định nghĩa trực tiếp bên trong functional component, nó được gọi mỗi khi component render! Và component render khi nào? Khi state thay đổi! Và khi nào thì state thay đổi? Khi interval callback được gọi.

Vậy nên để side-effect trong `useEffect` nếu bạn không muốn side-effect bị gọi mỗi lần component renders.

#### 2. Tại sao gọi hàm `setInterval` lại trông như vậy?

Điều này khá dễ dàng: nó chỉ đơn giản là (sử dụng API web của setInterval)[https://developer.mozilla.org/en-US/docs/Web/API/setInterval]. Có một số chức năng được định nghĩa cho bạn trên web mà bạn có thể trực tiếp sử dụng. `setInterval` là một trong số đó.

Hàm nhận hai đối số:

1. Đầu tiên là một hàm sẽ được gọi trong các khoảng thời gian xác định.
2. Thứ hai là khoảng thời gian, tính bằng mili giây.

#### 3. Tại sao chúng ta trả lại một cái gì đó từ hook `useEffect`?

Xin nhắc lại, khi chúng ta muốn thực hiện một số hành động khi một component bị hủy, chúng ta xác định nó trong một hàm được trả về trong `useEffect`.

Một trường hợp sử dụng rất phổ biến của điều này là xóa các effect như khoảng thời gian.

Tại sao chúng ta cần xóa các khoảng thời gian? Vâng, hãy tưởng tượng chúng ta không xóa nó. Component bị hủy, nhưng khoảng thời gian vẫn chạy! Và nó đang cố gắng thiết lập một state không tồn tại nữa.

Bản thân đây không phải là vấn đề quá lớn (React sẽ bỏ qua nó), nhưng nó vẫn là một điểm rò rỉ bộ nhớ. Bây giờ hãy tưởng tượng thành phần được tạo và phá hủy lặp đi lặp lại. Bạn có thể nhận được hàng tá setIntervals đang chạy! Tổng hợp lại, điều này có thể làm chậm ứng dụng của bạn một cách nghiêm trọng.

Đó là lý do tại sao API web cung cấp cho chúng ta `setInterval` cũng cung cấp cho chúng tôi một hàm `clearInterval`. Và đó là lý do tại sao bạn gọi nó trong câu lệnh trả về `useEffect`!