TỰ HỌC REACT.JS + REDUX [Fundamental]

Ngày đăng: 26/03/2021   -    Cập nhật: 05/08/2022
ReactJS là một thư viện JavaScript mạnh mẽ và phổ biến nhất trong Lập trình Front end. Nó không chỉ giúp phát triển Front end mà còn là nền tảng để bạn học tiếp lên React Native.


Đây cũng là công nghệ tiên phong trong lĩnh vực Front end và được sự hậu thuẫn mạnh mẽ từ Facebook cũng như cộng đồng lập trình viên trên toàn thế giới.


Chính vì thế, hiện nay có rất nhiều người mong muốn học ReactJS, chỉ học chuyên sâu về ngôn ngữ JavaScript để có thể:



"HỌC 1 LÀM 10"

 
Và nếu bạn muốn nhanh chóng nắm bắt và hiểu được cấu trúc của ReactJS cũng như sử dụng ReactJS để tạo ra một ứng dụng thực sự thì đây là Hướng dẫn Học ReactJS cơ bản mà chắc chắn bạn sẽ thích.
 

Tự học React JS


> Note: Hướng dẫn này được tạo ra cũng để giúp học viên ICT Hà Nội có nền tảng tốt hơn để nắm vững React. Nếu bạn muốn học thực tế, trực tiếp với Senior Front End DEV thì tham gia ngay KHÓA HỌC FRONT END (với React.js) này.


Mục lục:


I. Bắt đầu với ReactJS


 


II. React




III. React + Redux




Bây giờ, chúng ta sẽ bắt đầu ngay.


I. BẮT ĐẦU VỚI REACTJS



I.1. Lập trình Front end là gì?



Khi nhắc đến Lập trình Front end là chúng ta đang đề đến những gì người dùng cuối (cũng thường được gọi là "Client") có thể nhìn thấy.


Cơ bản nhất, lập trình Front end là việc viết code HTML, CSS và JavaScript.


Nếu như bạn đã lướt qua nhiều trang web, bạn sẽ thấy rằng một vài năm trở lại đây, các website đã thêm rất nhiều hiệu ứng, tính năng, chuyển động trên trang của họ nhằm lôi kéo khách hàng tương tác nhiều hơn, ở lại trên trang lâu hơn.


Nhưng điều này cũng dẫn đến một hệ quả là có quá nhiều việc cần phải làm và khi dự án trở nên lớn thì rất khó kiểm soát, quản lý chúng.


Cuối cùng, mấy ông "thần lười" quyết định là phải tìm một cách tốt hơn để quản lý tất cả code đó, vì thế họ đã tạo ra các thư viện hỗ trợ phát triển Front end để có thể có nhiều thời gian rảnh hơn.


Và React là một trong những thư viện đó, nổi bật và phổ biến nhất ở thời điểm hiện tại.


* React được tạo ra bởi Facebook và phát hành vào tháng 5 năm 2013 và đã được duy trì liên tục kể từ đó.



I.2. Tại sao chọn học React?



React là một trong những thư viện JavaScript phổ biến nhất cho các ứng dụng web front-end.


Dưới đây là một số ưu điểm của React:


Tốc độ cao



Để các trang web thực sự tương tác thì chúng cần cập nhật DOM mỗi khi có sự thay đổi. Quá trình này nói chung là chậm.


So với các thư viện JS khác, React sử dụng Virtual DOM (DOM ảo), cho phép chỉ cập nhật các phần của trang web đã thay đổi.


Điều này làm tăng tốc độ cập nhật đáng kể, vì các ứng dụng web hiện đại có thể chứa hàng nghìn phần tử. Nhưng các phần tử đã thay đổi thì cũng không thực sự nhiều lắm.


Dễ học / Dễ sử dụng


Nếu bạn đã học qua về JavaScript thì học React cũng khá đơn giản.


Hơn nữa, React cho phép các lập trình viên nhóm các code liên quan lại với nhau, do đó làm cho việc xây dựng và duy trì các ứng dụng quy mô lớn dễ dàng hơn nhiều.


Hậu thuẫn lớn / Cộng đồng mạnh


React có một cộng đồng lớn đáng kinh ngạc và nó là mã nguồn mở. Nó được duy trì bởi Facebook và cộng đồng.


Việc làm nhiều


Không thèm nói ngoa, chỉ cần bạn lướt lên các trang web tuyển dụng và gõ "React" thì số lượng việc chờ tuyển dụng phải nói là "Hàng đống".


Vue, Angular cũng là 2 thư viện JS cạnh tranh trực tiếp với React nhưng để so sánh về tỷ lệ tuyển dụng thì chỉ có hít khói React.


Thế nên, cứ việc làm nhiều thì mình học thôi.



I.3. Thêm React vào Website



React có thể được thêm vào một trang web mà không cần bất kỳ công cụ và cài đặt đặc biệt nào.


Đầu tiên, chúng ta cần thêm thư viện React dưới dạng hai thẻ script vào phần head của HTML (Ví dụ, file index.html):




<script src="https://unpkg.com/react@17/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
 


Tiếp theo, chúng ta cần thêm một tập lệnh khác, để cho phép sử dụng JSX.


JSX là một phần mở rộng cú pháp cho JavaScript và nó được khuyến khích sử dụng với React.


Đừng lo, bạn sẽ được tìm hiểu kỹ hơn về JSX trong các phần tiếp theo. Hiện tại, chúng ta chỉ cần thêm thẻ script sau vào bên dưới 2 thẻ trên:




<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
 


> Lưu ý: Cách thêm React vào trang web này chỉ phù hợp để tạo các bản demo nhỏ. Chúng ta sẽ học cách tạo một dự án React thực sự trong phần tiếp theo.


Với file index.html ở trên, ta thêm một vùng chứa vào phần body như sau:




<div id="container"></div>
 


Bây giờ, chúng ta sẽ code dòng code React đầu tiên!


Thử hiển thị một thông báo bằng thẻ h2 như sau:




    <script type="text/babel">
        ReactDOM.render(
            <h2>Hướng dẫn tự học React JS cơ bản</h2>,
            document.getElementById("container")
        );
    </script>
 


Kết quả chạy file index.html trên trình duyệt ta được:


Chương trình React JS đầu tiên


File index.html hoàn chỉnh:



<!DOCTYPE html>
<html>

<head>
    <meta charset="UTF-8" />
    <title>Học ReactJS cơ bản</title>
    <script src="https://unpkg.com/react@17/umd/react.development.js"></script>
    <script src="https://unpkg.com/react-dom@17/umd/react-dom.development.js"></script>
    <script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>

<body>
    <div id="container"></div>
    <script type="text/babel">
        ReactDOM.render(
            <h2>Hướng dẫn tự học React JS cơ bản</h2>,
            document.getElementById("container")
        );
    </script>
</body>

</html>
 


Ở đây, có 2 điều bạn cần nhớ đó là:


  • Chúng ta cần một vùng chứa (trống)
  • Chương trình React JS để render nội dung cần vào vùng chứa đó


OK, chương trình trên chỉ để Demo về React JS. Còn để thật sự tạo ra ứng dụng React JS thì ta cần đi sang phần tiếp theo


I.4. Tạo React App



Các ứng dụng web thực với React có quy mô chứa rất nhiều file, sử dụng các thư viện của bên thứ ba, v.v.


Do đó, cách tạo dự án React trong thực tế sẽ khác với ví dụ đơn giản ở trên.


Facebook đã tạo ra một công cụ tiện dụng có tên là Create React App giúp bạn dễ dàng thiết lập một dự án React chỉ với một lệnh đơn giản!


Để bắt đầu, hãy đảm bảo rằng bạn đã cài đặt phiên bản Node.js mới nhất đây trên máy của mình.


Bây giờ, chạy các lệnh sau trong Terminal để tạo và khởi động ứng dụng React, ví dụ ứng dụng có tên là my-app:


Đầu tiên, sử dụng lệnh cd để chuyển tới thư mục bạn dự định lưu trữ dự án, ví dụ:




cd desktop
 


Sau đó, gõ lệnh tạo dự án React có tên my-app như sau:



npx create-react-app my-app
 


Đợi tải và cài đặt các thứ cần thiết xong thì di chuyển vào thư mục dự án vừa tạo bằng lệnh:



cd my-app
 


Và thử khởi chạy dự án react với lệnh:



npm start
 



Video hướng dẫn Tạo và Chạy dự án React với VS Code


Như bạn thấy, một dự án React mẫu được tạo ra với cấu trúc chuẩn.

