มาเริ่มต้นเขียน React ด้วย Create React App กันดีกว่า

Published on
React
2018/02/learn-react-with-create-react-app
Discord

สวัสดีครับ บทความนี้เป็นบทความที่ผมดองไว้ยาวนานมากๆ เนื่องจากว่าติดปัญหาหลายๆอย่างทำให้ไม่มีเวลาเขียนให้จบซะที ครั้นมีเวลามาเขียนต่อ ก็พบว่าเนื้อหามันอัพเดทไปไวเหลือเกิน ก็ต้องมารื้อๆ มาปรับแก้บางส่วนเพื่อให้ผู้อ่านมือใหม่ได้เข้าใจ

วันนี้ก็เลยนำมาปัดฝุ่น หลังจากเคยเขียนบทความเกี่ยวกับ React ไว้เมื่อนานมาแล้ว จนตอนนี้ก็ผ่านมา 3 ปีละ รู้สึกว่าบทความนี้คนค้นหา และอ่านกันค่อนข้างเยอะ : React คืออะไร ? + เริ่มต้นเขียน React ซึ่งเนื้อหามันค่อนข้างเก่าแล้วด้วย จะอัพเดทก็ยังไงๆอยู่ เลยตัดสินใจเขียนใหม่เลยดีกว่า

ซึ่ง ณ ปัจจุบัน ต้องบอกเลยว่าการเรียน React นั้น แม้ว่าจะมี Learning Curve ที่ค่อนข้างสูง แต่ตอนนี้น่าจะมีความง่ายขึ้นมากกว่าเมื่อก่อน เนื่องจาก Community ไปเร็วมาก บทความต่างๆ Tutorials ก็มีให้อ่าน ให้ดูมากมาย เหนื่อสิ่งอื่นใด คือมีเจ้า Create React App นี่แหละมาช่วยให้การเริ่ม React นั้นง่ายขึ้น

เตรียมตัวก่อนเขียน React

React คืออะไร?

React เป็น JavaScript Library ที่เอาไว้สำหรับทำ UI (พัฒนาโดย Facebook) ซึ่ง React ไม่ใช่ SPA Framework (Single Page Application) อย่าง Angular แต่เป็นเพียงแค่ตัว V ใน MVC (Model View Controller) เท่านั้น คือเอาไว้ render พวก Component หรือ Element ต่างๆ ในหน้า HTML เท่านั้น

Create React App คืออะไร?

Create React App เป็น Command Line Tools ที่เอาไว้ให้เราสร้างโปรเจ็ค React ได้ง่ายๆ เพียงแค่การพิมพ์คำสั่งบรรทัดเดียว ซึ่งเจ้า Create React App นั้นถูกสร้างโดย Facebook (นำทีมโดย Dan Abramov คนคิด Redux นั่นเอง) ซึ่งจริงๆทำผ่านตัว react-scripts ซึ่งถ้าหากเราไม่ใช่ตัว Create React App เราก็ต้อง โหลด React มาติดตั้งเอง

ซึ่งเจ้า Create React App นั้น รวม Tools และ Config ค่าต่างๆ หลายๆอย่างไว้ให้เราแล้ว โดยที่เราเอาเวลาโฟกัสเรื่องพวกนี้ไปเขียน React จะดีกว่า

ด้านล่างนี้คือ Features ของ Create React App (สำหรับมือใหม่ ข้ามไป เริ่มสร้าง Project ได้เลยครับ)

  • Config Webpack สำหรับทั้ง Development และ Production (Minify CSS, JS, Images)
  • Babel : ถูก Setup มาให้เรียบร้อยแล้ว ซึ่งการเขียน React บาง Feature ยังจำเป็นต้องพึ่งตัว Babel อยู่ เช่น JSX, Object Rest/Spread
  • ESLint : Config มาให้แล้ว เผื่อเอาไว้เช็ค Syntax ของโค๊ดเราว่าเขียนถูกต้องตาม Style Guide หรือไม่
  • Jest : เป็นตัว Test Library ของทาง Facebook built in มาให้เรียบร้อย
  • Autoprefixer CSS : ไม่ต้องไปนั่งใส่พวก Vendor prefix เช่น -moz-, -webkit-
  • PWA (Progressive Web Application) : ใส่ Service Worker แล้วก็ Web Manifest มาให้เลย

Step 1 : Getting Started

เราจะเริ่มต้นเขียน React ด้วยการใช้งาน Create React App กัน วิธีนั้นง่ายมากๆ เปิด Terminal ขึ้นมา สำหรับ Tutorial นี้ผมตั้งชื่อ App ให้มันว่า hello-react

สำหรับ npm version 5.2+ ใช้คำสั่งนี้ :

npx create-react-app hello-react

และ สำหรับ npm เวอร์ชั่นต่ำกว่า

