React – “Nghệ thuật” sử dụng useEffect() được hiệu quả hơn
Bài viết được sự cho phép của tác giả Sơn Dương
useEffect là một trong những hook quan trọng và hay sử dụng nhất trong các dự án React. Do useEffect được sử dụng rất nhiều, nên nếu bạn viết code trong hook này không tốt, sẽ khiến cho dự án rất khó đọc và dễ gây ra những lỗi tiềm tàng.
Bài viết này mình sẽ chia sẻ một số nguyên tắc để làm việc với useEffect tốt hơn, dễ quản lý hơn.
1. Viết ít effect hơn
Về cơ bản, để mã nguồn dễ quản lý hơn, tránh những lỗi không đáng có, bạn hạn chế tối đa sử dụng các effects khi làm việc với state.
Với useEffect cũng vậy, nếu hạn chế được thì cứ hạn chế, hoặc tìm giải pháp khác thay thế.
Tuy nhiên, có những trường hợp bắt buộc bạn phải dùng tới useEffect hook, ví dụ như phải lấy dữ liệu ban đầu mỗi khi khởi tạo màn hình nào đó.
Data fetching
Data fetching là một side effect phổ biến thường được quản lý bằng useEffect(). Về cơ bản, các ứng dụng kiểu SPA đều phải lấy dữ liệu từ server. Do đó, data fetching là công việc phổ biến tới mức có rất nhiều thư viện 3rd được viết ra để tối ưu hóa chúng.
Có một số thư viện như react-query, Apollo… mà bạn có thể thử. Với những thư viện, bạn sẽ hạn chế tối đa phải sử dụng tới useEffect.
2. Tuân theo nguyên tắc single responsibility principle
Nếu bạn đã từng đọc về bộ triết lý để viết code clean có tên S.O.L.I.D thì sẽ biết ngay nguyên tắc này.
Nội dung nguyên tắc này là: Mỗi class, mỗi function chỉ nên làm một việc duy nhất, không nên kiêm nhiệm nhiều việc.
Nguyên tắc này cũng tương tự khi áp dụng với hàm trong useEffect()
, không nhồi nhét nhiều thứ vào một lần gọi useEffect.
Ví dụ: chúng ta có một lần dùng useEffect như sau:
React.useEffect(() => { document.title = 'hello world' trackPageVisit() }, [])
Như ở đây, mỗi khi component được mounted, bạn sẽ thực hiện hai việc là: gán tiêu đề “hello world” cho trang và theo dõi lượt visit trang.
Như vậy là bạn đã thực hiện 2 việc rất khác nhau trong lần sử dụng useEffect này. Hiện tại thì chúng ta có thể tặc lưỡi bỏ qua vì nó cũng vẫn đơn giản. Nhưng khi chức năng phần mềm phức tạp dần lên theo năm tháng thì sao?
Ví dụ chúng ta muốn thêm tính năng đồng bộ state với tiêu đề trang, mỗi khi state thay đổi thì tiêu đề trang sẽ tự động cập nhật theo:
const [title, setTitle] = React.useState('hello world') React.useEffect(() => { document.title = title trackPageVisit() }, [title])
Bạn đã nhận ra bug bắt đầu xuất hiện ở đây chưa?
Bug ở đây là mỗi khi tiêu đề trang thay đổi (vì một lý do nào đó như thay đổi cài đặt) thì hàm trackPageVisit()
cũng bị gọi và dẫn đến làm sai số liệu lượt visit trang.
Để xử lý lỗi này, đơn giản là tách ra làm hai lần gọi effect thôi:
const [title, setTitle] = React.useState('hello world') React.useEffect(() => { document.title = title }, [title]) React.useEffect(() => { trackPageVisit() }, [])
Bạn thấy đấy, code vừa dễ đọc, vừa tránh được lỗi lại vừa dễ quản lý khi sau này yêu cầu chức năng có phức tạp hơn.
Tham khảo việc làm React hấp dẫn rên TopDev
3. Viết custom hook
Thực sự mà nói, mình không thích những component mà nhồi nhét quá nhiều hook, chưa kể trong mỗi hook lại có quá nhiều công việc trong đó. Vì cách viết như này sẽ trộn lẫn giữa logic nghiệp vụ và các chỉ dấu – markup.
Bạn hoàn toàn có thể refectoring lại chỗ này cho code được đẹp hơn, bằng cách viết custom hook. Đặc biệt, các custom hook còn có thể tái sử dụng.
Dưới đây là một số ưu điểm của custom hook.
Có thể đặt tên hook theo ý muốn
Việc tạo ra một hook riêng với tên gọi dễ nhớ sẽ giúp mã nguồn của bạn dễ đọc hơn rất nhiều. Thay vì chỉ thấy gọi useEffect và một đống logic bên trong, dev nào mà join vào sau, để đọc đoạn code đó cũng hết hơi mới hiểu được ý đồ của tác giả.
Dưới đây là một ví dụ về đặt tên cho custom hook. Chỉ cần nhìn tên là biết hook này định làm gì.
const useTitleSync = (title: string) => { React.useEffect(() => { document.title = title }, [title]) } const useTrackVisit = () => { React.useEffect(() => { trackPageVisit() }, []) }
Đóng gói logic
Đây có lẽ là lợi thế lớn nhất của custom hook. Khi mà mọi logic được đóng gói hoàn chỉnh, khi cần là gọi sử dụng.
Như ví dụ trên, useTitleSync
hook vẫn chưa hoàn chỉnh lắm, khi mà nó chỉ đóng gói được phần đánh dấu effect, khi mà component nào sử dụng vẫn phải quản lý thủ công phần tiêu đề. Vậy tại sao chúng ta không đưa luôn phần quản lý tiêu đề vào trong hook này?!
const useTitle = (initialTitle: string) => { const [title, setTitle] = React.useState(initialTitle) React.useEffect(() => { document.title = title }, [title]) return [title, setTitle] as const }
Dễ unit test
Nói đến clean code thì không thể nhắc tới việc phải dễ unit test.
Việc chúng ta đã tách được custom hook ra khỏi logic của component sẽ khiến việc test custom hook giống như bao function bình thường khác. Khi test, bạn sẽ không còn phải quan tâm tới các logic khác của component như trackingPageVisit
.
import { act, renderHook } from '@testing-library/react-hooks' describe('useTitle', () => { test('sets the document title', () => { const { result } = renderHook(() => useTitle('hello')) expect(document.title).toEqual('hello') act(() => result.current('world')) expect(document.title).toEqual('world') }) })
Trên đây là một kinh nghiệm để sử dụng useEffect được hiệu quả, giúp mã nguồn cũng sẽ dễ đọc và hạn chế lỗi tiềm tàng.
Bạn thấy những kinh nghiệm này thế nào? Có giúp được gì cho dự án của bạn không? Để lại ý kiến chia sẻ với mọi người trong phần bình luận nhé.
Bài viết gốc được đăng tải tại vntalking.com
Xem thêm:
- Một số Patterns hay sử dụng trong React
- Tìm hiểu về ExpressJS và những ưu nhược điểm của ExpressJS
- Setup Eslint và Prettier cho dự án React theo chuẩn coding style guide của Airbnb
Xem thêm Việc làm IT hấp dẫn trên TopDev
- M Mới ra trường không kinh nghiệm, sao làm BA?
- C Chuyển đổi SA key sang Workload Identity
- U Use Case Diagram và 5 sai lầm thường gặp
- K Kinh nghiệm xử lý câu lệnh điều kiện trong JavaScript
- D Dart là gì? Ứng dụng của ngôn ngữ lập trình Dart
- C Chuẩn Hóa CV, Nhận Ngay Phím Chất
- S So sánh MySQL và MongoDB: Nên chọn CSDL nào?
- D Dân BA có cần phải rành về kỹ thuật???
- C CSS Selector là gì? Cách sử dụng các loại CSS Selector phổ biến
- P Phân biệt Sketch, Wireframe, Mockup, và Prototype?