Hướng dẫn toàn diện về useEffect trong ReactJS cho người mới bắt đầu

Xin chào các pháp sư React tương lai! Hôm nay, chúng ta sẽ bắt đầu một hành trình thú vị vào thế giới của useEffect trong React. Đừng lo lắng nếu bạn mới làm quen với lập trình - tôi sẽ là người hướng dẫn thân thiện của bạn, và chúng ta sẽ cùng nhau từng bước. Cuối cùng của bài hướng dẫn này, bạn sẽ sử dụng useEffect như một chuyên gia!

ReactJS - Using useEffect

useEffect là gì?

Trước khi chúng ta bắt đầu, hãy hiểu về useEffect là gì. Hãy tưởng tượng bạn đang nướng bánh. Bạn trộn nguyên liệu, cho vào lò nướng, và sau đó... gì? Bạn có thể muốn đặt một đồng hồ hẹn giờ, đúng không? Đó là điều useEffect làm trong React. Nó cho phép bạn thực hiện các "tác dụng phụ" trong các thành phần của bạn.

Tác dụng phụ là các hành động xảy ra cùng với công việc chính của thành phần là渲染 giao diện người dùng. Những điều này có thể bao gồm:

  • Lấy dữ liệu từ API
  • Thay đổi DOM thủ công
  • Thiết lập các đăng ký

Bây giờ, hãy vào phần chi tiết!

Định dạng của useEffect

Hook useEffect có một cách viết cụ thể. Hãy phân tích nó:

useEffect(() => {
// Mã hiệu ứng của bạn ở đây
}, [dependencies]);

Dưới đây là ý nghĩa của từng phần:

  1. useEffect: Đây là tên của hook mà chúng ta đang sử dụng.
  2. () => { ... }: Đây là một hàm mũi tên nơi chúng ta đặt mã hiệu ứng của mình.
  3. [dependencies]: Đây là một mảng tùy chọn nơi chúng ta liệt kê bất kỳ giá trị nào mà hiệu ứng của chúng ta phụ thuộc vào.

Hãy xem một ví dụ đơn giản:

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

function Timer() {
const [seconds, setSeconds] = useState(0);

useEffect(() => {
const interval = setInterval(() => {
setSeconds(prevSeconds => prevSeconds + 1);
}, 1000);

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

return <div>Giây: {seconds}</div>;
}

Trong ví dụ này, chúng ta đang tạo một đồng hồ đơn giản. Hook useEffect thiết lập một interval để tăng giá trị của seconds mỗi giây. Mảng dependency trống [] có nghĩa là hiệu ứng này chỉ sẽ chạy một lần khi thành phần được挂载.

Tính năng của Hook Effect

Bây giờ chúng ta đã xem qua một ví dụ cơ bản, hãy khám phá một số tính năng chính của hook hiệu ứng:

  1. Thời gian: Hiệu ứng chạy sau mỗi lần render theo mặc định.
  2. Thực hiện có điều kiện: Chúng ta có thể kiểm soát khi nào hiệu ứng chạy bằng cách sử dụng mảng dependency.
  3. Dọn dẹp: Hiệu ứng có thể trả về một hàm dọn dẹp để ngăn chặn rò rỉ bộ nhớ.

Hãy xem chi tiết từng tính năng này.

Thời gian

Theo mặc định, useEffect chạy sau mỗi lần render. Điều này có nghĩa là nếu bạn cập nhật state trong hiệu ứng, nó có thể gây ra một vòng lặp vô hạn! Dưới đây là một ví dụ về điều không nên làm:

function BadExample() {
const [count, setCount] = useState(0);

useEffect(() => {
setCount(count + 1); // Điều này sẽ gây ra một vòng lặp vô hạn!
});

return <div>{count}</div>;
}

Thực hiện có điều kiện

Để ngăn chặn hiệu ứng chạy không cần thiết, chúng ta có thể cung cấp một mảng dependency:

function ConditionalEffect({ userId }) {
const [user, setUser] = useState(null);

useEffect(() => {
fetchUser(userId).then(data => setUser(data));
}, [userId]);

return <div>{user ? user.name : 'Đang tải...'}</div>;
}

Trong ví dụ này, hiệu ứng chỉ sẽ chạy khi userId thay đổi.

Dọn dẹp

Một số hiệu ứng cần được dọn dẹp để ngăn chặn rò rỉ bộ nhớ. Dưới đây là cách chúng ta có thể làm điều đó:

function CleanupExample() {
useEffect(() => {
const subscription = subscribeToSomething();

return () => {
subscription.unsubscribe();
};
}, []);

return <div>Tôi đã đăng ký!</div>;
}

Hàm trả về từ hiệu ứng sẽ được gọi khi thành phần được gỡ bỏ.

Lấy dữ liệu bằng Effect

Một ứng dụng phổ biến của useEffect là lấy dữ liệu từ API. Hãy xem một ví dụ:

function DataFetcher() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);

useEffect(() => {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
setData(data);
setLoading(false);
})
.catch(error => {
setError(error);
setLoading(false);
});
}, []);