npm install create-react-app -g
create-react-app hello-react

npx เป็นเหมือน version upgrade ของ npm หากใช้ npm version 5.2+ จะมีติดมาอยู่แล้ว

หลังจากนั้น เราก็จะได้โปรเจ็คที่เป็น React ขึ้นมา

cd hello-react
yarn start

# หรือหากใช้ npm :
npm start

เมื่อรันแล้ว มันจะเปิดหน้าเว็บเราให้อัตโนมัติ โดย default แล้วจะเป็น http://localhost:3000 หน้าตาเว็บเราก็จะเป็นแบบนี้

Hello React

ที่นี้กลับมาดูที่ตัวโปรเจ็คเรา ทำการเปิดด้วย Text Editor หรือ IDE ที่เราถนัดเลย ซึ่งไฟล์ที่สำคัญๆจะประกอบไปด้วย

  • public/index.html : คือไฟล์ html หลักของเรา
  • src/index.js : เป็นไฟล์หลักของ React
  • src/App.js : ไฟล์สำหรับ Component ที่ชื่อว่า App

ซึ่งเมื่อเปิดดูไฟล์ App.js จะมีโค๊ดด้านล่างดังนี้

import React, { Component } from 'react'
import logo from './logo.svg'
import './App.css'

class App extends Component {
  render() {
    return (
      <div className="App">
        <header className="App-header">
          <img src={logo} className="App-logo" alt="logo" />
          <h1 className="App-title">Welcome to React</h1>
        </header>
        <p className="App-intro">
          To get started, edit <code>src/App.js</code> and save to reload.
        </p>
      </div>
    )
  }
}

export default App
  • import { Component } from 'react' : คือการ Import module จะมีทั้ง import default และ import module, See more : ES6 : import
  • export default App : คือการ export ตัว Component App เพื่อเอาไปใช้ที่ไฟล์อื่น See more : ES6 export

Note : สำหรับบทความผมใช้ Style Guide แบบ Standard เลยไม่มี ; ต่อท้าย ไม่ต้องตกใจไปครับ

เราจะเห็นว่า ด้านบนมีส่วนที่คล้ายๆ HTML เลย นั่นก็คือตรงส่วนที่อยู่ใน render() ซึ่งมันก็คือการ render HTML นั่นแหละ เพียงแต่ render ในรูปแบบ JSX Syntax ที่สามารถใส่โค๊ด JavaScript ลงไปใน HTML ได้ เช่น

<img src={logo} className="App-logo" alt="logo" />

จะเห็นว่าเราสามารถใส่ script ลงไปใน HTML ได้ ผ่าน {}

และ App ก็คือ Component ของเราเอง ที่ extend มาจาก React.Component อีกที ซึ่งเจ้า Component กฎการสร้างก็มีเพียงแค่นี้ (คือการ extends Component และมี function render() เพื่อ return เป็น HTML Element กลับมา)

และดูที่ไฟล์ /src/index.js ซึ่งเป็นไฟล์ที่จะใช้รัน React

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'
import registerServiceWorker from './registerServiceWorker'

ReactDOM.render(<App />, document.getElementById('root'))
registerServiceWorker()

จะเห็นว่ามีส่วน ReactDOM.render(<App />, document.getElementById('root')) มันเป็นการบอกว่า หา element ที่มี id ชื่อว่า root จากนั้นก็ทำการ render React Component โดยในที่นี่ทำการ render ตัว App ญึ่ง id=root เราได้ประกาศไว้ในไฟล์ public/index.html นั่นเอง

ที่นี้เราลองมาดูตัวอย่างการใช้ Component ร่วมกับ HTML ดู สมมติเราสร้าง Component ใหม่ และตั้งชื่อว่า HelloApp.js

import React from 'react'

class HelloApp extends React.Component {
  render() {
    return <h1>Ahoy! React</h1>
  }
}

export default Hello

ทำการแก้ไขไฟล์ src/App.js โดยการเพิ่ม นี้ลงไป

import HelloApp from './HelloApp'

และตรงส่วน render() ก็ทำการเพิ่ม <HelloApp /> ลงไป

render () {
  return (
    <div className='App'>
      <HelloApp />
      <header className='App-header'>
        <img src={logo} className='App-logo' alt='logo' />
        <h1 className='App-title'>Welcome to React</h1>
      </header>
      <p className='App-intro'>
        To get started, edit <code>src/App.js</code> and save to reload.
      </p>
    </div>
  )
}

ทีนี้เมื่อลองดูหน้าเว็บอีกครั้ง เราจะเห็น Ahoy! React และก็ไม่จำเป็นต้อง refresh browser ด้วย ตัว Create React App นั้น built in ทุกอย่างมาให้เราแล้ว สนใจแค่โค๊ดก็พอ :)

Hello React 2

Step 2 : Props & State

