Skip to main content

[React] Component là gì? Tìm hiểu cụ thể về component

Component là gì?

Component là một block code độc lập để phân chia các UI (giao diện người dùng) thành các phân nhỏ riêng lẻ để dễ dàng quản lý và tái sử dụng.

Ví dụ:

Mình có một website gồm nhiều phần bố cục khác nhau như phần header, phần thân (body), phần footer và bây giờ mình muốn chia các thành phần đó thành 3 component header, body và footer riêng các phần ra để dễ quản lý hoặc tái sử dụng nó

Image
Component là gì

Khởi tạo một React Component

Trước khi thực hiện viết components, chúng ta nên khởi tạo một thư mục có tên components trong thư mục src để chứa tất cả các component trong dự án. Cấu trúc thư mục của dự án lúc này sẽ là:

public/
node_modules/
src/
-----components/
---------------Components sẽ viết ở trong thư mục này
-----App.js
-----index.js
---- vv....
packages.json
packages-lock.json

React có 2 loại component: Funtional (Stateless) và Class (Stateful)

Lưu ý: Đặt tên cho component phải viết hoa dạng Pascal case.

Đoạn mã sau sẽ bị lỗi ở dòng số 3:

function numberInput() {
   return (<input type="number");
}
<numberInput />

Đoạn mã sau sẽ đúng:

function numberInput() {
   return (<input type="number");
}
let NumberInput = numberInput;
<NumberInput />

Functional (Stateless) Components

Functional component là một hàm Javascript (hoặc ES6) trả về 1 phần tử hoặc 1 element React và có thể nhận props làm tham số.

Đây là cách viết phổ biến và được sử dụng nhiều nhất trong các dự án mà mình viết, bởi tính nhanh gọn và không quá phức tạp như các viết class component.

Tiến hành tạo một file có tên Welcome.js trong thư mục src/components:

//Import react vào trong dự án
import React from "react";
 
const Welcome = function(props) {
  return (
    <div>
      <h1>Welcome ! I am a functional component </h1>
    </div>
  )
}
 
export default Welcome;

Các props được truyền vào component bằng cách nhận một tham số trong funciton. Chúng ta sẽ return các react element bằng cách sử dụng cú pháp return() như ví dụ bên trên

Cuối file bạn cần phải export component này để file khác có thể lấy và sử dụng. Bây giờ chúng ta sẽ tiến hành import file Welcome.js vào trong file App.js và gọi component Welcome như sau:

import React from 'react';
import Welcome from './components/Welcome'
function App() {
  return (
    <div>
        <Welcome />
    </div>
  );
}
 
export default App;

Tiến hành khởi chạy dự án chúng ta sẽ có kết quả như hình :

Image
Function Compoment React Demo

Chú ý: Functional components cũng được nói với một cái tên là stateless components bởi vì chúng ta không thể làm nhiều thứ phức tạp như quản lý React State (data) hoặc phương thức life-cycle trong functional components.

Tuy nhiên, React giới thiệu React Hooks trong versions 16.8, giờ nó cho phép chúng ta sử dụng state và những features khác trong functional components. Bạn có thể đọc React Hooks tại đây.

Class (Stateful) Components

Class component là một class ES6, nó sẽ là một component khi nó "kế thừa" React component, có thể nhận props trong hàm khởi tạo nếu cần, có maintain data của nó với state và có method render để trả về một React Element.

Cách viết này là cách viết đầy đủ của của một component, khi bạn viết một class component bạn sẽ sử dụng được hầu hết các chức năng của component như state, props, lifecycle,..

Chúng ta tiếp tục với ví dụ trên, chúng ta chỉ sửa đổi file src/Welcome.js :

import React, { Component } from "react";
class Welcome extends Component {
  render() {
    return (
      <div>
        <h1>Welcome ! I am a class component </h1>
      </div>
    );
  }
}
export default Welcome; 

Bạn có thể thấy, class Welcome kế thừa Component, vì vậy React hiểu class này là một component, và nó render 1 React Element.

Khởi chạy mà bạn sẽ nhận được kết quả giống như ví dụ bên trên.

Image
Class component React demo

 

Gợi ý: Khi bạn muốn làm việc với với các chức năng của component như events, state, lifce cycles hay tổ chức các đoạn code theo cấu trúc theo mô hình OOP thì bạn có thể cân nhắc sử dụng class components. Ngược lại, bạn có thể sử dụng functional component để thay thế.