Cấu trúc thư mục dự án React


Thư mục public chứa các tệp liên quan đến cách ứng dụng sẽ hiển thị trên phía client, tệp quan trọng nhất trong số đó là index.html, là mẫu trang HTML của chúng ta:


Cấu trúc thư mục dự án React - Thư mục public


Thư mục src thì chứa tất cả các file JavaScript, CSS và hình ảnh. Từ đây, nội dung sẽ được biên dịch thành một gói và được đưa vào file index.html


Cấu trúc thư mục dự án React - Thư mục src


Trong trường hợp này, Webpack sẽ được sử dụng.


Webpack tạo một gói chứa nội dung của nhiều file thành một file duy nhất. Lúc này, chương trình chỉ cần tìm một file thay vì nhiều file như trước kia. Điều này cũng làm cho thời gian tải nhanh hơn.


Mặc dù có các file khác trong thư mục src đi kèm khi dự án được tạo ra, bạn chỉ cần lưu ý 2 file dưới đây:



  • index.js: Trong code của chúng ta, một phương thức có tên là ReactDOM.render() được sử dụng để tìm một phần tử có id = "container" trong HTML để thêm nội dung vào đó.

  • App.js: Tệp này là thành phần chính (main components) sẽ được hiển thị cho DOM, bao gồm hình ảnh, icon react mà chúng ta thấy trong kết quả.


Nào, bây giờ bạn đã biết cách tạo và chạy một dự án React. Hãy thử thay đổi đầu ra xem sao nhé.


Vào file src > index.js và thay đổi phương thức ReactDOM.render() thành như sau:




ReactDOM.render
  <h2>Học React đi nào!</h2>,
  document.getElementById("container")
);
 


Tiếp đến, mở Terminal và gõ lệnh:



npm start
 


Kết quả trên trình duyệt ta được:


Thử nghiệm thay đổi code React JS


Lưu ý: Trong file public/index.html mặc định sẽ có một vùng chứa (thẻ div) có id là root. Tuy nhiên, trong hướng dẫn này mình sẽ sử dụng id là container để rõ ý nghĩa bạn nhé.


I.5. Giới thiệu dự án React



Để tiếp tục, trong suốt hướng dẫn này chúng ta sẽ cùng đi từng bước hoàn thiện dự án Danh sách Sinh viên bằng cách sử dụng React.

Giới thiệu dự án React: Danh sách Sinh viên


Tất cả những khái niệm bạn học sẽ được triển khai ngay vào dự án và dần dần hoàn thiện, nó giúp bạn thấy tất cả những gì bạn học trông thực tế hơn.


Dự án Danh sách Sinh viên này cho phép bạn thêm mới tên sinh viên và hiển thị danh sách sinh viên ngay bên dưới.



II. REACT



Phần này chúng ta sẽ đi vào tìm hiểu những concept cốt lõi của React


II.1. JSX là gì?



Trong phần trước, chúng ta đã sử dụng đoạn code sau để hiển thị kết quả ra bằng React:



ReactDOM.render
  <h2>Học React JS đi nào!</h2>,
  document.getElementById("container")
);
 


Hãy nhìn vào tham số đầu tiên: <h2>Học React JS đi nào!</h2>


Như bạn thấy, nó không cần đặt trong dấu nháy đơn / kép gì cả. Nó không phải là một chuỗi thông thường.


Nó giống như HTML và hoạt động đúng trong JavaScript.


Điều này gọi là JSX, nó là một cú pháp mở rộng của JavaScript cho phép xây dựng các phần tử UI trong code JavaScript.


JSX thì không phải là yêu cầu bắt buộc trong React, nhưng nó là best practice.


Vì thế, để tránh rắc rối, tốt nhất là chúng ta nên sử dụng cú pháp JSX.


Hãy nhìn lại đoạn code này:




ReactDOM.render
  <h2>Học React JS</h2>,
  document.getElementById("container")
);
 


Phương thức này gọi là phương thức render(). Nó nhận và hai tham số:


  • Tham số đầu tiên là phần tử JSX
  • Tham số thứ hai là một vùng chứa (trống) (Đó là một câu lệnh thao tác với DOM mà thôi)


Khi phương thức render() này được gọi, nó sẽ render nội dung đè lên vùng chứa chỉ định.


Chúng ta có thể sử dụng bất kỳ biểu thức JavaScript nào bên trong JSX bằng cách sử dụng dấu ngoặc nhọn.




const name = "Ngọc Anh";
const el = <p>Xin chào, {name}</p>

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Như bạn thấy, JSX có thể được gán cho biến, và nó cũng có thể chứa các biểu thức JavaScript bằng cách đặt chúng trong dấu ngoặc nhọn { }


Như trong ví dụ này, chúng ta đặt biến name bên trong phần tử JSX để truyền giá trị khi render.


Ngoài ra, chúng ta có thể chỉ định các thuộc tính bằng cách sử dụng dấu ngoặc kép, giống như trong HTML:




<div id="name"></div>
 


Khi sử dụng biểu thức JavaScript làm giá trị thuộc tính, ta sử dụng dấu ngoặc nhọn như thế này:



<div id={student.id}></div>
 


> Lưu ý: React DOM sử dụng quy ước đặt tên thuộc tính camelCase thay vì tên thuộc tính HTML thông thường. Ví dụ, class trở thành className trong JSX.


II.2. Virtual DOM



Khi các biểu thức JSX được biên dịch, chúng được chuyển đổi thành các đối tượng JavaScript, đại diện cho các phần tử React.


Sau đó, React sử dụng các phần tử này để xây dựng DOM HTML tương ứng và hiển thị nó trong trình duyệt.


Hãy tạo một ứng dụng đếm số, nó tăng một biến counter lên 1 đơn vị mỗi giây và hiển thị nó trên trang trong thẻ p:




let counter = 0;

function show() {
  counter++;
  const el = <p>{counter}</p>;
  ReactDOM.render(
    el,
document.getElementById("container")
  );
}

setInterval(show1000);
 


Ở đây, chúng ta sử dụng hàm setInterval để gọi hàm show mỗi giây và hiển thị giá trị counter hiện tại lên trên trang.


Bạn thử chạy nó trên máy của bạn xem sao nhé.


Một trong những tính năng tuyệt vời của React là nó chỉ cập nhật những phần tử cần cập nhật.


Bạn có thể kiểm tra HTML trên trang của ví dụ trên và thấy rằng chỉ văn bản trong thẻ <p></p> được cập nhật mỗi giây còn toàn bộ code HTML khác là không đổi. (Không cần load lại trang)


Điều này cho phép các ứng dụng React nhanh hơn nhiều so với các ứng dụng được xây dựng bằng các công nghệ front-end khác.


Nhưng làm thế nào để React có thể làm điều đó?


Lý do chính là React sử dụng Virtual DOM, là một phiên bản đại diện, nhẹ hơn của DOM.


Khi một phần tử bị thay đổi, phần tử đó sẽ được cập nhật lần đầu tiên trong Virtual DOM. Quá trình đó diễn ra nhanh chóng, vì DOM ảo được biểu diễn bằng các đối tượng đơn giản.


Sau đó, React so sánh Virtual DOM với trạng thái (state) trước đó của nó và chỉ áp dụng các bản cập nhật DOM cần thiết để đưa DOM về trạng thái mong muốn.



II.3. Components là gì?



Components đề cập đến việc giúp bạn chia các thành phần của trang thành những phần có thể tái sử dụng.


Ví dụ, đây là phần đăng ký thông tin học bổng lập trình của NIIT - ICT Hà Nội.


Ví dụ Components trong React JS


Ở đây, chúng ta có thể chia chúng thành các phần và gọi là các components


Phần thông tin kêu gọi là một component, phần điền email và nhấn gửi là một components


Điều này giúp chúng ta tách biệt các mối quan tâm ra gọi là Speration of concerns



Trong React, có hai loại component mà bạn có thể sử dụng:


  • Functional components
  • Class components


Một Functional component là một hàm JavaScript đơn giản, ví dụ:



function Hello() {
  return <h2>Hello React!</h2>;
}
 


Đoạn code trên định nghĩa một component gọi là Hello và component này trả về một phần tử react đơn giản.


> Lưu ý: Tên của Function component bắt đầu bằng một chữ cái viết HOA. Đây là qui tắc. Nếu tên của một 
component là chữ thường, trình duyệt sẽ coi component của chúng ta giống như một phần tử HTML thông thường thay vì một Component.


