React

React là gì

React là một thư viện JavaScript mã nguồn mở và giao diện người dùng, rất hữu ích trong việc phát triển giao diện người dùng dành riêng cho các ứng dụng SPA. Nó hữu ích trong việc xây dựng các thành phần giao diện người dùng (UI) phức tạp và có thể tái sử dụng của các ứng dụng web và di động vì nó tuân theo mô hình dựa trên component.

Tính năng của React:

  • Tăng hiệu suất của ứng dụng với Virtual DOM.

  • JSX làm cho code dễ đọc và viết.

  • Nó kết xuất cả phía máy khách và máy chủ.

  • Dễ dàng tích hợp với các frameworks khác (Angular, BackboneJS) vì nó chỉ là một thư viện giao diện.

  • Dễ dàng viết các trường hợp kiểm thử UI và tích hợp với các công cụ như JEST.

Lợi ích khi dùng React

  • ReactJS giúp cho việc viết các đoạn code Javascript sẽ trở nên dễ dàng hơn vì nó sử dụng một cú pháp đặc biệt đó chính là cú pháp JSX. Thông qua JSX cho phép nhúng code HTML và Javascript.

  • ReactJS cho phép nhà phát triển phá vỡ những cấu trúc UI phức tạp thành những component độc lập. Các nhà phát triển sẽ không phải lo lắng về tổng thể ứng dụng web, giờ đây có thể dễ dàng chia nhỏ các cấu trúc UI/UX phức tạp thành từng component đơn giản hơn.

  • Do sử dụng các component nên React có tính tái sử dụng cao

  • Đi kèm với ReactJS là rất nhiều các công cụ phát triển giúp cho việc debug code một cách dễ dàng hơn.

  • Một trong những ưu điểm nữa của ReactJS đó là sự thân thiện với SEO. Hầu như các JS Frameworks không thân thiện với các tìm kiếm mặc dù đã được cải thiện nhiều nhưng dưới sự hỗ trợ của các render dữ liệu trả về dưới dạng web page giúp cho SEO chuẩn hơn.

  • React cùng với React Native, Redux, Electro cùng với nhiều công cụ hữu ích khác giúp nhà phát triển xây dựng được đa dạng loại ứng dụng phù hợp với nhiều yêu cầu.

Hạn chế của React

  • React không phải một framework hoàn chỉnh mà chỉ là thư viện.

  • Component trong React sẽ rất nhiều và mất nhiều thời gian để hiểu với các trang web phức tạp.

  • Code sẽ trở nên phức tạp khi dùng template với JSX.

  • Khá khó cho người mới bắt đầu.

Sự khác biệt giữa class component và function component

Trước khi giới thiệu hooks ở phiên bản 16, các function component được gọi là stateless component và ít khi được dùng trong React. Sau khi hook ra đời, các function component giờ đã ngang hàng với class component.

  • Khai báo

Function component giống như một hàm thông thường trong JS, ta có thể tạo kiểu arrow function hoặc function:

function card(props){
    return(
        <div className="main-container">
            <h2>Title of the card</h2>
        </div>
    )
}

const card = (props) => {
    return(
        <div className="main-container">
            <h2>Title of the card</h2>
        </div>
    )
}

Class component sử dụng cú pháp tạo lớp của ES6

class Card extends React.Component{
    constructor(props){
        super(props);
    }
    render(){
        return(
            <div className="main-container">
                <h2>Title of the card</h2>
            </div>
        )
    }
}
  • Xử lý props

Ta thử render component dưới đây theo cả hai cách:

<Student Info name="Vivek" rollNumber="23" />

Trong function component, xử lý props rất thẳng thắn. Bất ký props nào cũng được xem như tham số của function component có thể xử lý trực tiếp:

function StudentInfo(props){
    return(
        <div className="main">
            <h2>{props.name}</h2>
            <h4>{props.rollNumber}</h4>
        </div>
    )
}

Với class component, props được xử lý bằng this:

class StudentInfo extends React.Component{
    constructor(props){
        super(props);
    }
    
    render(){
        return(
            <div className="main">
                <h2>{this.props.name}</h2>
                <h4>{this.props.rollNumber}</h4> 
            </div>
        )
    }
}
  • Xử lý state

Function component sử dụng hook để quản lý state. Hook hữu ích nhất là useState cho thiết lập state trong component.

