Import and Export Modules

หลังจากที่คุณได้ผ่านคอร์ส React Basic มาแล้ว คงจะมีความคุ้นเคยกับเรื่องของ Module ในโลกของ Javascript เป็นอย่างดี แต่ยังไงก็ขอใช้พื้นที่ตรงนี้ในการอธิบาย Module โดยภาพรวมซักหน่อย

Module คือ หน่วยที่ใช้สำหรับจัดเก็บ code ไว้ในที่ใดที่หนึ่งอย่างเป็นระเบียบ ที่สามารถนำมาใช้งานภายในส่วนต่างๆ ของระบบของเราได้ โดยไม่ก่อให้เกิดความเสียหายใดๆ ต่อระบบโดยรวม

ES6 (ย่อมาจาก ECMAScript 6) คือมาตรฐานใหม่ล่าสุดของ Javascript ที่มีการปรับปรุง และเปลี่ยนแปลงหลายอย่างนับตั้งแต่ปี 2009 เป็นต้นมา ซึ่งหากคุณผู้อ่านสนใจ สามารถไปอ่าน feature ทั้งหมดของ ES6 ได้ที่ http://es6-features.org/

ตัว ES6 เองนั้น มีฟีเจอร์สำหรับช่วยให้เราจัดการกับ Module ได้อย่างดูเป็นระเบียบมากขึ้น โดยมาดูจาก code ของจริงกันเลยดีกว่าว่า มันทำงานอย่างไร

ในหนึ่งไฟล์นั้น เราสามารถ export item ต่างๆ ออกสู่โลกภายนอกได้มากกว่า 1 item (เรียกเป็นภาษาทางการว่า named exports) โดย item นั้นอาจจะเป็นได้ทั้ง function หรือ ตัวแปร (ส่วนใหญ่จะเป็น function) ก็ได้ และหากคุณต้องการจะใช้งาน item เหล่านั้น ก็แค่ import item พวกมันเข้ามาภายใน code ตัวอื่น (เรียกเป็นภาษาทางการว่า named imports)

มาดูตัวอย่างกัน

สมมติว่าเรามี module ที่ชื่อ math.js โดยภายใน module มีรายละเอียดดังนี้

คราวนี้เราต้องการจะนำ function บางตัวภายใน math.js มาใช้งาน เราก็แค่ import แบบนี้

การ import แบบ named imports นั้น ในส่วนของชื่อ item ที่เราระบุ จะต้องถูกครอบด้วย { } จากนั้นตามด้วย from และ path ที่ชี้ไปยัง module ตัวนั้น (ซึ่งในที่นี้คือ math.js ที่อยู่ใน path เดียวกับ app.js โดยเราไม่ต้องเขียน .js หลังไฟล์ เพราะ Javascript รู้อยู่แล้วว่ามันต้องเป็น .js file)

จากตัวอย่างข้างต้น math.js มีการ export function ออกมาสามตัว คือ add, multiply และ divide แต่ทาง app.js ต้องการ import มาใช้งานแค่ add และ multiply เท่านั้น

ในกรณีที่เราต้องการ import ทุก item ที่มีการ export ให้เราเขียนประโยค import ดังนี้

เพียงเท่านี้เราก็จะได้ item ทุกตัวที่ถูก assign ไว้ในตัวแปรชื่อ X แล้ว มาดูตัวอย่างวิธีใช้กันเลย

สมมติว่าใน app.js ต้องการ import function ทุกตัวใน math.js เราจะเขียนแบบนี้

ES6 นั้น เปิดให้เราสามารถ import และ export ได้สองแบบ โดยแบบแรกคือ named imports/exports ซึ่งเราได้กล่าวไปแล้ว

ส่วนแบบที่สองนั้นเรียกว่า default imports/exports เรามาดูตัวอย่างกัน

จากตัวอย่างข้างต้นจะเห็นว่า module math2.js นั้นมีการ export default ให้กับ function ชื่อ doAllTheMath เวลาที่เราจะทำการ import function ตัวนี้ เราสามารถ import แบบเรียกชื่อตรงๆ โดยไม่ต้องครอบด้วย { }

คราวนี้เราเอาวิธีการ import และ export ทั้งสองแบบมาผสมกันดีกว่า

module math3.js นั้นมีทั้งการ export แบบ named export และ default export เมื่อเราจะ import มาใช้งาน ก็ต้อง import doAllTheMath function ในแบบ default และ add function ในแบบ named โดยทั้งหมดนั้นสามารถทำจบได้ภายใน บรรทัดเดียว