Để hiển thị component trên, chúng ta cần tạo phần tử JSX tương ứng, ví dụ:




const el = <Hello />;
 


Bạn hãy ghi nhớ cú pháp <Hello />. Từ giờ, để tạo một phần tử React từ Functional component hay Class component, chúng ta sẽ sử dụng nó.


Bây giờ, việc còn lại là render nó vào phần tử container.




// Functional Components
function Hello() {
  return <h2>Hello React!</h2>;
}

const el = <Hello />;

// Render
ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả chạy trên trình duyệt, ta được:


Ví dụ Functional Components trong React JS



Loại compoents thứ hai mà chúng ta có thể sử dụng là Class components


Class components thường được sử dụng khi cần tạo thành phần có tương tác người dùng cao hơn như Forms và Animation...


Tất cả các Class components cần phải mở rộng lớp React.Component


Chúng ta có thể viết lại Functional components Hello của chúng ta dưới dạng một Class components như sau:




// Class Components
class Hello extends React.Component {
  render() {
    return <h2>Hello React!</h2>;
  }
}

const el = <Hello />;

// Render
ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Class components có một phương thức render() để cho biết trang sẽ render ra nội dung gì.


II.4. Props trong React



Trong React, Functional components có thể chấp nhận các đối số, tương tự như các hàm JavaScript. Các đối số này được gọi là props và đại diện cho một đối tượng.


Ví dụ: Chúng ta có thể sử dụng props trong để nhận đối số trong Functional components Hello của chúng ta như sau:




// Function Components
function Hello(props) {
  return <h2>Hello {props.name}!</h2>
}
 


Sau đó, chúng ta tạo phần tử với JSX và truyền giá trị cho name



const el = <Hello name = "Ngọc Anh" />;
 


Giá trị của thuộc tính name sẽ được truyền cho component khi render.


Bây giờ, thử gộp code lại, render và chạy chúng trên trình duyệt xem nhé:




// Function Components
function Hello(props) {
  return <h2>Hello {props.name}!</h2>
}

const el = <Hello name = "Ngọc Anh" />;

// Render
ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả:


Ví dụ sử dụng Props trong React JS


> Lưu ý: Một phần tử có thể có nhiều thuộc tính, các thuộc tính này sẽ được chuyển cho components bằng đối tượng props. Bạn có thể sử dụng bất kỳ tên nào cho các thuộc tính của mình.


Một component cũng có thể sử dụng components khác.


Ví dụ: Bây giờ, chúng ta muốn chào một lúc nhiều người, thay vì tạo lại một components hoàn toàn mới, chúng ta chỉ việc tạo một components sử dụng lại components Hello là được.




// Functional Components
function Hello(props) {
  return <h2>Hello {props.name}!</h2>
}

// Functional Components sử dụng Functional components khác
function BigHello() {
  return <div>
    <Hello name = "Ngọc Anh" />
    <Hello name = "Vũ Hà" />
    <Hello name = "Thu Hương" />
  </div>;
}

const el = <BigHello />;

// Render
ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả ta được:


Ví dụ Functional components sử dụng Functional components khác trong React JS


Nói chung, việc chia các component phức tạp thành các component đơn giản hơn giúp chúng ta dễ quản lý, dễ tái sử dụng hơn.


Props trong Functional components là vậy.


Còn sử dụng props trong Class components là như thế nào?


Khác với Functional components, trong Class components chúng ta muốn sử dụng props thì cần phải gọi this.props


Ví dụ: Cũng ví dụ Hello ban đầu nhưng bây giờ triển khai nó trong Class components




// Class Components
class Hello extends React.Component {
  render() {
    return <h2>Hello {this.props.name}!</h2>;
  }
}
 


Tiếp tục tạo phần tử JSX và render nội dung ra vùng chứa:



const el = <Hello name = "Ngọc Anh" />;

// Render
ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả ta được:


Ví dụ sử dụng props trong class components
 

Đến đây, bạn đã biết tạo components và truyền dữ liệu cho chúng.


Hãy thử tạo một danh sách sản phẩm.


Mỗi một sản phẩm đều có tên (name) và giá (price), ví dụ như thế này:




<Product name = "iPhone 12" price = "1200" />
 


Component Product sẽ render nội dung một thẻ div đơn giản với dữ liệu:



function Product(props) {
  return <div className = "product">
  <b>Tên:</b> {props.name} <br />
  <b>Giá:</b> {props.price}
  </div>;
}
 


Bây giờ, chúng ta có thể tạo thêm một component khác để sử dụng component Product như sau:



function MyApp() {
  return <div>
    <Product name = "iPhone 12" price = "1200" />
    <Product name = "Samsung Note 21" price = "1500" />
    <Product name = "VSmart Pro 5" price = "500" />
  </div>;
}
 


Cuối cùng, tạo phần tử JSX, render và chạy thử trên trình duyệt:



const el = <MyApp />;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả, mình đã thêm một chút CSS cho dễ nhìn:


Ví dụ tổng hợp sử dụng props trong React JS


Một điều quan trọng cần nhớ là props ở chế độ chỉ đọc, nghĩa là các components không thể sửa props của chúng.


Tuy nhiên, các ứng dụng tương tác thường cần thay đổi dữ liệu và các thành phần của trang. Do đó, nó sinh ra khái niệm state.



II.5. State trong React



Nhiều ứng dụng web cần các component của chúng để thay đổi dữ liệu của chúng, chẳng hạn như sau khi người dùng tương tác (nhấp vào nút, gửi biểu mẫu, v.v.).


Tuy nhiên, với props thì chúng ta không thể thay đổi nó.


Để cho phép các component quản lý và thay đổi dữ liệu của chúng, React cung cấp một tính năng gọi là state (trạng thái)


Statemột đối tượng được thêm vào như một thuộc tính trong các compnent của Class.


Ví dụ:




// Class Components
class Hello extends React.Component {

  // state
  state = {
    name: "NIIT - ICT Hà Nội"
  }

  render() {
    return <h1>Xin chào {this.state.name}.</h1>;
  }
}

const el = <Hello />;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả:


Ví dụ State trong React



Như bạn có thể thấy, state chỉ là một đối tượng đơn giản, chứa các cặp key:value


Tương tự như props, các giá trị có thể được truy cập bằng cách gọi this.state


Bây giờ, khi components hiển thị, state được khởi tạo với giá trị đã cho và sẽ có một tiêu đề có nội dung "Xin chào NIIT - ICT Hà Nội"



> Lưu ý: State có thể chứa nhiều cặp key:value bạn nhé. Các cặp key:value được phân tách bằng dấu phẩy ,


Như đã nói, chúng ta sử dụng state để mong muốn thay đổi dữ liệu.


Tuy nhiên, không nên để state có thể sửa đổi trực tiếp.


Mà thay vào đó, React cung cấp một phương thức có tên là setState(), có thể được sử dụng để sửa đổi state.


Ví dụ:




// Phương thức thay đổi state
this.setState({ 
  name: "Ngọc Anh ICT",
  age: 18
});
 


Bạn cần truyền một đối tượng có cặp key:value mới vào trong phương thức setState()


Nhưng vì sao chúng ta nên sử dụng setState(), thay vì chỉ thay đổi trực tiếp các giá trị của các thuộc tính đối tượng?


Câu trả lời cho thấy một trong những tính năng hữu ích nhất của React:



"Khi setState() được gọi, React sẽ tự động hiển thị lại component bị ảnh hưởng với state mới!"


Thông thường, sự thay đổi sate xảy ra trong các trình xử lý sự kiện (event handlers).


Để hiểu rõ cách state làm việc, chúng ta cùng tạo một ứng dụng đếm số lần click chuột.


Ứng dụng này cần hiển thị số lần click chuột mỗi lần khi người dùng click vào nút.


Để bắt đầu, chúng ta cần khởi tạo một component trong đó bao gồm state và nội dung sẽ hiển thị ở đầu ra:




class MouseClick extends React.Component {
  // State
  state = {
    click: 0
  }
 
  render() {
    return <div class = "mouseClick">
    <h1>{this.state.click}</h1>
    <button>CLICK VÀO ĐÂY!</button>
    </div>;
  }
}
 


> Note: Mình thêm className để thêm chút CSS. Bạn đừng để ý.


Ở đây, chúng ta đã khởi tạo trạng thái của state với giá trị là 0.


Bây giờ, chúng ta muốn khi click vào nút thì sẽ tăng giá trị của click trong state lên 1 đơn vị đúng không?


