Một trong những điều quan trọng mà một developer nên nghiên cứu là làm thế nào để debug ứng dụng trong một ngôn ngữ lập trình. Biết cách debug không chỉ giúp bạn dễ dàng tìm ra nguyên nhân gây lỗi trong code của mình, mà còn cho bạn thấy cách thức một ngôn ngữ lập trình hoạt động qua đó sẽ giúp bạn tránh mắc những lỗi tương tự trong tương lai.
Tôi sẽ giới thiệu một số kỹ thuật và công cụ mà bạn sẽ thấy hữu ích khi phát triển một ứng dụng ReactJS. Trong bài viết này tôi sử dụng trình duyệt Chrome, nhưng hầu hết các kỹ thuật phổ biến và các công cụ đều có sẵn cho những trình duyệt khác nhau.
Lưu ý rằng những ví dụ sau được thực hiện khi sourcemap được kích hoạt. Việc debug một ứng dụng không kích hoạt sourcemap sẽ gây ra rất nhiều khó khăn.
Đầu tiên- Hiểu về trình duyệt mà chúng ta sử dụng
Hầu hết các công cụ hỗ trợ mà chúng ta cần đều có sẵn trong trình duyệt-tôi đang nói về các developer tool của trình duyệt. Trong hâù hết các trường hợp chúng ta có thể mở các công cụ bằng cách bấm F12 hoặc click chuột phải và chọn "Inspect":
Có hai thẻ quan trọng nhất của Devtools mà bạn nên làm quen đó là "Console" và "Network". Tôi sẽ giới thiệu chúng cùng với những phần khác.
Console-Người bạn đầu tiên và mạnh mẽ nhất
Thẻ console là một trong những công cụ quan trọng nhất. Nó không chỉ hiển thị tất cả các message mà ứng dụng của chúng ta đang ghi log bằng console.log
, nó cũng hiển thị phần lớn các thông báo lỗi trong trình duyệt do ứng dụng gây ra. Trên hết, đó là môi trường REPL nơi mà bạn có thể nhập bất kỳ mã JS hợp lệ nào và thực thi ngay lập tức.
console
object trong JS có rất nhiều tính năng - nếu bạn muốn tìm hiểu thêm thì tôi khuyên bạn nên đọc tài liệu của MDN.
console
là cách cơ bản nhất để debug một ứng dụng. Bạn muốn xem một phần nào đó trong code của bạn có thực hiện đúng ý mình không? Liệu hàm xử lý onClick có được gọi đến? Hãy dùngconsole.log
, trong hầu hết các trường hợp output sẽ cho phép bạn nhanh chóng tìm ra được những sai sót trong ứng dụng của mình.
Lưu ý: console.log
khi được sử dụng với một đối tượng / mảng như một tham số có thể khiến bạn bị bối rối. Hãy xem xét đoạn code sau:
const myObject = { name: 'BTM' }
console.log(myObject);
myObject.name = 'John';
Bạn đang mong đợt output của log là gì ?
“Đúng thế, ‘BTM’, là thứ mà tôi đang nghĩ!” Phải vậy không?
Ok …. Vậy điều gì đã xảy ra? console.log
sử dụng tham chiếu khi chúng ta xem xét phiên bản mở rộng bằng cách click mũi tên trỏ xuống, nhưng giá trị thì lại nằm trong phiên bản thu gọn. Hãy ghi nhớ điều này khi thực hiện debug ứng dụng React - nó có thể giống như dữ liệu hợp lệ được chuyển đến một thành phần con trong khi thực tế nó đang bị thay đổi trong thành phần cha!
Tab Network
Có khả năng rất cao là ứng dụng của bạn sử dụng một số hình thức giao tiếp với server và do đó bạn sẽ nhận được dữ liệu sai hoặc dữ liệu sẽ có định dạng mà bạn không mong đợi. Thẻ Network là cách để bạn “truy cập” đến đây. Nó sẽ theo dõi tất cả các yêu cầu HTTP và Websocket đã xảy ra kể từ khi bạn mở công cụ (điều này thật không may cho Websockets — nó sẽ chỉ hiển thị thông tin liên lạc xảy ra trên các socket được mở sau khi bạn mở Developer Tools, vì vậy nếu bạn cần theo dõi Websockets hãy nhớ mở Developer Tools trước, hoặc nếu đã mở DevTool trước rồi thì bạn cần refresh lại trang để thực hiện lại quá trình trên):
Điều quan trọng cần nhớ:
- Nguyên tắc chung là “request không thành công có màu đỏ, request thành công màu trắng”
- Mỗi yêu cầu có thể có nhiều trạng thái, theo dõi các yêu cầu “Pending”-nếu trạng thái vẫn tồn tại trong một thời gian dài hơn, điều đó có nghĩa là bạn đã nhập sai URL hoặc chương trình backend đang gặp sự cố.
- Khi bạn click vào request, bảng chi tiết sẽ mở — tab “Preview” và “Response” sẽ hiển thị dữ liệu của bạn; nếu như dữ liệu cỏ vẻ là ổn nhưng bạn không thể phân tích cú pháp trong ứng dụng của mình, hãy kiểm tra “Content-type” trong tab “Headers” — đôi khi máy chủ sẽ gửi cho bạn dữ liệu JSON dưới dạng văn bản hoặc HTML.
- Một lỗi rất phổ biến dẫn đến dữ liệu hiển thị trong thẻ“Network” nhưng không thể truy cập được đối với ứng dụng của bạn đó là không thực hiện được giao thức CORS. Theo dõi các lỗi như thế này trong phần “Console” của bạn:
Lỗi CORS đặc biệt phức tạp vì nó sẽ hiển thị như một request thành công (nó sẽ có màu trắng trong danh sách) và tất cả dữ liệu bạn mong đợi sẽ có trong tab “Preview”. Để hạn chế “giới hạn” của CORS, bạn cần phải làm việc với nhà cung cấp backend (để cho phép CORS trên máy chủ hoặc cấu hình nó theo cách mà ứng dụng của bạn có thể sử dụng) hoặc sử dụng giải pháp proxy (CORS chỉ ảnh hưởng đến trình duyệt — bất kỳ proxy nào được viết bằng ngôn ngữ phía máy chủ sẽ bỏ qua nó).
React Developer Tools
React developer tools là một tiện ích mở rộng cho trình duyệt đến từ Facebook sẽ cung cấp công cụ cho phép chúng ta kiểm tra xem dữ liệu và cấu trúc JSX có ổn không. Bạn có thể cài đặt tiện ích từ này thư viện của trình duyệt hoặc tải phiên bản độc lập ở đây .
Sau khi cài đặt tiện ích mở rộng, bạn sẽ thấy biểu tượng React trên thanh biểu tượng, biểu tượng này sẽ sáng lên mỗi khi bạn truy cập trang web được hỗ trợ React và bạn sẽ thấy một tab khác (React) được thêm vào Developer Tools của trình duyệt. Khi mở tab này ra, bạn sẽ thấy một khung tương tự như cấu trúc HTML nhưng thay vì các nút HTML, bạn sẽ thấy JSX hiện tại:
Click vào từng phần tử JSX sẽ hiển thị cho bạn dữ liệu quan trọng của nó bao gồm: key, ref, state và props . Bạn cũng có thể sử dụng tool để thay đổi một số giá trị (chủ yếu là các giá trị vô hướng: boolean, số, chuỗi).
Bạn có thể sử dụng ô “Search” để tìm các component theo tên, và tính năng khác là kiểm tra phần tử mà bạn đã nhấp chuột phải và chọn “Inspect” (tất cả những gì bạn phải làm là thay đổi từ thẻ “Element” sang “React” ).
Tuy nhiên, một trong những tính năng quan trọng nhất nằm trong bản cập nhật của React Developer Tools đó là thêm vào bảng “Console” mặc định (nếu bạn không nhìn thấy nó khi đang ở tab “React”, hãy nhấp vào biểu tượng dấu ba chấm và chọn “Show console drawer”). Khi một phần tử React được chọn, bạn có thể sử dụng $r
trong bảng Console, nó sẽ hiển thị cho bạn this
của phần tử được chọn này:
Bạn cũng có thể tương tác với phần tử, gọi đến phương thức của nó và trình xử lý sự kiện giống như một sự tương tác bình thường. Tính năng này cho phép bạn thay đổi cấu trúc phức tạp mà chúng tôi đã đề cập trước đó (ví dụ: khi bạn chọn một phần tử, sau đó sử dụng$r.setState({message: 'Hello world!'})
điều này sẽ kích hoạt quá trình bình thường.
Quan trọng: nếu bạn đang chạy một bản production build, tên của các thành phần sẽ bị che khuất theo mặc định. Bạn có thể làm được điều đó bằng cách đặt một biế tĩnh là displayName
trên thành phần. Bạn có thể sử dụng babel-plugin-add-react-displayname để đơn giản hóa quá trình này.
Debugging nghiêm túc (Y)— breakpoints
Vừa nãy chúng ta đã tìm hiểu tất cả những thứ “dễ dàng”, bây giờ hãy chuyển sang “real world debugging” — làm việc với các breakpoint. Breakpoint là một lệnh trong code có nhiệm dừng tất cả việc thực hiện và kích hoạt trình debug. Có 2 cách thông dụng để thiết lập các breakpoint :
- Thêm
debugger;
vào source code của bạn — khi trình phân tích cú pháp gặp lệnh này và Developer Tools đang mở nó sẽ kích hoạt breakpoint. - Tìm điểm mà chúng ta muốn break trong Develooper Tools (tab “Source”) và click vào số dòng — việc này sẽ thêm các điểm đánh dấu trực quan và nó cũng sẽ hoạt động giống như cách bên trên; các breakpoint được thiết lập theo cách này vẫn tồn tại nếu trình duyệt được refresh.
Khi thực thi code tới các breakpoint, bạn sẽ thấy rằng trang đang ở trạng thái “tạm dừng” và Devtool lúc này có thêm một số tùy chọn:
Bảng “Sources” hiển thị trên mỗi breakpoint (bạn có thể có nhiều breakpoint trong ứng dụng của mình tại bất kỳ thời điểm nào) và phía bên phải hiển thị một số thông tin về trạng thái hiện tại của ứng dụng, quan trọng nhất là:
- bảng điều hướng ở trên cùng — cho phép chúng ta tiếp tục ứng dụng, lùi lại / chuyển tiếp trong khi thực thi hoặc vô hiệu hóa tất cả các breakpoint
- callstack — cho chúng ta biết hàm nào được gọi đến để lay trạng thái hiện tại của ứng dụng
- scope — hiển thị những biến nào có tại điểm thực hiện và chúng nằm trong scope nào (local, global, closure) cùng với các giá trị của chúng; bạn cũng có thể thay đổi các giá trị này tại breakpoint, những thay đổi này— khi được tiếp tục — sẽ được phản ánh trong ứng dụng của bạn.
- Console lúc này được kết nối với trạng thái ứng dụng, bạn có quyền truy cập vào tất cả các biến được hiển thị trong “Scope” — điều này cho phép bạn thay đổi các giá trị trong code, trong các trường hợp khác không thể truy cập được từ khu vực
window
(ví dụ: bạn có quyền truy cập vào các thành phầnthis
).
Bạn đã bao giờ rơi vào tình huống, khi bạn bắt đầu giaỉ thích một bug kì lạ cho một người và sau đó người đó thốt lên rằng "Vậy thì cuối cùng, cái gì ở đây đang sai?". Đọc thêm ở đây nhé!
Hi vọng sau bài giới thiệu này, các bạn có những phút giây thoải mái bên chú vịt cao su của mình :))
Bài viết được dịch từ Intro to debugging ReactJS applications của tác giả Bartosz Szczeciński