Giới thiệu về Debug trong ứng dụng ReactJS

Viet Vu
VelaCorp
Published in
9 min readOct 27, 2018

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":

Chrome developer tools with Dark theme, inspecting Discordapp.com page

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ì ?

Như thế này, đúng không?

“Đúng thế, ‘BTM’, là thứ mà tôi đang nghĩ!” Phải vậy không?

BTM === John (Hic, cú lừa…?)

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):

Chi tiết một response được trả về từ Discord

Đ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:
CORS request failed

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:

Discord Messages component được kiểm tra bằng React Developer Tools

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 $rtrong bảng Console, nó sẽ hiển thị cho bạn thiscủa phần tử được chọn này:

$r = this

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à displayNametrê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:

Kich hoạt Breakpoint

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ần this).

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 :))

Credit: https://en.wikipedia.org/wiki/Rubber_duck_debugging#/media/File:Rubber_duck_assisting_with_debugging.jpg

Bài viết được dịch từ Intro to debugging ReactJS applications của tác giả Bartosz Szczeciński

--

--