function ClassRoom(props){
    let [studentsCount,setStudentsCount] = useState(0);
    
    const addStudent = () => {
        setStudentsCount(++studentsCount);
    }
        
    return(
        <div>
            <p>Number of students in class room: {studentsCount}</p>
            <button onClick={addStudent}>Add Student</button>
        </div>
    )
}

Ta không thể sử dụng hook bên trong class component, thế nên ta vẫn phải xử lý state bằng this trong class component.

class ClassRoom extends React.Component{
    constructor(props){
        super(props);

        this.state = {studentsCount : 0};
        this.addStudent = this.addStudent.bind(this);
    }
    
    addStudent(){
        this.setState((prevState)=>{
            return {studentsCount: prevState.studentsCount++}
        });
    }
    
    render(){
        return(
            <div>
                <p>Number of students in class room: {this.state.studentsCount}</p>
                <button onClick={this.addStudent}>Add Student</button>
            </div>
        )
    }
}

Virtual DOM

Virtual DOM là một khái niệm trong đó biểu diễn ảo của DOM thực được lưu giữ bên trong bộ nhớ và được đồng bộ hóa với DOM thực bởi một thư viện như ReactDOM

Tại sao cần Virtual DOM

Thao tác DOM là một phần không thể thiếu của bất kỳ ứng dụng web nào, nhưng thao tác DOM khá chậm khi so sánh với các thao tác khác trong JavaScript. Hiệu quả của ứng dụng bị ảnh hưởng khi một số thao tác DOM đang được thực hiện. Hầu hết các framework JavaScript cập nhật toàn bộ DOM ngay cả khi một phần nhỏ của DOM thay đổi.

Ví dụ: hãy xem xét một danh sách đang được hiển thị bên trong DOM. Nếu một trong các mục trong danh sách thay đổi, toàn bộ danh sách sẽ được hiển thị lại thay vì chỉ hiển thị mục đã được thay đổi/cập nhật. Đây được gọi là cập nhật không hiệu quả.

Để giải quyết vấn đề cập nhật không hiệu quả, team React đã đưa ra khái niệm virtual DOM

Đối với mỗi đối tượng DOM, có một đối tượng DOM ảo tương ứng (bản sao), có các thuộc tính giống nhau. Sự khác biệt chính giữa đối tượng DOM thực và đối tượng DOM ảo là bất kỳ thay đổi nào trong đối tượng DOM ảo sẽ không phản ánh trực tiếp trên màn hình. Hãy coi một đối tượng DOM ảo như một bản thiết kế của đối tượng DOM thực. Bất cứ khi nào một phần tử JSX được hiển thị, mọi đối tượng DOM ảo sẽ được cập nhật.

Lưu ý- Người ta có thể nghĩ rằng việc cập nhật mọi đối tượng DOM ảo có thể không hiệu quả, nhưng không phải vậy. Cập nhật DOM ảo nhanh hơn nhiều so với cập nhật DOM thực vì chúng tôi chỉ cập nhật bản thiết kế của DOM thực.

React sử dụng hai virtual DOM để hiển thị giao diện người dùng. Một cái được sử dụng để lưu trữ trạng thái hiện tại của các đối tượng và cái còn lại để lưu trữ trạng thái trước đó của các đối tượng. Bất cứ khi nào DOM ảo được cập nhật, React so sánh hai DOM ảo và biết về đối tượng DOM ảo nào đã được cập nhật. Sau khi biết đối tượng nào đã được cập nhật, React chỉ hiển thị các đối tượng đó bên trong DOM thực thay vì hiển thị DOM thực hoàn chỉnh. Bằng cách này, với việc sử dụng virtual DOM, react sẽ giải quyết được vấn đề cập nhật không hiệu quả.

Giải thích state và props

Props
State

Bất biến

Có thể thay đổi

Hiệu suất tốt hơn

Phạm vi cục bộ

Truyền được cho component khác

Truyền được giống như props

Có phương thức setState để đổi giá trị

Đổi trạng bất đồng bộ

Các kiểu side effect trong React component

