Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> JavaScript

React Components: Functional vs Class Components

React.js เป็นเฟรมเวิร์ก JavaScript ที่ช่วยให้นักพัฒนาสามารถห่อหุ้มโค้ดเพื่อนำไปใช้ซ้ำได้ โค้ดที่ห่อหุ้มไว้เรียกว่า Components สามารถเก็บ logic และ state ของตัวเองได้โดยไม่รบกวน Document Object Model (DOM)

การแยกส่วนของเว็บไซต์เป็นคอมโพเนนต์เล็กๆ เพื่อส่งผ่านข้อมูล ทำให้โค้ดเป็น reusable และ DRY (Don't Repeat Yourself) มีคอมโพเนนต์หลัก 2 ประเภทใน React ได้แก่ Functional Components และ Class Components


ภาพรวม React Components

ในระดับสูง React Components คือฟังก์ชัน JavaScript ที่รับ props เป็นพารามิเตอร์ และคืนค่า React elements ที่อธิบายว่าควรแสดงอะไรบนหน้าจอ

import React from 'react';
import ReactDOM from 'react-dom';

const Greeting = (props) => {
  return (
    <div> Hello, {props.name} </div>
  );
};

const element = <Greeting name="Yolanda" />;
ReactDOM.render(element, document.getElementById('root'));

React element ในที่นี้คือ <div> พร้อมข้อความที่ใช้ props object ที่ส่งเข้ามา Props จะส่งข้อมูลลงจาก parent ไปยัง child components

Functional Components

Functional components คือฟังก์ชัน JavaScript ธรรมดา สามารถเขียนด้วยไวยากรณ์ ES5 หรือ ES6 กฎทั่วไปคือชื่อคอมโพเนนต์ต้องขึ้นต้นด้วยตัวพิมพ์ใหญ่

ตัวอย่าง ES5 Functional Component (ไม่ใช้ JSX)

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Basic React Component</title>
</head>
<body>
  <div id="root"></div>
  <script src="https://unpkg.com/react@16/umd/react.development.js" crossorigin></script>
  <script src="https://unpkg.com/react-dom@16/umd/react-dom.development.js" crossorigin></script>
  <script>
    'use strict';
    const element = React.createElement;
    function Greeting() {
      return element('h4', null, `Hello, World!`);
    }
    function App() {
      return element(Greeting);
    }
    const domContainer = document.querySelector('#root');
    ReactDOM.render(element(App), domContainer);
  </script>
</body>
</html>

นี่คือตัวอย่าง ES5 functional component โดยไม่ใช้ JSX ใช้ React.createElement สร้าง element แทน

JSX คืออะไร?

JSX (JavaScript XML Extension) ช่วยให้เขียน HTML ใน JavaScript ได้ ทำให้เข้าใจง่ายและขยายแอปได้เร็วขึ้น เป็น syntactic sugar ของ React.createElement

Functional Components แบบ ES5 และ ES6 (ใช้ JSX)

ES5

import React from 'react';
import ReactDOM from 'react-dom';

function Animal(props) {
  const element = <h1>My cat's name is {props.name}</h1>;
  return element;
}

function App() {
  return <Animal name="Marshmallow"/>;
}

const domContainer = document.querySelector('#root');
ReactDOM.render(<App/>, domContainer);

ES6

const Animal = (props) => {
  const element = <h1>My cat's name is {props.name}</h1>;
  return element;
}

const App = () => {
  return <Animal name="Marshmallow"/>;
}

const domContainer = document.querySelector('#root');
ReactDOM.render(<App/>, domContainer);

ก่อน React v16 Functional components เรียกว่า stateless components ใช้เพื่อแสดงผล (presentational) ไม่จัดการ state เอง แต่รับข้อมูลผ่าน props

Class Components

Class components ซับซ้อนกว่า ใช้แนวคิด ES6 class โครงสร้างคลาสคืออ็อบเจ็กต์ที่มี attributes และ methods ใช้ this เข้าถึง instance

ใน React Class components เป็น instance ที่มี state (ข้อมูลที่คอมโพเนนต์ครอง) สามารถนำ state ไปแสดง ส่งต่อ หรือใช้ใน logic อื่นๆ ได้

import React from 'react';
import ReactDOM from 'react-dom';
import Name from './Name';

class Animal extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      species: ['fox', 'tiger', 'bear', 'kangaroo', 'fish', 'cat', 'dog', 'squirrel']
    };
  }

  render() {
    return (
      <div>
        {this.state.species.map(animal => {
          return <Name animal={animal}/>;
        })}
      </div>
    );
  }
}

ReactDOM.render(<Animal />, document.getElementById('root'));

State เป็นอ็อบเจ็กต์ที่มี properties และ values ใช้ this.state.species เข้าถึง array นี้ จุดประสงค์คือส่งชื่อสัตว์ลงไปยัง component <Name />

ข้อมูลไหลเพียงทางเดียว: จาก parent ไป child เพียงระดับเดียว ต้องส่งต่อหากต้องการให้ grandchild เข้าถึงได้

Lifecycle Methods

Class components ใช้ lifecycle methods จัดการ state:

  1. componentDidMount() - ทำ AJAX requests โหลดข้อมูลเข้า state ด้วย this.setState()
  2. componentDidUpdate() - อัปเดต state หลัง user โต้ตอบ
  3. componentWillUnmount() - ทำความสะอาด timers, AJAX requests เมื่อ unmount

Class components ใช้ render() method แทน return statement ของ functional components

Functional Components และ useState() (React Hooks)

React v16 (2018) นำเสนอ React Hooks - วิธีที่สะอาดและกระชับในการใช้ state และ lifecycle ใน functional components

import React, {useState} from 'react';
import ReactDOM from 'react-dom';

const Animal = (props) => {
  const element = <h1>My cat's name is {props.name}</h1>;
  return element;
};

const App = () => {
  const [state, setState] = useState('Marshmallow');
  return <Animal name={state}/>;
};

const domContainer = document.querySelector('#root');
ReactDOM.render(<App/>, domContainer);

useState คืนค่า array 2 ตัว: ค่า state ปัจจุบัน และฟังก์ชันอัปเดต state (setState) ใช้ curly braces {state} ใน JSX เพื่อส่งค่าเข้าไป

useEffect() hook รวมทุก lifecycle methods ไว้ใน hook เดียว

สรุป

ก่อน React v16 Functional components ใช้เฉพาะแสดงผล Class components จัดการ state และ lifecycle methods React Hooks ทำให้ functional components สามารถมี state และ lifecycle ของตัวเองได้ แม้ Hooks จะนิยมมากขึ้น แต่ควรเข้าใจ class components ด้วย เพราะ legacy code ยังใช้อยู่มาก