React Hooks - Giới thiệu cơ bản
Hooks là một tính năng bổ sung mới từ React 16.8 trở đi. Chúng cho phép bạn sử dụng State và các tính năng khác của React mà không cần viết một class.
Tất tần tật về React
import React, { useState } from 'react';
function Example() {
// Declare a new state variable, which we'll call "count"
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked {count} times</p>
<button onClick={() => setCount(count + 1)}>
Click me
</button>
</div>
);
}
Chúng ta sẽ bắt đầu học React Hooks ở các phần tiếp theo. Phần này mình chỉ giới thiệu sơ về lý do tại sao Facebook lại phát triển Hooks và cách chúng giúp bạn phát triển các ứng dụng với chúng.
Video giới thiệu
Tại React Conf 2018, Sophie Alpert và Dan Abramov đã giới thiệu Hooks, tiếp theo là Ryan Florence trình bày cách cấu trúc lại một ứng dụng để sử dụng chúng. Xem video tại đây:
Không tồn tại Breaking Changes
- Hook hoàn toàn không bắt buộc: Bạn có thể thử dùng Hooks trong một số components mới mà không cần phải viết lại code hiện tại. Bạn cũng không cần phải học hoặc sử dụng Hooks nếu bạn không muốn.
- 100% tương thích ngược: Hooks không chứa các thay đổi có thể khiến break ứng dụng của bạn.
- Hook hiện tại đã có sẵn trong React Core từ phiên bản 16.8 trở đi.
Facebook cũng không hề có dự định xóa bỏ các React Classes. Nếu bạn vẫn còn lăn tăn thì có thể tham khảo phần bên dưới của bài viết này.
Hooks không thay thế kiến thức của bạn về các khái niệm trong React. Thay vào đó, Hooks cung cấp một API trực tiếp hơn cho các khái niệm React mà bạn đã biết: props, state, context, refs, and lifecycle. Như chúng tôi sẽ trình bày ở phần sau, Hooks cũng cung cấp một cách thức mạnh mẽ mới để kết hợp chúng lại với nhau.
Nếu bạn chỉ muốn bắt đầu học Hooks, mình rất vui và hẹn gặp lại bạn trong bài viết tiếp theo.
Bạn cũng có thể tiếp tục đọc trang này để tìm hiểu thêm về lý do tại sao Facebook thêm Hooks và cách thức Facebook bắt đầu sử dụng Hooks mà không cần viết lại ứng dụng của mình.
Động lực phát triển
Hooks giải quyết nhiều vấn đề dường như không được kết nối trong React mà phía Facebook đã gặp phải trong hơn 5 năm phát triển và maintenance hàng chục ngàn components. Cho dù bạn đang học React, sử dụng nó hàng ngày hay thậm chí thích một thư viện khác với mô hình components tương tự, bạn có thể nhận ra một vài vấn đề tương tự trong số chúng.
Rất khó để sử dụng lại các logic stateful giữa các components
React không đưa ra cách "đính kèm" các behaviour có thể tái sử dụng vào một component một cách chính thức (ví dụ: kết nối nó với một store).
Nếu đã làm việc với React một thời gian, bạn có thể quen với các pattern như render props và các higher-order components để giải quyết vấn đề này. Nhưng các patterns này yêu cầu bạn phải cấu trúc lại các components của mình khi sử dụng, điều này có thể gây cồng kềnh và khiến code khó theo dõi hơn.
Nếu bạn nhìn vào một ứng dụng React điển hình trong React DevTools, bạn có thể sẽ tìm thấy một "wrapper hell" gồm các components được bao quanh bởi nhiều lớp providers, consumers, higher-order components, render props, và các lớp abstractions khác. Mặc dù chúng ta có thể lọc chúng ra trong DevTools, nhưng điều này chỉ ra một vấn đề tiềm ẩn: React cần một tính năng tốt hơn để chia sẻ các stateful logic.
Với Hooks, bạn có thể trích xuất các stateful logic từ một component để nó có thể được kiểm tra một cách độc lập và tái sử dụng. Hooks cho phép bạn sử dụng lại stateful logic mà không thay đổi các cấu trúc phân cấp components của bạn. Điều này giúp bạn dễ dàng chia sẻ Hook giữa nhiều components hoặc với cộng đồng.
Chúng ta sẽ thảo luận về vấn đề này nhiều hơn trong phần Xây dựng các Hooks của riêng bạn.
Các thành phần phức tạp trở nên khó hiểu
Facebook thường phải duy trì các components từ đơn giản lúc ban đầu nhưng đã phình to thành một mớ hỗn độn không thể quản lý của các stateful logic và các tác dụng phụ khác.
Các phương thức lifecycle thường chứa một hỗn hợp các logic không liên quan đến nhau lắm. Ví dụ: các components có thể thực hiện một số data fetching bên trong componentDidMount và componentDidUpdate.
Tuy nhiên, cùng một phương thức componentDidMount cũng có thể chứa một số logic không liên quan như thiết lập các event listeners với việc dọn dẹp dữ liệu mà sẽ được thực hiện trong componentWillUnmount. Các code xử lý có liên quan và ảnh hưởng lẫn nhau lại bị tách ra, trong khi các code hoàn toàn không liên quan lại sẽ được kết hợp trong một method duy nhất. Điều này làm cho việc phát triển các logic dễ dàng văng lỗi và có sự không nhất quán.
Trong nhiều trường hợp, không thể chia những components này thành những components nhỏ hơn vì stateful logic ở khắp nơi, cũng như khó để thực hiện unit testing cho chúng. Đây là một trong những lý do khiến nhiều người thích kết hợp React với một thư viện quản lý state riêng biệt. Tuy nhiên, điều đó thường tạo ra quá nhiều abstraction, yêu cầu bạn phải di chuyển qua lại giữa các files khác nhau, và làm cho việc tái sử dụng các components trở nên khó khăn hơn.
Để giải quyết vấn đề này, Hooks cho phép bạn chia một component thành các functions nhỏ hơn dựa trên những phần có liên quan (chẳng hạn như thiết lập subscriptions hoặc thực hiện fetching dữ liệu), thay vì buộc phân chia dựa trên các lifecycle methods. Bạn cũng có thể chọn tham gia quản lý local state của component bằng một reducer giúp nó dễ dự đoán hơn.
Chúng ta sẽ thảo luận thêm về vấn đề này trong phần Sử dụng Effect Hook.
Các Class dễ gây nhầm lẫn cho chúng ta
Ngoài việc khiến việc tái sử dụng code và tổ chức code trở nên khó khăn hơn, phía Facebook nhận thấy rằng các Class có thể là một rào cản lớn đối với việc học React. Bạn phải hiểu cách hoạt động của nó trong JavaScript, điều này rất khác với cách nó hoạt động trong hầu hết các ngôn ngữ. Bạn cũng phải nhớ bind các event handlers. Không có đề xuất cú pháp stable, code lại dài dòng. Mọi người có thể hiểu rất rõ về các props, state và luồng dữ liệu từ trên xuống nhưng vẫn phải vật lộn với các class. Sự khác biệt giữa các functional components với class components trong React, khi nào sử dụng từng loại component dẫn đến sự bất đồng ngay cả giữa các developer React có kinh nghiệm.
Ngoài ra, React đã ra mắt được khoảng 5 năm và Facebook muốn đảm bảo rằng nó vẫn phù hợp trong 5 năm tới. Như Svelte, Angular, Glimmer... và những framework khác cho thấy, việc biên dịch trước các components có rất nhiều tiềm năng trong tương lai. Đặc biệt nếu nó không giới hạn ở các patterns. Gần đây, Facebook đã thử nghiệm việc đóng gói các components bằng cách sử dụng Prepack và nhận thấy những kết quả ban đầu đầy hứa hẹn.
Tuy nhiên, Facebook nhận định rằng các Class Components có thể xảy ra một số patterns ngoài ý muốn làm việc tối ưu hóa trở nên chậm hơn. Các class cũng gặp phải nhiều vấn đề với các công cụ ngày nay. Ví dụ: các class không được minify tốt và chúng làm cho việc hot reloading không đáng tin cậy. Facebook muốn giới thiệu một API giúp code có nhiều khả năng được tối ưu hóa tốt hơn.
Để giải quyết những vấn đề này, Hooks cho phép bạn sử dụng nhiều tính năng của React hơn mà không cần class. Về mặt khái niệm, các React components sẽ luôn gần với functional hơn. Hooks bao gồm các functions, nhưng không làm mất đi tinh thần của React. Hooks cung cấp quyền truy cập nhanh chóng và không yêu cầu bạn phải học các kỹ thuật reactive programming hay functional programming phức tạp.
Facebook không có kế hoạch xóa bỏ Class Components khỏi React
Điều quan trọng, Hooks hoạt động song song với code hiện có để bạn có thể áp dụng chúng dần dần. Không cần vội vàng chuyển sang sử dụng Hooks.
Mình khuyên bạn nên tránh viết lại quá nhiều code, đặc biệt là đối với các class components phức tạp hiện có. Tốt nhất trước tiên bạn nên thực hành sử dụng Hook trong các components mới và không quan trọng và đảm bảo rằng mọi người trong team của bạn cảm thấy thoải mái với chúng.
Facebook dự định sẽ phát triển cho Hooks tất cả các use cases hiện có cho các class, nhưng họ vẫn sẽ tiếp tục hỗ trợ các class components trong tương lai gần. Tại Facebook, có hàng chục nghìn components được viết dưới dạng các class và họ hoàn toàn không có kế hoạch viết lại chúng. Thay vào đó, họ đang bắt đầu sử dụng Hooks trong các components mới song song với các class sẵn có.