Có hai kiểu side effect trong React.

  • Effect không có cleanup: Side effect này sẽ được sử dụng trong useEffect không hạn chế trình duyệt cập nhật màn hình. Nó cũng cải thiện khả năng phản hồi của một ứng dụng. Một vài ví dụ phổ biến là yêu cầu mạng, logging, chỉnh sửa DOM thủ công, v.v.

  • Effect có cleanup: Một số Hook effect sẽ yêu cầu cleanup sau khi cập nhật xong DOM. Ví dụ: nếu bạn muốn thiết lập đăng ký nguồn dữ liệu bên ngoài, nó yêu cầu dọn dẹp bộ nhớ, nếu không có thể xảy ra sự cố rò rỉ bộ nhớ. Có một thực tế là React sẽ thực hiện dọn dẹp bộ nhớ khi các component unmounting. Nhưng các effect sẽ chạy mỗi phương thức render() hơn là cho bất kỳ phương thức cụ thể nào. Do đó, chúng ta có thể nói rằng, trước khi thực thi các hiệu ứng thời gian, React cũng sẽ dọn dẹp các hiệu ứng từ lần hiển thị trước đó.

Các quy tắc sử dụng React Hooks

  • Chỉ có thể gọi hooks trong function component (không thể dùng trong class).

  • Chỉ có thể gọi ở cấp cao, không thể gọi trong hàm, vòng lặp hay điều kiện.

Các cách khác nhau để chỉnh style component

Inline Styling: ta có thể chỉnh style trực tiếp lên phần tử bằng cách dùng thuộc tính style. Nhớ giá trị của style luôn là đối tượng JavaScript:

class RandomComponent extends React.Component {
    render() {
        return (
            <div>
            <h3 style={{ color: "Yellow" }}>This is a heading</h3>
            <p style={{ fontSize: "32px" }}>This is a paragraph</p>
            </div>
        );
    }
}

Javascript Object: ta có thể tạo đối tượng JavaScript và tập mô tả thuộc tính style. Các đối tượng có thể dùng như giá trị của thuộc tính style.

class RandomComponent extends React.Component {
    paragraphStyles = {
        color: "Red",
        fontSize: "32px"
    };

    headingStyles = {
        color: "blue",
        fontSize: "48px"
    };

    render() {
        return (
            <div>
            <h3 style={this.headingStyles}>This is a heading</h3>
            <p style={this.paragraphStyles}>This is a paragraph</p>
            </div>
        );
    }
}

CSS Stylesheet: Ta sẽ tạo một file CSS riêng và viết tất cả style cho component trong file đó. Sau đó import nó vào file React.

import './RandomComponent.css';

class RandomComponent extends React.Component {
    render() {
        return (
            <div>
                <h3 className="heading">This is a heading</h3>
                <p className="paragraph">This is a paragraph</p>
            </div>
        );
    }
}

CSS Module: Tương tự như file CSS, nhưng ta sửa thành .module.css, với cách này tên lớp sẽ được mã hoá, đồng thời nó hỗ trợ kiểu viết tương tự sass.

.paragraph{
    color:"red";
    border:1px solid black;
}

Ta có thể import file vào component như sau:

import styles from  './styles.module.css';

class RandomComponent extends React.Component {
    render() {
        return (
            <div>
                <h3 className="heading">This is a heading</h3>
                <p className={styles.paragraph} >This is a paragraph</p>
            </div>
        );
    }
}

Các kỹ thuật tối ưu hiệu suất ứng dụng React

  • useMemo()

    • Là hook dùng cho caching CPU.

    • Đôi khi trong các ứng dụng web, các hàm đắt (tính toán nhiều, tốn bộ nhớ) được gọi liên túc do re-render đẫn đến tốc độ render chậm, hiệu suất kém.

    • useMemo() có thể sử dụng cho cache cám hàm như vậy. Bằng cách dùng useMemo() các hàm đó chỉ được gọi khi cần thiết.

  • React.PureComponent

    • Là class component cơ sở để kiểm tra state và props của một component để biết khi nào nó nên được cập nhật.

    • Thay vì dùng React.Component, ta có sử dụng React.PureComponent để giảm việc re-render không cần thiết.

  • Duy trì vị trí state

    • Đây là quá trình chuyển state đến nơi bạn nhất có thể.

    • Thỉnh thoảng ta có các state không cần thiết nằm trong component cha để gây khó đọc và bảo trì hơn, thậm chí là dẫn đến re-render không cần thiết.

    • Để tốt hơn, ta chuyển các state vô nghĩa ở component cha sang một component riêng biệt.

  • Lazy Loading

    • Đây là kỹ thuật dùng để giảm thời gian tải của ứng dụng React. Lazy loading giúp tối ưu hiệu suất ứng dụng web bằng cách chỉ tải khi cần thiết.

