มาเริ่มต้นเขียน React ด้วย Create React App กันดีกว่า
สวัสดีครับ บทความนี้เป็นบทความที่ผมดองไว้ยาวนานมากๆ เนื่องจากว่าติดปัญหาหลายๆอย่างทำให้ไม่มีเวลาเขียนให้จบซะที ครั้นมีเวลามาเขียนต่อ ก็พบว่าเนื้อหามันอัพเดทไปไวเหลือเกิน ก็ต้องมารื้อๆ มาปรับแก้บางส่วนเพื่อให้ผู้อ่านมือใหม่ได้เข้าใจ
วันนี้ก็เลยนำมาปัดฝุ่น หลังจากเคยเขียนบทความเกี่ยวกับ React ไว้เมื่อนานมาแล้ว จนตอนนี้ก็ผ่านมา 3 ปีละ รู้สึกว่าบทความนี้คนค้นหา และอ่านกันค่อนข้างเยอะ : React คืออะไร ? + เริ่มต้นเขียน React ซึ่งเนื้อหามันค่อนข้างเก่าแล้วด้วย จะอัพเดทก็ยังไงๆอยู่ เลยตัดสินใจเขียนใหม่เลยดีกว่า
ซึ่ง ณ ปัจจุบัน ต้องบอกเลยว่าการเรียน React นั้น แม้ว่าจะมี Learning Curve ที่ค่อนข้างสูง แต่ตอนนี้น่าจะมีความง่ายขึ้นมากกว่าเมื่อก่อน เนื่องจาก Community ไปเร็วมาก บทความต่างๆ Tutorials ก็มีให้อ่าน ให้ดูมากมาย เหนื่อสิ่งอื่นใด คือมีเจ้า Create React App นี่แหละมาช่วยให้การเริ่ม React นั้นง่ายขึ้น
เตรียมตัวก่อนเขียน React
- ควรจะมีพื้นฐาน Node.js มาบ้าง (อ่านเพิ่มเติม : Node.js คืออะไร ? + เริ่มต้นใช้งาน Node.js)
- ใช้ Command Line ได้ พอรู้จัก NPM, Yarn
- ถ้ารู้จัก หรือเคยเขียน ES6/ES7 มาก่อนจะดีมาก (อ่านเพิ่มเติม : มาหัดเขียน JavaScript ES6 (ES2015) กันดีกว่า)
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 หน้าตาเว็บเราก็จะเป็นแบบนี้
ที่นี้กลับมาดูที่ตัวโปรเจ็คเรา ทำการเปิดด้วย Text Editor หรือ IDE ที่เราถนัดเลย ซึ่งไฟล์ที่สำคัญๆจะประกอบไปด้วย
public/index.html
: คือไฟล์ html หลักของเราsrc/index.js
: เป็นไฟล์หลักของ Reactsrc/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 : importexport 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 ทุกอย่างมาให้เราแล้ว สนใจแค่โค๊ดก็พอ :)
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>
)
แต่ถ้าเราต้องการ 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
ซึ่งเรายังไม่ได้สร้าง ต่อมาสร้าง methodhandleClick
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 จะเห็นว่า ค่าถูกอัพเดทตามที่เรากดเลย
สรุประหว่าง Props และ States
Props
: จะเป็นการส่งข้อมูลข้าม ComponentState
: ข้อมูลจะถูกใช้ภายใน 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"
/>
}
สรุป
บทความนี้ก็ถือว่าเป็น Guide Basic สำหรับผู้เริ่มต้นหัดเขียน React ละกันนะครับ ซึ่งถือว่าเริ่มต้นได้ง่ายกว่าเมื่อ 2-3ปีก่อนมากๆ มี Create React App เข้ามาช่วย
และเนื้อหาบทความนี้ก็ส่วนใหญ่ บางอันก็จะไม่ได้ลง Detail มาก เน้นมองภาพรวม ไปเร็วๆ ซึ่งไม่รู้ว่าจะอ่านเข้าใจกันรึเปล่าหนอ เดี๋ยวบทความหน้า ถ้ามีเวลาว่างจะมานั่งอธิบายว่า ES6 Feature ไหนที่ใช้ใน React บ่อยๆ แล้วมันทำงานยังไง?
สุดท้าย Source Code ของบทความ เผื่อมีประโยชน์ไม่มากก็น้อย
- Authors
- Name
- Chai Phonbopit
- Website
- @Phonbopit