Vậy thì chúng ta sẽ cần:



  • 1 Phương thức thay đổi state
  • 1 Event handler để lắng nghe sự kiện click để gọi đến phương thức thay đổi state



class MouseClick extends React.Component {
  // State
  state = {
    click: 0
  }

  // Phương thức thay đổi state
  incermentClick = () => {
    this.setState({
      click: this.state.click + 1
    });
  }

  render() {
    return <div className = "mouseClick">
    <h1>{this.state.click}</h1>
    <button onClick={this.incermentClick}>CLICK VÀO ĐÂY!</button>
    </div>;
  }
}

const el = <MouseClick />;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả:


Ví dụ ứng dụng sử dụng state trong React JS


Mỗi khi chúng ta click vào nút, sự kiện onClick sẽ được kích hoạt và gọi đến phương thức incrementClick để thay đổi state.


Khi state thay đổi, React tự động kích hoạt render nội dung mới và hiển thị chúng.


> Lưu ý: Trình xử lý sự kiện sử dụng cú pháp camelCase và hàm xử lý được truyền trong dấu ngoặc nhọn { }.



Tóm lại, qua hai phần propsstate bạn cần nắm được:



  • Chúng ta sử dụng props để truyền dữ liệu cho các component.
  • Các component sử dụng state để quản lý dữ liệu của chúng.
  • props ở chế độ chỉ đọc và không thể sửa đổi.
  • State thì có thể được sửa đổi bởi component của nó bằng phương thức setState().
  • Phương thức setState() giúp ta thay đổi sate và kích hoạt hành động render lại nội dung đã thay đổi.



II.6. Hook là gì?



Phiên bản trước của React chỉ cho phép sử dụng trạng thái với Class components.


Tuy nhiên, trong phiên bản cập nhật gần đây của React, một tính năng mới được gọi là hooks đã được giới thiệu, hooks cho phép sử dụng state bên trong Functional components.


Để sử dụng tính năng hooks, chúng ta cần import nó:




import { useState } from 'react'
 


Trong đó:


  • useState trả về một cặp, giá trị state hiện tại và một function, cho phép bạn thay đổi state.
  • useState nhận một đối số, là giá trị ban đầu của state.


Ví dụ: Làm lại ví dụ Hello nhưng sử dụng tính năng hooks



function Hello() {
  const [namesetName] = useState("NIIT - ICT Hà Nội");

  return <h2>Tôi là {name}.</h2>;
}

const el = <Hello />;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả:


Ví dụ sử dụng tính năng Hooks trong React JS


Trong ví dụ trên, chúng ta tạo một biến trạng thái name và một hàm setName. Cú pháp dấu ngoặc vuông [ ] được gọi là array destructuring.


Nó gán biến name cho giá trị state hiện tại và phương thức setName cho hàm cho phép thay đổi sate.


Bạn có thể đặt tên cho các name và setName() bằng bất cứ thứ gì bạn thích.


> Lưu ý: Bạn có thể tạo nhiều biến tương tự name và các phương thức setName(). Chỉ cần sử dụng các câu lệnh riêng biệt cho từng biến bằng hook useState.



Bây giờ, hãy thử viết lại ứng dụng MouseClick bằng cách sử dụng tính năng Hooks xem sao nhé:



function MouseClick() {
  // State
  const [clicksetClick] = useState(0);

  // Thay đổi state
  function incrementClick() {
    setClick(click + 1);
  }

  return <div className = "mouseClick">
    <h2>{click}</h2>
    <button onClick={incrementClick}>CLICK VÀO ĐÂY!</button>
  </div>
}

const el = <MouseClick />;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả:


Ví dụ ứng dụng sử dụng tính năng Hooks trong React JS


Bạn có thể thấy, cách viết sử dụng tính năng Hooks này ngắn gọn hơn và dễ hiểu hơn đúng không?


Đó cũng chính là lý do vì sao họ lại tạo ra Hooks.


Đơn giản là muốn code ngắn gọn và dễ đọc, dễ hiểu hơn.


> Lưu ý: Chỉ có thể sử dụng Hooks bên trong Functional components



II.7. Lifecycle Method trong React



React cung cấp các Lifecycle method đặc biệt cho các Class components, các phương thức này được gọi khi:


  • Mounting: Khi components được render trên trang
  • Unmounting: Khi components được xóa khỏi trang

 


Phương thức componentDidMount() được gọi khi một components được render trên trang.


Ví dụ: Chúng ta cũng có thể sử dụng componentDidMount() trong ứng dụng MouseClick của mình để thiết lập giá trị ban đầu của click:

 


class MouseClick extends React.Component {
  state = {
      click: 0
  }
  
  incrementClick = () => {
    this.setState({
      click: this.state.click + 1
    });
  }

  // Phương thức được gọi khi
  // nội dung được render trên trang
  componentDidMount() {
    this.setState({
      click: 15
    });
  }

  render() {
    return <div className="mouseClick">
      <h2>{this.state.click}</h2>
      <button onClick={this.incrementClick}>CLICK VÀO ĐÂY!</button>
    </div>;
  }
}

const el = <MouseClick/>;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 


Kết quả: 

 

Vi Du Su Dung Phuong Thuc componentDidMount Trong React JS Tu Hoc React JS



> Lưu ý: Tương tự, phương thức componentWillUnmount() được gọi ngay trước khi thành phần bị xóa khỏi DOM. Nó có thể được sử dụng để giải phóng tài nguyên do components chiếm dụng



Tương tự, chúng ta cũng có phương thức được kích hoạt component được thay đổi trong DOM là componentDidUpdate()


Ví dụ: Cũng sử dụng ví dụ trên, chúng ta sử dụng phương thức componentDidUpdate() để log số click vào trong console


 


class MouseClick extends React.Component {
  state = {
      click: 0
  }

  incrementClick = () => {
    this.setState({
      click: this.state.click + 1
    });
  }

  // Phương thức được gọi khi
  // nội dung được render trên trang
  componentDidUpdate() {
    console.log("Click: " + this.state.click);
  }

  render() {
    return <div className="mouseClick">
      <h2>{this.state.click}</h2>
      <button onClick={this.incrementClick}>CLICK VÀO ĐÂY!</button>
    </div>;
  }
}

const el = <MouseClick/>;

ReactDOM.render(
  el,
  document.getElementById("container")
);
 



Kết quả ta được:
 


Ví dụ sử dụng phương thức componentDidUpdate trong React JS



Lifecycle Method chỉ có sẵn trong Class components.


Tuy nhiên, Hooks cung cấp một phương thức đặc biệt là useEffect() để giúp Lifecycle Methods có thể sử dụng trong Functional components.


Ví dụ: Chúng ta làm lại ứng dụng MouseClick sử dụng useState()useEffect() như sau:


 


function MouseClick() {
  const [clicksetClick] = useState(0);

  // Gọi khi nội dung được render
  useEffect(() => {
    console.log("Click: "click);
  });

  // Hàm xử lý đếm số click
  function incrementClick() {
    setClick(click + 1);
  }

  return <div className = "mouseClick">
    <h2>{click}</h2>
    <button onClick={incrementClick}>CLICK VÀO ĐÂY!</button>
  </div>
}
 


Khi chạy chương trình, ngay từ lần đầu tiên useEffect() đã được gọi.


Và sau mỗi lần click nó lại được gọi.


Bởi vì theo mặc định, useEffect() chạy cả hai.


Nếu bạn muốn gọi đến nó sau khi component thay đổi thì cung cấp cho nó một tham số thứ 2 như sau:


 


useEffect(() => {
  // Làm gì đó
}, [click]);
 


Để bắt chước componentWillUnMount(), useEffect() có thể return một hàm như sau:

 


useEffect(() => {
  // Làm gì đó
  
  return () => {
    // dọn dẹp
  }; 
});
 



Như vậy, chúng ta chỉ cần sử dụng useEffect() là đã có được nhiều chức năng trong một component.


Và, để sử dụng useEffect() thì trước tiên bạn cần phải nhớ import nó:


 