if (loading) return <div>Đang tải...</div>;
if (error) return <div>Lỗi: {error.message}</div>;
return <div>Dữ liệu: {JSON.stringify(data)}</div>;
}

Thành phần này lấy dữ liệu khi nó được挂载, xử lý các trạng thái tải và lỗi, và hiển thị dữ liệu khi nó sẵn sàng.

Thay đổi DOM

useEffect cũng có thể được sử dụng để trực tiếp thay đổi DOM. Dưới đây là một ví dụ:

function DOMManipulator() {
useEffect(() => {
const element = document.getElementById('my-element');
element.style.color = 'red';

return () => {
element.style.color = '';
};
}, []);

return <div id="my-element">Tôi là màu đỏ!</div>;
}

Hiệu ứng này thay đổi màu sắc của một phần tử thành đỏ khi thành phần được挂载, và đặt lại nó khi thành phần được gỡ bỏ.

Hàm dọn dẹp

Chúng ta đã đề cập đến các hàm dọn dẹp, nhưng hãy đi sâu hơn một chút. Các hàm dọn dẹp rất quan trọng để ngăn chặn rò rỉ bộ nhớ và hành vi không cần thiết. Dưới đây là một ví dụ phức tạp hơn:

function WindowResizer() {
const [windowWidth, setWindowWidth] = useState(window.innerWidth);

useEffect(() => {
const handleResize = () => setWindowWidth(window.innerWidth);
window.addEventListener('resize', handleResize);

return () => {
window.removeEventListener('resize', handleResize);
};
}, []);

return <div>Chiều rộng cửa sổ: {windowWidth}px</div>;
}

Trong ví dụ này, chúng ta đang thêm một bộ lắng nghe sự kiện khi thành phần được挂载, và loại bỏ nó khi thành phần được gỡ bỏ. Điều này ngăn chặn bộ lắng nghe sự kiện tiếp tục hoạt động sau khi chúng ta không cần nó nữa.

Tóm tắt

Hãy tóm tắt những gì chúng ta đã học về useEffect:

Tính năng Mô tả
Định dạng useEffect(() => { ... }, [dependencies])
Thời gian Chạy sau mỗi lần render theo mặc định
Thực hiện có điều kiện Sử dụng mảng dependency để kiểm soát khi nào hiệu ứng chạy
Dọn dẹp Trả về một hàm từ hiệu ứng để dọn dẹp
Lấy dữ liệu Có thể được sử dụng để lấy dữ liệu từ API
Thay đổi DOM Có thể trực tiếp thay đổi DOM
Hàm dọn dẹp Quan trọng để ngăn chặn rò rỉ bộ nhớ

Và thế là bạn đã bước vào thế giới của useEffect. Nhớ rằng, giống như bất kỳ công cụ mạnh mẽ nào khác, việc thành thạo nó cần phải luyện tập. Vậy đừng ngại thử nghiệm và mắc lỗi - đó là cách chúng ta học hỏi. Chúc bạn may mắn và thành công trong việc lập trình, và mong rằng các hiệu ứng của bạn luôn sạch sẽ và các thành phần của bạn luôn phản hồi!

Credits: Image by storyset