ซึ่งหากให้มองตามสายตาของผมในฐานะผู้เรียบเรียง ผมมองว่าการ import module ในรูปแบบของ ES6 นั้น ดูดีกว่า การเขียนในแบบเดิมมากมายนัก

เพราะมันทั้งดูดีกว่า clean กว่า และเขียน code น้อยกว่า ที่สำคัญคือ เราสามารถนำไปเขียนผสมกับ code javascript แบบเก่าได้เลย ไม่ต้องเขียนแบบ ES6 ทั้งหมดก็ได้ ทำให้เราสามารถเลือกได้ว่า จะใช้ฟีเจอร์ใดของ ES6 มาเขียน หากตัวไหนช่วยทำให้ code ของเราดีขึ้น เข้าใจง่ายขึ้น ก็ปรับเฉพาะในส่วนนั้นที่เราต้องการเพียงเท่านั้น

Github Battle Refactoring

ติดตั้ง code ตั้งต้นสำหรับคนที่ไม่ได้ผ่านคอร์ส React Basic

หากใครไม่ได้ตามคอร์สใน React Basic สามารถไป clone git จาก code ตั้งต้นสำหรับคอร์สได้ที่ https://github.com/himaeng/react-fundamentals.git

ให้ทำการติดตั้ง code ดังนี้

ติดตั้ง babel-preset-es2015

ก่อนจะเข้าเรื่อง เราจำเป็นต้องทำการติดตั้งตัว preset ของ babel เพื่อให้มันสามารถแปลงไฟล์จาก ES6 (หรือ ES2015 แล้วแต่ใครจะเรียก)

ทำการติดตั้ง babel-preset-es2015

จากนั้นให้เปิดไฟล์ .babelrc (อยู่ใน root path ของ Project) แล้วให้แก้ดังนี้

นั่นแปลว่า งานนี้เราจะให้ babel แปลงไฟล์ทั้ง react และ es6 ให้กับเรา พร้อมๆ กัน (อย่าลืมใส่ ‘,’ ข้างหลัง “react” นะครับ)

ES6 Refactoring

ConfirmBattle Refactoring

เรามาเริ่ม Reafactoring กันเลยดีกว่า เริ่มจาก module ConfirmBattle.js

ให้เปิดไฟล์ app/components/ConfirmBattle.js

จากบรรทัดต่อไปนี้

ให้ refactor ดังนี้

เห็นความสวยงามมั๊ยครับ!!!

ทบทวนอีกครั้งตัว React จาก module react เป็น default exports ส่วน PropTypes เป็น named exports ดังนั้น เวลา import จึงต้องทำแบบนี้

ต่อไปให้เปลี่ยนตัว import ยกชุด จาก

เป็น

ท้ายสุด ให้เราทำการ export แบบ default ให้กับ component ตัวนี้ (จริงๆ React component มันก็คือ javascript module นั่นเอง) โดยเปลี่ยน code ในบรรทัดสุดท้ายจาก

เป็น

การ export แบบ default มีข้อเสียอยู่อย่างนึงคือ หากจะ import มัน แล้วใช้วิธีเขียนแบบ JavaScript แบบเดิม เราต้องเขียนแบบนี้

ซึ่งนั่นจะทำให้ code เดิมที่เคยมีการ import ConfirmBattle แบบเดิมๆ เกิดการ break ทันที ดังนั้น เราต้องไล่หาดูว่า มี module ใดบ้างที่มีการ import ConfirmBattle ไปใช้งาน

ให้เปิดไฟล์ app/containers/ConfirmBattleContainer.js ขึ้นมา แล้วแก้ code ตรงส่วนที่ import ConfirmBattle ดังนี้

ให้เป็น

คราวนี้ให้ลองเข้าไปใช้ระบบผ่าน localhost:8080 เมื่อเจอหน้าแรกให้กดปุ่ม ‘Get Started’ เพื่อเข้าระบบ จากนั้นในสองหน้าต่อมาให้กรอกข้อมูล username ใน github ที่คุณรู้จัก เพื่อเอามาวัดคะแนน จากนั้นเมื่อไปถึงหน้า /battle?… แล้วเปิด console ดู หากหน้า console ว่างเปล่า ไร้ริ้วรอยแห่ง error ใดๆ ก็เป็นอันสบายใจได้ว่าการ refactor ครั้งนี้ไร้ปัญหา

screen-shot-2559-11-09-at-10-30-01-am

Home refactoring

ให้เปิดไฟล์ app/components/Home.js ขึ้นมา แล้วแก้ตัว import จาก

ให้เป็น

เปลี่ยนบรรทัดสุดท้าย จาก