Truyền và nhận tham số của React Component

Truyền tham số từ ngoài vào cho React Component

Tham số của React Component được gọi là «property».  Những ngôn ngữ markup như XML, HTML gọi tham số truyền vào là «attribute». Dịch sang tiếng Việt cả 2 đều là “thuộc tính” hết.

Trong các tài liệu tiếng Anh, «property» thường dùng trong ngữ cảnh ngôn ngữ JavaScript, còn «attribute» thường dùng với ngôn ngữ markup XML, HTML.

Có sự khác nhau giữa  Attribute của JSX là có thể nhận vào bất kỳ kiểu dữ liệu nào mà một biến JavaScript có thể chứa, nhưng attribute của HTML và XML chỉ có một kiểu dữ liệu chuỗi (string).

Khi truyền dữ liệu kiểu string cho React Component thì phải có cặp ngoặc nháy "...", nếu truyền kiểu dữ liệu khác, hoặc truyền biến, thì phải đặt trong cặp ngoặc móc {...}.

Chú ý: JSX attribute phải được viết ở dạng camel case.

Ví dụ:

function SalaryInput () {
   const holderText = 'Enter your salary';
   return (
      <NumberInput
         label="Salary"
         placeholder={holderText}
         readonly={false}
         decimalDigits={2}
      />
   );
}

Truyền kiểu dữ liệu nào vào thẻ HTML thì đều được xem như là string:

<input type="number" value={500} />
// Cũng giống như
<input type="number" value="500" />

Tham số kiểu boolean có giá trị true có thể được viết rút gọn, nhưng giá trị false thì phải viết ở dạng đầy đủ:

<NumberInput readonly />
// Cũng giống như
<NumberInput readonly={true} />

Nhận tham số từ bên trong React Component

Với Functional component

Function Component nhận được tham số dưới dạng một object gồm các key và value được truyền vào từ JSX. Ví dụ: 

const NumberInput = (props) => {
   console.log(props); // In ra { label: "Salary", placeholder: "Enter your salary", readonly: false, decimalDigits: 2 }
   return (...);
};

Với Class component

Class Component nhận tham số qua property tên là props. Truy cập đến nó bằng cú pháp this.props. Ví dụ:

class NumberInput extends React.Component {
   render() {
      console.log(this.props); // In ra { label: "Salary", placeholder: "Enter your salary", readonly: false, decimalDigits: 2 }
      return (...);
   }
}

Phân tách tham số (Argument destructuring)

Object Destructuring là một cú pháp có trong JavaScript ES6, chúng ta có thể sử dụng nó để lấy ra những property mà mình muốn, ví dụ:

function NumberInput(props) {
   const { placeholder: holder, readonly=false } = props;
   return (
      <input placeholder={holder} readonly={readonly} />
   );
}
class NumberInput extends React.Component {
   render() {
      const { placeholder: holder, readonly=false } = this.props;
      return (
         <input placeholder={holder} readonly={readonly} />
      );
   }
}

Mặc dù ở ví dụ trên chúng ta đã dùng chức năng “default value” của destructuring để gán giá trị mặc định cho props readonly, nhưng cách làm này không được khuyến khích, thay vào đó hãy dùng kỹ thuật dưới đây.

Sử dụng defaut Props

React cho phép chúng ta đặt giá trị mặc định cho props với default Props, nếu nó không được truyền từ bên ngoài vào.

Ưu điểm của cách này so với default value của destructuring là không cần phải khai báo nhiều lần mỗi khi cần destructure một props.

function NumberInput(props) {
   const { placeholder: holder, readonly=false } = props;
   return (
      <input placeholder={holder} readonly={readonly} />
   );
}
NumberInput.defaultProps = {
   readonly: false,
   decimalDigits: 4
}
class NumberInput extends React.Component {
   static defaultProps = {
      readonly: false,
      decimalDigits: 4
   };
   render() {
      const { placeholder: holder, readonly=false } = this.props;
      return (
         <input placeholder={holder} readonly={readonly} />
      );
   }
}

Không được gán đè props

Props là tham số từ bên ngoài truyền vào cho component, nên React không cho phép gán đè giá trị khác cho props. Đoạn mã sau sẽ gây lỗi:

function NumberInput(props) {
   props.readonly = true;
   return (...   );
}