import {useStateuseEffectfrom 'react';
 


 

II.8. Handing Events



Việc xử lý các sự kiện trong React rất giống với việc xử lý các sự kiện trong DOM.


Sự khác biệt duy nhất là tên sự kiện trong React sử dụng cú pháp camelCase và trình xử lý sự kiện cần được truyền trong dấu ngoặc nhọn { }.


Giống như bạn đã nhìn thấy trong các ví dụ trên:




<button onClick={incrementClick}>
CLICK VÀO ĐÂY!
</button>
 


Như thế này có nghĩa là, nút này đang lắng nghe sự kiện onClick. Khi sự kiện này kích hoạt, nó gọi đến trình xử lý sự kiện là incrementClick.


Để hiểu thêm về cách xử lý sự kiện, chúng ta cùng đi làm một ứng dụng chuyển đổi tiền tệ từ Đô la sang tiền Việt nhé.


Để đơn giản, ứng dụng này yêu cầu một thẻ input. Sau khi người dùng nhập số tiền đô thì sẽ chuyển đổi ngay sang tiền việt và hiển thị luôn.


 


function DolaToVND() {
  const [dolasetDola] = useState(0);

  function handleChange(e) {
    setDola(e.target.value);
  }

  // Hàm xử lý sự kiện chuyển đổi
  function toVnd(dola) {
    // Chuyển đổi Đô la sang tiền Việ
    // và thêm dấu phân tách hàng nghìn
    let vnd = Intl.NumberFormat().format(dola * 23075);
    
    return vnd;
  }

  return <div className = "doLaToVND">
   <input type="text" value = {dola} onChange = {handleChange} />
   <p> {dola} Đô la = {toVnd(dola)} VNĐ</p>
  </div>;
}

const el = <DolaToVND/>;

ReactDOM.render(el
  document.getElementById("container")
);
 


 

Kết quả, khi chạy chương trình ta được:

 

Ví dụ ứng dụng chuyển đổi tiền tệ đơn giản trong React JS


 

> Lưu ý: Giá trị của text field được truy cập thông qua đối tượng e, đại diện cho sự kiện React. Nó được truyền cho hàm xử lý sự kiện như một đối số và có thể được sử dụng để truy cập đối tượng sự kiện.


OK, vậy còn trong trường hợp xử lý cả form có nhiều sự kiện thì sao?


Để hiểu về các xử lý form, chúng ta cùng thực hiện một ví dụ khác: Một form có trường input và một nút submit. Khi nhập số vào input và nhấn submit thì cộng vào tích lũy và hiển thị ra tổng ở bên dưới


 


function AddForm() {
  const [numsetNum] = useState(0);
  const [sumsetSum] = useState(0);

  // Hàm xử lý khi người dùng
  // nhập vào input
  function handleChange(e) {
    setNum(e.target.value);
  }

  // Hàm xử lý khi người dùng
  // nhấn nút Cộng (submit)
  function handleSubmit(e) {
    setSum(sum + Number(num));
    e.preventDefault();
  }

  return <form onSubmit={handleSubmit} className="formSubmit">
    <input type="number" value={num} onChange={handleChange} />
    <input type="submit" value="Cộng" />
    <h3> Tổng là {sum} </h3>
  </form>;
}

const el = <AddForm />;

ReactDOM.render(el
  document.getElementById("container")
);
 



Khi người dùng nhập vào input thì sự kiện handleChange được kích hoạt và thiết lập giá trị cho biến num.


Tiếp đó, khi người dùng click vào nút Cộng thì sự kiện handleSubmit được kích hoạt và cộng num vào biến sum.


Kết quả khi chạy chương trình:


 

Ví dụ xử lý Form trong React JS
 

> Lưu ý:  Câu lệnh e.preventDefault(); là câu lệnh ngăn hành vi mặc định của Form. Bởi vì theo mặc định, trang được tải lại khi Submit. Tuy nhiên, trong React thì không cần hành vi mặc định này, thế nên chúng ta cần phải gọi preventDefault().

 

II.9. Cách render một danh sách



Trong lập trình web, có rất nhiều phần tử cần lặp lại với cùng DOM, nhưng khác dữ liệu, ví dụ như một danh sách.


Giả sử, chúng ta có một mảng.


 


const arrSV = ["Ngọc Anh""Vũ Hà""Thu Hương"];
 


Bây giờ, chúng ta muốn hiển thị mỗi phần tử vào một thẻ <li> và kết xuất trên trình duyệt.


Trong trường hợp này, chúng ta có thể tạo một components và truyền dữ liệu vào cho chúng thông qua props, sử dụng thuộc tính data:


 


<SinhViens data={arrSV} />
 



Bây giờ, chúng ta sẽ viết logic cho nó như sau:

 


function SinhViens(props) {
  const danhSachSV props.data;

  const sinhViens = danhSachSV.map((svindex=>
    <li key={index}>{sv}</li>
  );

  return <ul>{sinhViens}</ul>;
}

const arrSV = ["Ngọc Anh""Vũ Hà""Thu Hương"];

const el = <SinhViens data={arrSV} />;

ReactDOM.render(el
  document.getElementById("container")
);
 



Ở đây, chúng ta lấy mảng đầu vào từ props, lặp qua mảng bằng cách sử dụng phương thức map trong JavaScript và trả về một phần tử <li> cho mỗi mục.


Mảng kết quả được lưu trữ trong biến sinhViens.


Sau đó, component trả về mảng sinhViens bên trong thẻ ul và được render trên trang.


Kết quả ta được như sau:


 

Ví dụ hiển thị danh sách bằng React JS



Ngoài ra, bạn để ý, mỗi phần tử trong danh sách cần có một thuộc tính key


Các key hoạt động như một cách để định danh từng phần tử (đây là các ID từ dữ liệu của bạn hoặc có thể là các chỉ mục được tạo tự động)


Các key rất quan trọng, vì chúng giúp React hiểu và theo dõi xem những phần tử nào đã thay đổi, được thêm vào hoặc bị xóa để cập nhật dữ liệu.


 

II.10. Dự án Danh sách Sinh viên sử dụng React



Bây giờ, bạn đã biết cách tạo ra components và truyền dữ liệu sử dụng props và quản lý chúng với state. Hãy cùng vận dụng những thứ đó để làm dự án đơn giản Danh sách Sinh viên


Dự án Danh sách Sinh viên của chúng ta sẽ cho phép xem tên các sinh viên và thêm sinh viên mới vào danh sách đó.



Giới thiệu dự án React: Danh sách Sinh viên


Nhìn vào hình trên ta thấy, chúng ta cần xây dựng 2 components:


  • ThemSinhVien: Một form với một input (nhập tên) và một nút (thêm sinh viên)
  • SinhViens: Một danh sách sinh viên


Trước tiên, chúng ta cùng tạo components ThemSinhVien



function ThemSinhVien(props) {
  const [ tensetTen ] = useState("");

  // Hàm xử lý khi 
  // người dùng điền tên sinh viên
  function handleChange(e) {
    setTen(e.target.value);
  }

  // Hàm xử lý khi
  // người dùng nhấn Thêm sinh viên (submit)
  function handleSubmit(e) {
    e.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text"
      placeholder="Tên sinh viên"
      onChange={handleChange}
      value={ten} />
      <button type="submit">Thêm sinh viên</button>
    </form>
  );
}
 


Và một components SinhViens nhận một mảng đầu vào và hiển thị danh sách sinh viên:



function SinhViens(props) {
  // Lấy dữ liệu ban đầu
  const danhSachSV = props.data;

  // Đặt tên từng sinh viên vào trong thẻ li
  const sinhViens = danhSachSV.map((svindex=>
    <li key={index}>{sv}</li>
  );

  return <ul>{sinhViens}</ul>;
}
 


Bây giờ, chúng ta có thể hiển thị các component với dữ liệu ban đầu lên trên trình duyệt như sau:



const arrSV = ["Ngọc Anh""Vũ Hà""Thu Hương"];

const el = (
  <div>
    <ThemSinhVien />
    <SinhViens data={arrSV} />
  </div>
);

ReactDOM.render(
  el
  document.getElementById("container")
);
 


Kết quả trên trình duyệt ta được:


Dự án React: Danh sách Sinh viên (1)



Tuy nhiên, lúc này hành động Thêm sinh viên chưa hoạt động, vì chúng ta chưa viết logic trong hàm handleSubmit.


Hiện tại, ThemSinhVien đang giữ state của nó một cách độc lập.


Vậy thì làm cách nào để chúng ta  có thể thêm một sinh viên mới vào SinhViens của mình, khi nhấn Thêm sinh viên?


Để thực hiện điều đó, chúng ta cần chia sẻ state giữa các components.


Chúng ta có thể làm điều đó bằng cách nâng state lên component cha. Điều này có nghĩa là component cha sẽ giữ dữ liệu cần được chia sẻ giữa các component.


Hãy tạo một components cha có tên là DSSinhVien, sau đó nhét ThemSinhVienSinhViens làm components con và giữ arrSV ở state của nó:




function DSSinhVien(props) {
  const [duLieusetDuLieu] = useState(props.data);
 
  return (
    <div>
      <ThemSinhVien />
      <SinhViens data={duLieu} />
    </div>
  );
}
 


Đó, bây giờ components cha đang nhận dữ liệu đầu vào và lưu vào state của nó (thông qua props).


Sau đó nó truyền xuống components con. Tại thời điểm này, Components con lấy được danh sách sinh viên từ cha, là biến duLieu)



> Lưu ý: React sử dụng luồng dữ liệu đơn hướng (truyền từ trên xuống dưới) không thể truyền ngược lại


Tiếp tục, chúng ta cần tạo một hàm để thêm tên sinh viên mới vào mảng state hiện tại.



function DSSinhVien(props) {
  const [duLieusetDuLieu] = useState(props.data);

  function themSVMoi(ten) {
    setDuLieu([...duLieuten]);
  }
....
}
 


Nhưng làm thế nào chúng ta sẽ gọi hàm này từ components ThemSinhVien của chúng ta?


Giống như chúng ta truyền dữ liệu bằng cách sử dụng props, React cho phép chúng ta truyền các tham chiếu hàm!




function DSSinhVien(props) {
  const [duLieusetDuLieu] = useState(props.data);

  function themSVMoi(ten) {
    setDuLieu([...duLieuten]);
  }

  return (
    <div>
      <ThemSinhVien handleSubmit={themSVMoi}/>
      <SinhViens data={duLieu} />
    </div>
  );
}
 


Tương tự như việc chuyển danh sách liên hệ sang components SinhViens của chúng ta, chúng ta đã chuyển hàm themSVMoi() cho ThemSinhVien của chúng ta bằng cách sử dụng một prop có tên là handleSubmit.


Bây giờ, SinhViens của chúng tôi có thể gọi hàm handleSubmit mà nó đã nhận được khi gửi biểu mẫu, để thêm một sinh viên mới vào danh sách:


Bây giờ, components ThemSinhVien sẽ trở thành như thế này:




function ThemSinhVien(props) {
  const [ tensetTen ] = useState("");

  // Hàm xử lý khi 
  // người dùng điền tên sinh viên
  function handleChange(e) {
    setTen(e.target.value);
  }

  // Hàm xử lý khi
  // người dùng nhấn Thêm sinh viên (submit)
  function handleSubmit(e) {
    props.handleSubmit(ten);
    setTen('');
    e.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text"
      placeholder="Tên sinh viên"
      onChange={handleChange}
      value={ten} />
      <button type="submit">Thêm sinh viên</button>
    </form>
  );
}
 


Chúng ta cũng xóa giá trị của trường văn bản, ngay sau khi nhấn Thêm sinh viên bằng cách sử dụng setTen('').


Đây là code của toàn bộ chương trình này:




function ThemSinhVien(props) {
  const [ tensetTen ] = useState("");

  // Hàm xử lý khi 
  // người dùng điền tên sinh viên
  function handleChange(e) {
    setTen(e.target.value);
  }

  // Hàm xử lý khi
  // người dùng nhấn Thêm sinh viên (submit)
  function handleSubmit(e) {
    if (ten !== "") {
      props.handleSubmit(ten);
      setTen('');
    }
    e.preventDefault();
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="text"
      placeholder="Tên sinh viên"
      onChange={handleChange}
      value={ten} />
      <button type="submit">Thêm sinh viên</button>
    </form>
  );
}

function SinhViens(props) {
  // Lấy dữ liệu ban đầu
  const danhSachSV = props.data;

  // Đặt tên từng sinh viên vào trong thẻ li
  const sinhViens = danhSachSV.map((svindex=>
    <li key={index}>{sv}</li>
  );

  return <ul>{sinhViens}</ul>;
}

function DSSinhVien(props) {
  const [duLieusetDuLieu] = useState(props.data);

  function themSVMoi(ten) {
    setDuLieu([...duLieuten]);
  }

  return (
    <div>
      <ThemSinhVien handleSubmit={themSVMoi}/>
      <SinhViens data={duLieu} />
    </div>
  );
}

const arrSV = ["Ngọc Anh""Vũ Hà""Thu Hương"];

const el = <DSSinhVien data={arrSV} />

ReactDOM.render(
  el
  document.getElementById("container")
);
 


Kết quả chạy chương trình ta đã có thể thêm mới sinh viên và thấy nó hiển thị ở danh sách bên dưới.


Dự án React: Danh sách Sinh viên (2)
 

Một điểm quan trọng rút ra từ bài học này là các props có thể được sử dụng để truyền lại không chỉ state, mà còn cả các hàm có thể thao túng state.


Bằng cách này, chúng ta có thể lưu trữ state trong components cha và cho phép các components con của nó sử dụng và thao tác với state đó.


Bây giờ, khi ứng dụng của chúng ta đã chạy được, bạn có thể thêm một số CSS cho ứng dụng đẹp hơn.


> Bài tập: Cố gắng sửa đổi code và thêm các thuộc tính vào ứng dụng của chúng ta, chẳng hạn như mã sinh viên, năm sinh, số điện thoại...


 
CHÚC MỪNG BẠN!


Đến đây coi như bạn đã hiểu về các concept cốt lõi của React và hiểu cách sử dụng chúng để xây dựng các components.


Có vẻ như quá nhiều việc phải làm cho một ứng dụng nho nhỏ thế này nhỉ? :D.


Đúng vậy, có nhiều việc phải làm. Nhưng concept của nó mang lại hiệu quả đối với các dự án phức tạp.


Tuy nhiên, thực sự thì truyền sate qua các component như thế này khá rắc rối, khó hiểu.


Chính vì thế, React cung cấp cho chúng ta một giải pháp để đơn giản hóa đi các công việc trên. Đó chính là Redux


 

III. REACT VÀ REDUX


 

III.1. Giới thiệu Redux



Redux được tạo ra để giúp việc quản lý sate có thể dự đoán được, cung cấp một vùng chứa state duy nhất và các quy tắc nghiêm ngặt về cách có thể thay đổi state.


Redux là một thư viện JavaScript nhỏ và có thể được sử dụng với bất kỳ front-end framework nào, chẳng hạn như React, Angular, jQuery.


Nó sử dụng mô hình "single source of truth".


Nói tóm lại, single source of truth chỉ đề cập đến việc chuyển vị trí state và tất cả logic liên quan ra bên ngoài ứng dụng, cho phép BẤT KỲ components nào truy cập vào dữ liệu mà nó cần.


Có một vùng chứa state duy nhất giúp quản lý sate của bạn dễ dàng hơn, vì bạn có thể truy cập và thay đổi dữ liệu từ bất kỳ components nào mà không cần phải truyền dữ liệu nhiều cấp như trước.


 

III.2. Các concept cốt lõi của Redux



Hãy cùng xem xét các concept cốt lõi của Redux.


Store


Trong Redux, state được lưu trữ dưới dạng một đối tượng đơn giản, được gọi là store.


Và chỉ nên có một store duy nhất trong một ứng dụng.


Ví dụ, một store có thể trông như thế này:




{
  students: [{
    name: "Ngọc Anh"
  }, {
    name: "Vũ Hà"
  }],
  toggletrue
}
 


Tuy nhiên, để thay đổi state, bạn không thể thay đổi trạng thái trực tiếp. Thay vào đó, bạn cần gửi một hành động (action).


Action và Reducers


Một action chỉ là một đối tượng JavaScript đơn thuần:




  type"ADD_STUDENT"
  name"Thu Hương"
}
 


Đoạn code trên xác định một action (hành động) với typeADD_STUDENT và một thuộc tính name.


Một action mô tả rõ ràng lý do tại sao lại thay đổi sate và có thể được thực hiện từ bất kỳ đâu trong ứng dụng của bạn.


Tại thời điểm này, chúng ta chỉ có một store, bao gồm dữ liệu state của chúng ta và một đối tượng, bao gồm một số dữ liệu cần được thay đổi trong trạng thái. Vì vậy, làm thế nào để chúng ta thực sự thực hiện thay đổi?


Để liên kết storeaction với nhau, chúng ta cần viết một hàm, được gọi là reducer


Nó nhận stateaction làm đối số và trả về state tiếp theo của ứng dụng.




function studentsApp(stateaction) {
  if (action.type === "ADD_STUDENT") {
    return [ ...state,  action.name ]
  } else {
    return state
  }
}
 


Đoạn code trên định nghĩa một hàm studentsApp đơn giản (hàm reducer) để kiểm tra action, nếu đúng thì trả về state mới.


Các khái niệm này về cơ bản là ý tưởng của Redux:



"Giữ state trong một chỗ (store), xác định các hành động (action) để mô tả những gì cần thay đổi trong store và viết các hàm (reducer) để xử lý các action đó."


> Lưu ý: Chỗ này chưa có cú pháp React đặc biệt nào cả, hoàn toàn là JavaScript thuần túy đấy nhé.


Tóm lại, bạn cần phải nhớ 3 concept chính:



  • Toàn bộ state của ứng dụng được lưu trữ trong một store duy nhất
  • Bạn chỉ có thể thay đổi state thông qua action. Action thì chứa thông tin mà bạn muốn thay đổi
  • Reducer xử lý các action và trả về state tiếp theo của ứng dụng. Reducers cần phải thuần túy, nghĩa là chúng không thể sửa đổi state, chúng cần trả về một đối tượng state mới.



Bây giờ, chúng sẽ đi vào từng phần

 

III.3. Action



Action có thể được xem như là thông tin được gửi đến store.


Các action được thể hiện bằng đối tượng JavaScript đơn giản và bắt buộc phải có thuộc tính type:




  type"ADD_STUDENT"
  name"Thu Hương"
}
 



Trong ví dụ trên, chúng ta xác định một hành động với kiểu ADD_STUDENT và cung cấp cho nó một thuộc tính name làm payload của nó.


> Lưu ý: Tên giá trị của type phải được viết HOA và phân tách bằng dấu gạch dưới _. Đây còn được gọi là SNAKE_CASE. Nói chung nó là quy tắc, bạn làm theo là được.


Ngoài ra, thuộc tính khác xác định dữ liệu trong action thì bạn viết kiểu gì cũng được.


Ví dụ: Bạn có thể gọi nó là payload và cung cấp cho nó một đối tượng với dữ liệu


 


  type"ADD_STUDENT"
  payload: {
    name"Thu Hương"
  } 
}
 