Các giai đoạn trong vòng đời component

Có 3 giai đoạn trong vòng đời component React.

  • Mounting: đề cập đến việc đưa phần tử vào DOM của trình duyệt. Vì React dùng virtual DOM, toàn bộ DOM của trình duyệt đã render sẽ không được làm mới. Bao gồm các phương thức trong giai đoạn này bao gồm: constructorcomponentDidMount.

  • Updating: Trong giai đoạn này, component sẽ được cập nhật khi có thay đổi state hoặc props của component. Các phương thức trong giai đoạn này: getDerivedStateFromProps, shouldComponentUpdate, render, và componentDidUpdate.

  • Unmounting: Ở giai đoạn cuối, component sẽ bị xoá khỏi DOM. Giai đoạn này sẽ có phương thức là componentWillUnmount.

Các phương thức trong vòng đời component

Trong vòng đời của React sẽ có các phương thức sẽ được gọi tự động ở các giai đoạn khác nhau trong vòng đời của component và do đó nó cung cấp khả năng kiểm soát tốt những gì xảy ra tại điểm được gọi. Nó cung cấp năng lực để kiểm soát và thao tác hiệu quả những gì diễn ra trong suốt vòng đời của component.

Ví dụ: nếu bạn đang phát triển ứng dụng YouTube, thì ứng dụng sẽ sử dụng mạng để đệm video và nó tiêu tốn pin (giả sử chỉ có hai mạng này). Sau khi phát video, nếu người dùng chuyển sang bất kỳ ứng dụng nào khác, thì bạn nên đảm bảo rằng các tài nguyên như mạng và pin đang được sử dụng hiệu quả nhất. Bạn có thể dừng hoặc tạm dừng tải video vào bộ đệm, do đó sẽ ngừng sử dụng pin và mạng khi người dùng chuyển sang ứng dụng khác sau khi phát video.

Vì vậy, chúng ta có thể nói rằng nhà phát triển sẽ có thể tạo ra một ứng dụng chất lượng với sự trợ giúp của các phương pháp vòng đời và nó cũng giúp các nhà phát triển đảm bảo lập kế hoạch những gì và làm như thế nào tại các thời điểm sinh, phát triển hoặc chết của giao diện người dùng.

Các phương thức trong vòng đời:

  • constructor(): phương thức được gọi khi component được tạo trước khi thực hiện bất kỳ hành động gì. Nó giúp tạo state và props.

  • getDerivedStateFromProps(): nó sẽ gọi trước khi phần tử được render vào DOM. Nó giúp thiết lập đối tượng state dựa trên props khởi tạo. Phương thức getDerivedStateFromProps sẽ có một state như đối số và trả về một đối tượng để thay đổi state. Nó sẽ là phương thức đầu tiên được gọi khi thực hiện cập nhật.

  • render(): phương thức này sẽ render HTML từ DOM với thay đổi mới nhất. Phương thức render sẽ được gọi mỗi khi có thay đổi đến component.

  • componentDidMount(): phương thức sẽ được gọi sau khi render component. Ta có thể chạy lệnh cần component đã được lưu trong DOM.

  • shouldComponentUpdate(): trả về giá trị boolean để quyết định xem có render hay không. Mặc định sẽ là True.

  • getSnapshotBeforeUpdate(): cung cáp truy cập cho props cung như state trước khi cập nhật. Nó dùng cho kiểm tra giá trị trước khi cập nhật.

  • componentDidUpdate(): được gọi sau khi cập nhật component trong DOM.

  • componentWillUnmount(): phương thức được gọi khi component bị xoá khỏi DOM.