ให้เป็น

เหมือนเดิมครับ เวลาเราทำการ exports แบบ default เราจะต้องไล่ไปดูด้วยว่า มี module ใดบ้างที่ทำการ import Home module แบบเดิมบ้าง ซึ่งในที่นี้จะมีแค่ module เท่านั้น นั่นคือ routes.js

ให้เปิดไฟล์ app/config/routes.js ขึ้นมา แล้วทำการแก้ code จาก

เป็น

จากนั้นให้ลองเข้าไปที่ localhost:8080 ดู หากเปิด console แล้วไม่มีอะไรผิดพลาด ก็ถือว่าผ่าน

Loading refactoring

เปิดไฟล์ Loading.js ขึ้นมา แล้วแก้การ import และ export ให้เป็นดังนี้

จากนั้นให้เปิดไฟล์ app/components/Results.js ขึ้นมาเพื่อแก้ code ในการ import (สำหรับขั้นตอนนี้ให้ลองทำดูเอาเองได้เลยนะครับ เพราะมันเป็นขั้นตอนเดิม)

Main refactoring

จากนั้นให้ทำการแก้ import และ export ของ app/components/Main.js (เนื่องจากมันมีการ import แค่ item เดียว ดังนั้นจึงไม่น่าจะจำเป็นต้องแสดง code ให้ดู)

routes refactoring

เนื่องจากผมเริ่มรำคาญการต้องคอยเข้ามาแก้ไขการ import และ export ใน routes.js มาก ดังนั้นให้แก้การ import ของ module นี้ทั้งหมดเลย ให้เป็นดังนี้

จากนั้นให้เปิด index.js ตรง root project แล้วแก้ code ดังนี้

เสร็จแล้วอย่าลืมลองทดสอบด้วยเข้าไปเล่นระบบดูนะครับ หากเจอ error  ก็ลองซ่อมดู เพื่อสร้างความเข้าใจใน ES6 และการ Refactoring ไปในอีกทางหนึ่งด้วย

Prompt refactoring

เปิด app/components/Prompt.js แล้วแก้ code ดังนี้

จากนั้นเปิดไฟล์ app/containers/PromptContainer.js แล้วแก้ code ดังนี้

จากนั้นก็ลองทดสอบกับ browser จริงดู

Results refactoring

เปิดไฟล์ app/components/Results.js แล้วแก้ code ดังนี้

จากนั้นให้เปิดไฟล์ app/containers/ResultsContainer.js แล้วแก้ Code ดังนี้

จากนั้นก็ลองเข้าไปทดสอบกับระบบจริงดูด้วยตนเอง

UserDetails and UserDetailsWrapper refactoring

เปิดไฟล์ app/components/UserDetails.js ขึ้นมา แล้วแก้ code ดังนี้

เปิดไฟล์ app/components/UserDetailsWrapper.js ขึ้นมา แล้วแก้ code ดังนี้

ConfirmBattleContainer refactoring

ให้เปิดไฟล์ app/containers/ConfirmBattleContainer.js ขึ้นมาแล้วแก้ไฟล์ดังนี้

MainContainer refactoring

เปิดไฟล์ app/containers/MainContainer.js ขึ้นมาแล้วแก้ code ดังนี้

githubHelpers refactoring

ตัวสุดท้ายที่เราจะทำการ Refactoring ก็คือ app/utils/githubHelpers.js ซึ่งผมขอเป็นแบบฝึกหัดให้ทุกคนไปแก้ในส่วนของ import/export  กันนะครับ

แล้วอย่าลืมทดสอบระบบด้วยนะครับ

ในกรณีที่อยากจะดู code ต้นแบบ สามารถเข้าไปดูได้ที่

https://github.com/himaeng/react-fun-course/tree/master/ES01-import-export

สรุป

คอร์ส ES6 for React นี้เป็นคอร์สสั้นๆ ที่จะสอนให้ทุกคนมีความคุ้นเคยกับ ES6 โดยเราจะเน้นไปที่ ฟีเจอร์ของ ES6 ที่จะถูกนำมาใช้กับ React

เนื้อหาในบทนี้จะพูดถึงเรื่องของการ import และ export โดย ES6 จะประกอบด้วยสองแบบคือ named import/export ซึ่งเวลา import จะต้องครอบตัว item ที่เรา import เข้ามาด้วย { }

ส่วนอีกแบบหนึ่งก็คือ default import/export ซึ่งเวลา export จะต้องระบุด้วยว่า

แล้วเวลา import ก็ import ชื่อของ item ตรงๆ ไม่ต้องครอบด้วย { }

1 COMMENT