ต่อมา เรามาพูดถึงเรื่องถัดไปของ React กัน นั้นก็คือเรื่องของ Props และ States กัน หากเราเขียน React ก็หนีไม่พ้นเจ้าสองตัวนี้แน่นอน ยังไงก็ต้องเจอ มาเริ่มเลย

Props

Props หรือชื่อเต็มๆมันคือ Properties หากเปรียบกับ HTML แล้ว ตัว Props จะเป็นคล้ายๆ attributes ของ HTML ดัง เช่น src, href หรือ class

<img src="/path/to/image.png" /> <a href="#" class="my-link">Click!</a>

ซึ่ง Props ใน React ข้อดีคือ เราสามารถส่งข้อมูลจาก Component หนึ่งไปอีก Component ได้ด้วยการใช้ Props นี่แหละ

เราลองกลับมาที่ Component App.js ที่เราเรียก HelloApp เราลองทำการส่ง props ไปกับ Component ด้วย แบบนี้

<HelloApp message="This is message sent from App" />

และที่นี่ที่ไฟล์ HelloApp.js เราก็ต้องทำการเพิ่ม

import React from 'react'

class HelloApp extends React.Component {
  render() {
    return (
      <div>
        <h1>Ahoy! React</h1>
        <p>{this.props.message}</p>
      </div>
    )
  }
}

export default HelloApp

ซึ่งจะเห็นได้ว่า render() นั้น return ค่าหลายบรรทัด เราจะใช้ () ซึ่งจำเป็นต้อง wrap element ด้วย ซึ่งถ้าเรา return แบบด้านล่าง จะไม่สามารถ run ได้ เนื่องจาก JSX จะมองไม่เห็น closing tag

return (
  <p>Hello</p>
  <p>Hello2</p>
)
React Compile Error

แต่ถ้าเราต้องการ render แบบนี้ละ ไม่อยากเอา div มาหุ้มอีกชั้นนึง? เราสามารถใช้ Fragment เข้ามาช่วยได้ แบบนี้

return (
  <React.Fragment>
    <h1>Ahoy! React</h1>
    <p>{this.props.message}</p>
  </React.Fragment>
)

ก็จะไม่ error แล้ว

State

State เป็นค่าที่จะถูกใช้ ภายใน Component วิธีการใช้งาน State ทำการสร้าง Constructor ขึ้นมา จากนั้น set ค่า default state ด้วยคำสั่ง this.state = {}

import React from 'react'

class HelloApp extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      counter: 0
    }
  }

  render() {
    return (
      <React.Fragment>
        <h1>Ahoy! React</h1>
        <p>{this.props.message}</p>
        <buttonClick me!</button>
        <p>Total click : {this.state.counter}</p>
      </React.Fragment>
    )
  }
}

export default HelloApp

ด้านบน เราได้ทำการเปลี่ยนแปลง HelloApp.js ใหม่

  • โดยให้ counter เก็บไว้ใน state มีค่าเริ่มต้น 0
  • ทำการ render ค่า counter ด้วย {this.state.counter}

เมื่อเราต้องการจะ set ค่าให้กับ state เราสามารถเรียกใช้ this.setState() ได้แบบนี้

this.setState({
  key: value
})

ตัวอย่าง ผมจะให้ เมื่อเราทำการ Click button จะให้มันทำการเพิ่ม counter ทีละ 1 โดยการใช้ setState() นั่นเอง ที่ <button>Click me!</button> ทำการเพิ่ม onClick เข้าไป

<button onClick={this.handleClick}>
  • เมื่อมี event click จะไปเรียก method handleClick ซึ่งเรายังไม่ได้สร้าง ต่อมาสร้าง method handleClick
handleClick() {
  this.setState({
    counter: this.state.counter + 1
  })
}

แต่! เราจะยังไม่สามารถกดได้ เนื่องจากตัว button เวลาถูก click มันไปเรียก handleClick แต่ว่า this ในฟังค์ชั่น มัน refer ไปที่ button ไม่ใช่ Class มัน เราจึงต้องทำการ bind ใน Constructor ก่อน

constructor(props) {
  this.handleClick = this.handleClick.bind(this)
}

สุดท้ายโค๊ด HelloApp.js จะเป็นแบบนี้

import React from 'react'

class HelloApp extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      counter: 0
    }

    this.handleClick = this.handleClick.bind(this)
  }

  handleClick() {
    this.setState({
      counter: this.state.counter + 1
    })
  }

  render() {
    return (
      <React.Fragment>
        <h1>Ahoy! React</h1>
        <p>{this.props.message}</p>
        <button onClick={this.handleClick}>Click me!</button>
        <p>Total click : {this.state.counter}</p>
      </React.Fragment>
    )
  }
}

export default HelloApp