> Lưu ý: Bạn nên chuyển càng ít dữ liệu trong mỗi action càng tốt. Nó giúp action đơn giản và dễ đọc.


Và để sử dụng cùng một action với các dữ liệu (payload) khác nhau, cũng như tạo code có thể tái sử dụng, chúng ta có thể tạo Action creators.

 


// Action creators
function addStudent(student) {
  return {
    type: 'ADD_STUDENT',
    payload: student
  }
}
 


Action creators đơn giản là hàm trả về các action.


Bây giờ, chúng ta có thể sử dụng action creators để tạo nhiều sinh viên mới bằng cách chuyển cho nó dữ liệu tương ứng.

 

III.4. Reducers



Reducer là các hàm xử lý các action.


Hàm lấy trạng thái hiện tại và hành động làm tham số của nó và trả về trạng thái mới.


Một reducer có thể xử lý nhiều action, do đó, thường chúng ta sử dụng câu lệnh switch bên trong nó:




function studentsApp(stateaction) {
  // Câu lệnh switch
  // Kiểm tra type và trả về sate mới
  switch (action.type) {
    case "ADD_STUDENT":
      return [ ...state,  action.name ]
    default:
      // Không có case nào khớp
      // thì trả về state hiện tại
      return state
}
 


Trong hàm reducer trên, nó nhận vào state hiện tại và action. Sau đó sử dụng switch để kiểm tra xem case nào phù hợp và trả về sate mới.


Nếu không có case nào phù hợp thì nó trả về state hiện tại.




Hãy nhớ là, reducer phải là một hàm thuần túy, có nghĩa là nó không thể sửa đổi state hiện tại. Thay vào đó, nó phải trả về một đối tượng state mới.


Nếu bạn có nhiều thực thể (tức là người dùng, sản phẩm, hóa đơn, đơn đặt hàng, v.v.), bạn nên chia chúng thành nhiều chức năng rút gọn để phân tách các mối quan tâm.


Redux cung cấp cho chúng ta một phương thức mà chúng ta có thể sử dụng được gọi là connectReducers.


Nó cho phép chúng ta sử dụng nhiều reducer để khi một action được gửi đi, action đó sẽ được chạy qua tất cả các reducer thay vì chỉ một reducer.




const studentsApp = combineReducers({
  addStudent,
  addAge
})
 


Bây giờ, studentsApp của chúng ta đã đang kết hợp hai reducer thành một.


> Lưu ý: Tốt nhất là chỉ cho mỗi reducer quản lý một phần state. Đây được gọi là reducer composition và là một mô hình cơ bản để xây dựng các ứng dụng Redux.



Ok, bạn đã hiểu qua các khái niệm cốt lõi của Redux, bây giờ chúng ta bắt đầu đi vào...


III.5. Lập trình React + Redux



Việc đầu tiên chúng ta cần làm đó là, cài đặt Redux.


Vào trong dự án của chúng ta, mở Terminal lên và gõ lệnh:




npm install redux
 



Câu lệnh trên sẽ cài đặt thư viện Redux.


Tuy nhiên, bản thân Redux chỉ là một thư viện nhỏ, có thể được sử dụng với các công nghệ khác nhau.


Để sử dụng nó với React, chúng ta cần cài đặt một thư viện nữa, có tên là react-redux:




npm install react-redux
 


Thư viện react-redux liên kết React với Redux, cho phép các React components đọc dữ liệu từ Redux store và gửi các action tới store để cập nhật dữ liệu.


Bây giờ, chúng ta sẽ làm lại ứng dụng MouseClick bằng cách kết hợp React với Redux.


Đầu tiên, ta cần tạo một action và một reducer tương ứng.


Action:




function incrementClick(click) {
  return { 
    type: "CLICK_BUTTON"
    click: click
  }
}
 


Đoạn code trên khai báo một action creator có tên là incrementClick(), hàm này trả về một hành động có typeCLICK_BUTTON và payload tương ứng.


Reducer:




const initialState = {
  click: 0
};

function reducer(state = initialStateaction) {
  switch(action.type) {
    case "CLICK_BUTTON":
      return { click: state.click + action.click };
    default:
      return state;
  }
}
 


Đoạn mã trên định nghĩa một hàm reducer, hàm này trả về state mới dựa trên action đã cho.


Kiểm tra nếu type đúng là CLICK_BUTTON thì trả về giá trị click = giá trị click hiện tại + giá trị click được truyền trong action.


Bây giờ, chúng ta tạo tiếp store để lưu trữ state tập trung


Để tạo store, chúng ta gọi hàm createStore(), hàm này lấy reducer làm tham số của nó:




const store = createStore(reducer);
 



Nhưng làm thế nào để chúng ta truyền store cho các components?


Để làm điều đấy, chúng ta sử dụng đến phần tử <Provider>.


Nó làm cho bất kỳ components nào bên trong nó truy cập được vào store.




const el = <Provider store={store}>
             <Click/>
           </Provider>;
 


À, lưu ý là chúng ta cần import ProvidercreateStore nhé:



import { Provider } from 'react-redux';
import { createStore } from 'redux';
 


Tại thời điểm này, chúng ta đã tạo action của mình, reducer, store và cung cấp nó cho MouseClick components của chúng ta bằng cách sử dụng phần tử <Provider>


Để kết nối components của chúng ta với store, chúng ta cần gọi thêm hàm connect().


Hàm connect() trả về một components mới, bao bọc components bạn đã truyền cho nó và kết nối nó với store bằng các hàm tham số đặc biệt của nó.


Cú pháp hàm connect():




function connect(mapStateToProps?, mapDispatchToProps?)();
 



Trong đó, hàm connect() nhận hai tham số tùy chọn:

 

  • mapStateToProps



Hàm này được gọi mỗi khi state trong store thay đổi. Nó nhận state như một tham số và trả về state cho components.


Ví dụ, đối với ứng dụng tính số click của chúng ta, chúng ta cần trả về biến state với số click hiện tại:


 


function mapStateToProps(state) {
  return {
    click: state.click
  };
}
 



Bây giờ, components của chúng ta có thể truy cập vào biến click bằng cách sử dụng props.


Cũng giống như tên của các trạng thái chức năng, nó ánh xạ trạng thái tới các đạo cụ.


 

  • mapDispatchToProps



Từ tên của hàm chúng ta cũng có thể biết được, tham số này được sử dụng để ánh xạ các hàm điều phối (dispatch) thành các props.


Nó có thể là một đối tượng đơn giản, xác định hàm cần được ánh xạ:


 


const mapDispatchToProps = {
  incrementClick
}
 



Ở đây, mapStateToProps chỉ trả về các biến state dưới dạng props cho components của chúng ta sử dụng.


Trong khi mapDispatchToProps cho phép xác định cách chúng ta gửi các hành động và cung cấp các hàm điều phối dưới dạng props.


Cả hai đều là tùy chọn, chẳng hạn như components của bạn có thể chỉ cần đọc dữ liệu từ store.


Lưu ý là chúng ta cũng cần import hàm connect() để sử dụng được bạn nhé:


 


import { connect } from 'react-redux';
 



Đó. Như vậy là sau khi đến bước này, các components đã được phép truy cập vào dữ liệu cần thiết.


Nhưng cụ thể thì truy cập như thế nào?


Bên trong components của chúng ta, chúng ta chỉ cần truy cập vào các thuộc tính store bằng cách sử dụng props.


 


function MouseClick(props) {
  function handleClick() {
    props.incrementClick(1);
  }
  return <div>
    <p>{props.click}</p>
    <button onClick={handleClick}>CLICK VÀO ĐÂY!</button>
  </div>;
}
 



Lưu ý là chúng ta đã truyền 1 làm đối số cho incrementClick(), làm cho biến click của chúng ta tăng lên 1.


Chúng ta có thể thay đổi giá trị thành bất kỳ số nào khác và bộ đếm click của chúng ta sẽ hoạt động như dự tính, vì chúng ta đã xử lý tăng biến click trong hàm reducer.


Bây giờ, việc duy nhất còn lại là gọi hàm connect() cho MouseClick components và hiển thị nó trên trang:


 


const Click = connect(mapStateToPropsmapDispatchToProps)(MouseClick);

const el = <Provider store={store}>
          <Click/>
        </Provider>

ReactDOM.render(
  el
  document.getElementById("container")
);
 



Và đây và code đầy đủ của ứng dụng đếm số lượt click của chúng ta:

 


// Action creator
function incrementClick(click) {
  return {
    type: "CLICK_BUTTON",
    click: click
  }
}

const initialState = {
  click: 0
};

// Hàm reducer
function reducer(state = initialStateaction) {
  switch(action.type) {
    case "CLICK_BUTTON":
      return { click: state.click + action.click };
    default:
      return state;
  }
}

// Components
function MouseClick(props) {
  function handleClick() {
    props.incrementClick(1);
  }
  return <div>
    <p>{props.click}</p>
    <button onClick={handleClick}>CLICK VÀO ĐÂY!</button>
  </div>;
}

// Trả về sate dưới dạng props
// cho components truy cập
function mapStateToProps(state) {
  return {
    click: state.click
  };
}

// Cung cấp hàm điều phối
// dưới dạng props
const mapDispatchToProps = {
  incrementClick
}

// Tạo store
const store = createStore(reducer);

// Cho phép component mới (được trả về)
// kết nối với store
const Click = connect(mapStateToPropsmapDispatchToProps)(MouseClick);

const el = <Provider store={store}>
          <Click/>
        </Provider>

ReactDOM.render(
  el
  document.getElementById("container")
);
 



Còn tiếp....


---

HỌC VIỆN ĐÀO TẠO CNTT NIIT - ICT HÀ NỘI
Học Lập trình chất lượng cao (Since 2002). Học thực tế + Tuyển dụng ngay!
Đc: Tầng 3, 25T2, N05, Nguyễn Thị Thập, Cầu Giấy, Hà Nội
SĐT: 02435574074 - 0383.180086
Email: hello@niithanoi.edu.vn
Fanpage: https://facebook.com/NIIT.ICT/
 
#niit #niithanoi #icthanoi #niiticthanoi #hoclaptrinh #khoahoclaptrinh #hoclaptrinhjava #hoclaptrinhphp #java #php #python
Bình luận Facebook
Khóa học liên quan đến bài viết

KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS

56 giờ
Học Lập trình Front end hiện đại với ReactJS. Học làm chủ HTML, CSS, JS và thư viện JavaScript phổ biến nhất hiện nay. Sẵn sàng đi thực tập / đi làm ngay sau khóa học.

Khóa học PHP Full stack [2023] cho người mới bắt đầu

96 giờ
Khóa học Lập trình PHP Full stack, phiên bản cập nhật lần thứ 8. Dạy Lập trình PHP bài bản từ Front end đến Back end + Laravel. Hướng dẫn làm 2 Dự Án Web lớn

KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG

50 giờ
Khóa học giúp học viên sử dụng thành thạo ngôn ngữ Lập trình Python (3x). Hiểu và phát triển được Ứng dụng Web với Django Framework. Học thực hành với Giảng viên cao cấp.

Lập trình PHP với Laravel Framework

42 giờ
Khóa học Lập trình PHP với Laravel Framework được NIIT - ICT HÀ NỘI xây dựng nhằm hoàn thiện kỹ năng lập trình web các các bạn đã biết Lập trình Web PHP thuần.

Khóa học Java Full stack (IJFD)

104 giờ
Học lập trình Java Fullstack với khóa học được xây dựng theo lộ trình bài bản, từ JAVA CƠ BẢN đến JAVA WEB và nâng cao về JAVA FRAMEWORK như: Spring Boot, Hibernate
Mục lục
Đăng ký tư vấn
Nhân viên gọi điện tư vấn miễn phí sau khi đăng ký
Được cập nhật các ưu đãi sớm nhất
Hotline: 0383180086
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Hãy đăng ký để nhận những thông tin mới nhất về học bổng mới nhất tại NIIT - ICT Hà Nội
top
Đóng lại Đăng ký học tại NIIT - ICT Hà Nội
6260+ học viên đã theo học tại NIIT - ICT Hà Nội và có việc làm tốt trong ngành lập trình. Nắm lấy cơ hội ngay hôm nay!
Chọn khóa học
  • KHÓA HỌC LẬP TRÌNH FRONT END VỚI REACT.JS
  • KHÓA HỌC LẬP TRÌNH PHP WEB
  • Khóa học PHP Full stack [2023] cho người mới bắt đầu
  • Khóa học BIG DATA với Hadoop và Spark
  • Khóa học Lập trình Android tại Hà Nội
  • [Tuyển sinh 2023] Lập trình viên Quốc tế DigiNxt
  • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại Hà Nội
  • LẬP TRÌNH GAME
    • Khóa học Lập trình Game Unity
  • LẬP TRÌNH WEB FRONT END
    • KHÓA HỌC PYTHON HƯỚNG ĐỐI TƯỢNG
    • KHÓA HỌC ANGULAR & TYPESCRIPT (FRONT END)
  • LẬP TRÌNH WEB BACK END
    • LẬP TRÌNH JAVA WEB VỚI FRAME WORK
    • Lập trình Web với Django
    • Lập trình PHP với Laravel Framework
  • CHƯƠNG TRÌNH ĐÀO TẠO ỨNG DỤNG CÔNG NGHỆ
    • Khóa học Tiền lương & Phúc lợi (C&B Excel) tại TP HCM
  • LẬP TRÌNH WEB FULL STACK
    • Khóa học Java Full stack (IJFD)
  • LẬP TRÌNH MOBILE
    • FRONT-END VỚI REACTJS VÀ REACT NATIVE
    • Lập trình Android Nâng cao
  • ĐÀO TẠO CHO DOANH NGHIỆP
    • KHÓA HỌC BUSINESS ANALYSIC TỪ CƠ BẢN ĐẾN NÂNG CAO 2023
    • Khóa học Magento: Làm chủ CMS TMĐT lớn nhất
    • Khóa học IOT: Xây dựng Sản phẩm IOT với Raspberry Pi
    • Khóa học Automation Testing Chuyên nghiệp
  • KHÓA HỌC DỰ ÁN
    • Học sử dụng bộ Office: Word, Excel, Power Point, Mail chuyên nghiệp
  • KHÓA HỌC KHÁC
    • VBA Excel Toàn Tập (Cơ Bản - Nâng Cao)
    • VBA Excel Nâng cao
    • Khóa học JMeter: Performance Testing
    • Khóa học Tester đạt chuẩn Quốc tế ISTQB Foundation Level
    • Khoá Học Tester đạt chuẩn quốc tế ISTQB Advanced Level
Bạn chưa chọn khóa học cần đăng ký
Tên không được để trống
Số điện thoại không được để trống
Email không được để trống
Đăng ký học thành công!
Cảm ơn bạn đã đăng ký học tại NIIT - ICT HÀ NỘI!