Các kiểu Hooks trong React

  • Hook có sẵn: là các hooks được hỗ trợ sẵn trong React

    • Hook cơ bản:

      • useState(): là component dùng cho thiết lập và chỉnh sửa state.

      • useEffect(): cho phép thực hiện side effect trên function component.

      • useContext(): dùng cho tạo dữ liệu chung có thể truy cập trong hệ phân cấp component mà không cần truyền dữ liệu theo props từ trên xuống.

    • Hook nâng cao:

      • useReducer(): dùng cho các logic state phức tạp có nhiều giá trị con khi cập nhật state phụ thuộc vào state trước đó. Nó sẽ giúp tối ưu hoá hiệu suất component khi kích hoạt các bản cập nhật sâu hơn vì nó được truyền xuống thay vì callback.

      • useMemo(): điều này sẽ được sử dụng để tính toán lại giá trị đã ghi nhớ khi có sự thay đổi trong một trong các phần phụ thuộc. Việc tối ưu hóa này sẽ giúp tránh các tính toán tốn kém trên mỗi lần render.

      • useCallback(): hữu ích khi truyền callback vào component con đã tối ưu hoá và phụ thuộc vào tham chiếu để ngăn chặn các render không cần thiết.

      • useImperativeHandle(): cho phép chỉnh sửa thực thể sẽ được truyền cho đối tượng ref.

      • useDebugValue(): dùng cho hiển thị nhãn hoặc hook tuỳ chỉnh trong React DevTools.

      • useRef(): Nó sẽ cho phép tạo một tham chiếu đến phần tử DOM trực tiếp trong function component.

      • useLayoutEffect(): dùng cho đọc bố cục từ DOM và re-render bất đồng bộ.

  • Hook tuỳ chỉnh: là một hàm JavaScript. Hoạt động giống như một hàm thông thường với "use" phía trước để React hiểu đó là một hook tuỳ chỉnh và sẽ mô tả các hàm đặc biệt theo quy tắc của Hook. Hơn thế nữa, việc phát triển hook tuỳ chỉnh cho phép bạn trích xuất logic component trong các hàm có thể tái sử dụng

Sự khác biệt giữa lớp và React Hook

React Hook
Lớp

Được dùng cho function component

Được dùng cho class component

Không yêu cầu khai báo constructor

Cần constructor trong các class component

Không yêu cầu con trỏ this cho khai báo hay chỉnh sửa

Cần dùng this cho khai báo state (this.state) và chỉnh sửa (this.setState())

Dễ sử dụng với useState

Không có hàm cụ thể giúp ta truy cập state với setState tương ứng

Hữu dụng khi triển khai Redux và Context API

Quá trình thiết lập state lâu, nên class state sẽ không được ưu tiên

Hiệu suất của React Hook so với lớp

  • React Hooks sẽ tránh được rất nhiều chi phí như tạo thực thể, liên kết các sự kiện, .., có trong các lớp.

  • Các hook trong React sẽ dẫn đến các cây component nhỏ hơn vì chúng sẽ tránh được việc lồng nhau tồn tại trong HOC và sẽ render props dẫn đến việc React phải thực hiện ít công việc hơn

Hook có thay thế được lớp hoàn toàn

Mục đích của Hook là thay thế các chức năng được cung cấp bởi lớp. Nhưng có các phương thức mà Hook vẫn chưa thay thế được lớp:

  • getSnapshotBeforeUpdate()

  • getDerivedStateFromError()

  • componentDidCatch()

Axios

Axios là một promise dựa trên HTTP để tạo yêu cầu HTTP đến trình duyệt hay web server.

Tính năng

  • Interceptors: Truy cập cấu hình yêu cầu hoặc phản hồi (header, dữ liệu, v.v.) khi chúng gửi đến hoặc đi. Các hàm này có thể hoạt động như các cổng để kiểm tra cấu hình hoặc thêm dữ liệu.

  • Instances: Tạo thực thể có thể tái sử dụng như baseUrl, headers, và cấu hình khác đã thiết lập.

  • Defaults: Thiết lập giá trị chung cho header chung (như Authorization) với các yêu cầu. Nó hữu ích khi bạn cần xác thực đến server trên mọi yêu cầu.

Các phương thức thường dùng:

  • axios.request(config)

  • axios.get(url[, config])

  • axios.delete(url[, config])

  • axios.head(url[, config])

  • axios.options(url[, config])

  • axios.post(url[, data[, config]])

  • axios.put(url[, data[, config]])

  • axios.patch(url[, data[, config]])

Caching trong React

Ta có thể caching dữ liệu trong React bằng nhiều cách như:

  • Local Storage

  • Redux Store

  • Giữa dữ liệu giữa mounting và unmounting

Memoization là một kỹ thuật mà chúng ta sẽ sử dụng để đảm bảo rằng chúng ta không gặp phải API nếu chúng tôi đã thực hiện một số loại yêu cầu tìm nạp nó ở một số giai đoạn đầu tiên. Việc lưu trữ kết quả của các cuộc gọi tốn kém sẽ tiết kiệm thời gian tải cho người dùng, nhờ đó tăng hiệu suất tổng thể.

Nguồn tham khảo

Last updated