แต่ว่า (อีกแล้ว) เนื่องจากเวลาเรา setState() ถ้าเกิดว่ามีการอัพเดท state เดิม มันจะมี side effect บ้างในบางครั้ง ทาง React แนะนำว่า ให้ใช้การ setState() แบบ function แทน ซึ่ง function ก็มี 1 argument เป็น state ก่อนหน้า และ return เป็น new state เช่น

this.setState(function (prevState) {
  return {
    counter: prevState.counter + 1
  }
})

แปลงด้านบนเป็น ES6 ให้สวยๆดีกว่า

this.setState(prevState => ({
  counter: prevState.counter + 1
}))

ทีนี้ลองกลับไปดูแล้วลอง คลิ๊ก Button จะเห็นว่า ค่าถูกอัพเดทตามที่เรากดเลย

Counter Clikc

สรุประหว่าง Props และ States

  • Props : จะเป็นการส่งข้อมูลข้าม Component
  • State : ข้อมูลจะถูกใช้ภายใน Component ตัวเอง
  • State : เมื่อ State มีการเปลี่ยนแปลง Component จะทำการ render() ใหม่

Step 3 : Stateless Component

ต่อมามาดูการสร้าง Component อีกแบบนึง ที่เรียกว่า Stateless Component คือ Component ที่ไม่มี State

เอ๊ะ เมื่อกี้เพิ่งพูดถึง State, setState() ไป คราวนี้ไม่มี State แล้ว ?

จริงๆ อาจจะมีบาง Component ที่เราต้องการสร้าง ไม่จำเป็นต้องใช้ State ต้องการรับค่า Props มาแล้วก็ทำการ Render อย่างเดียว เราก็ไม่จำเป็นต้อง extends React.Component แถมพ่วงมาด้วย Life Cycle ต่างๆ ของ React มาด้วย

วิธีการสร้าง Stateless Component คือจริงๆ ให้มองว่ามันคือ Function ธรรมดาก็ได้ เช่น

function Hello(props) {
  return <h1>Ahoy! {props.name}</h1>
}

ด้านบน เป็น function ที่รับ prop มา แล้ว return เป็น JSX กลับไป ทีนี้เราลองมาสร้าง Stateless ใน HelloApp.js ดู เพิ่งฟังค์ชั่น ด้านบน เข้าไปก่อนบรรทัด class HelloApp

function Hello(props) {
  return <h1>Ahoy! {props.name}</h1>
}

class Hello App extends React.Component {
 ...
}

และส่วน render() ก็แค่เรียกใช้ Component Hello พร้อมส่ง props ที่ชือ่ว่า name ไปด้วย แบบนี้

<Hello name="Chai" />

ข้อดีของ Stateless Component คือ

  • ไม่ต้อง extends Class ให้ยุ่งยาก
  • ไม่ต้องใช้ this (ไม่ต้อง bind ใน Constructor) แล้ว เช่น this.props.name ก็ใช้ props.name ได้เลย หรือ {onClikc={handleClikc}

ตัวอย่าง Stateless Component อีกอัน ลองสร้างขึ้นมาชื่อ MyStatelessComponent.js

import React from 'react'

const MyStatelessComponent = props => (
  <div>
    <h1>{props.title}</h1>
    <p>{props.message}</p>
  </div>
)

export default MyStatelessComponent

หรือสามารถ เขียน MyStatelessComponent ใหม่อีกแบบ ด้วย ES6 Destructuring ดังนี้

import React from 'react'

const MyStatelessComponent = ({ title, message }) => (
  <div>
    <h1>{title}</h1>
    <p>{message}</p>
  </div>
)

export default MyStatelessComponent

แล้วที่ไฟล์ App.js ก็ลองทำการเรียกใช้

import MyStatelessComponent from './MyStatelessComponent'


render() {
  <MyStatelessComponent
    title="Stateless"
    message="Example of Stateless Component"
  />
}
React Stateless

สรุป

บทความนี้ก็ถือว่าเป็น Guide Basic สำหรับผู้เริ่มต้นหัดเขียน React ละกันนะครับ ซึ่งถือว่าเริ่มต้นได้ง่ายกว่าเมื่อ 2-3ปีก่อนมากๆ มี Create React App เข้ามาช่วย

และเนื้อหาบทความนี้ก็ส่วนใหญ่ บางอันก็จะไม่ได้ลง Detail มาก เน้นมองภาพรวม ไปเร็วๆ ซึ่งไม่รู้ว่าจะอ่านเข้าใจกันรึเปล่าหนอ เดี๋ยวบทความหน้า ถ้ามีเวลาว่างจะมานั่งอธิบายว่า ES6 Feature ไหนที่ใช้ใน React บ่อยๆ แล้วมันทำงานยังไง?

สุดท้าย Source Code ของบทความ เผื่อมีประโยชน์ไม่มากก็น้อย

Buy Me A Coffee
Authors
Discord