ภาพรวมโปรเจ็กท์

Project Walkthrough

โปรเจ็กท์ที่เรากำลังจะสร้างภายในคอร์สนี้ชื่อว่า albums (เราได้สร้างเอาไว้ในตอนที่แล้ว) โดยภายในโปรเจ็กท์ดังกล่าวนี้ จะมีโครงสร้างของ folder และ file ดังนี้

folder __tests__ เป็นโฟลเดอร์สำหรับเก็บ test code ต่างๆ ของโปรเจ็กท์เอาไว้ ซึ่งหากต้องการจะรัน test ของโปรเจ็กท์ เราสามารถรันคำสั่งดังต่อไปนี้ได้ใน root path ของ project

เมื่อรันแล้วผลออกมาจะเป็นดังนี้

screen-shot-2559-11-20-at-8-38-51-am

ซึ่งถือเป็นการรัน test code ตัวอย่างทั้งของ android และ ios โดยในที่นี้เราใช้ test framework ที่ชื่อ jest (ซึ่งถูกติดตั้งพ่วงมากับ React Native ด้วย) ในการรันเทสต์

folder android\ และ ios\ นั้น คือโฟลเดอร์ที่เก็บ code สำหรับ Android และ IOS ตามลำดับ โดยภายในโฟลเดอร์ทั้งสองนี้แท้ที่จริงแล้วก็คือ project Native ของแต่ละแพลตฟอร์ม เช่น folder android\ คือโปรเจ็กท์ของ Android Studio และ ios\ คือโปรเจ็กท์ของ xCode

เวลาที่เราทำงานผ่าน React Native นั้น มีน้อยครั้งมากที่เราจะเข้าไปแตะต้อง หรือเปลี่ยนแปลง code ภายในทั้งสองโฟลเดอร์ ซึ่งหากจะมีบ้างก็เป็นส่วนของการติดตั้งพวก native component หรือการ config อะไรบางอย่าง (เช่นการ config compile SDK ใน android\  ตอนที่เราติดตั้ง android Emulator เป็นต้น)

ส่วน node_modules คือโฟลเดอร์ที่เก็บ dependencies module ต่างๆ ที่เราต้องใช้ในโปรเจ็กท์ ซึ่งก็เหมือนกับ android\ และ ios\ ที่เราแทบไม่จำเป็นต้องเข้าไปแตะต้องข้อมูลข้างในแต่ประการใด เช่นกัน

ไฟล์หลักที่มีความสำคัญสำหรับ React Native นั้นก็คือ index.android.js และ index.ios.js

ในยามที่ทำการ build android project ระบบของ React Native จะนำเอา code ภายใน index.android.js ไปรัน และเช่นกัน การ build ios project ก็ต้องใช้ code ภายใน index.ios.js ทั้งสองไฟล์นี้อาจจะเริ่มต้นโดยมี code ที่เหมือนกัน แต่เมื่อพัฒนาไปเรื่อยๆ ก็อาจจะมีบางส่วนที่เริ่มแตกต่างกัน แต่สำหรับ course นี้ จะพยายามให้ code ทั้งของฝั่ง android และ ios มีความเหมือนกันให้มากที่สุด เพื่อให้ระบบมีความเป็น cross platform ให้มากที่สุดเท่าที่จะทำได้

โดยสรุปก็คือ ทั้งสองไฟล์นี้คือ entry point ของโปรเจ็กท์ใน React Native นั่นเอง

สำหรับตอนเริ่มต้นนี้ เราจะทำการเคลียร์ code จากทั้งสองไฟล์ให้เกลี้ยง นั่นคือ ลบ code ทั้งหมดภายในทั้งสองไฟล์นี้ให้หมด เพราะเราจะเริ่มต้นเขียน React Native กันตั้งแต่ code ตัวแรกกัน

เริ่มสร้าง content แรก

เราจะเริ่มกันแบบ step-by-step นะครับ ให้เปิดไฟล์ albums/index.android.js ขึ้นมาแล้ววางโครงสร้างของ code ไว้ดังนี้

และเปิดไฟล์ albums/index.ios.js ขึ้นมาแล้ววางโครงสร้างของ code ไว้ดังนี้

หมายเหตุ: สำหรับคนที่จะพัฒนาแต่ ios ก็ให้เล่นแต่ไฟล์ index.ios.js เท่านั้น ส่วนใครจะสร้าง android app. ก็เล่นแค่ไฟล์ index.android.js ก็พอ แต่สำหรับคนที่จะสร้างทั้งสองระบบ ก็ให้เล่นทั้งสองไฟล์ไป 

หมายเหตุ 2: จากนี้ไปผมจะเล่นแต่ ios เท่านั้น ซึ่ง code ทั้งหมดสามารถเอาไปรันใน android ได้แบบ 100% ยกเว้นหากมีส่วนที่ต้องเขียน code ให้แตกต่างจริงๆ ก็จะระบุเป็นส่วนๆ ไป

ให้ทำการเพิ่ม code ใน albums/index.ios.js ในส่วนของ import (step 1) ดังนี้

สำหรับ React Native นั้นเราจะต้อง import สอง modules เป็นฐาน นั่นคือ react และ react-native มาใช้ โดย react module จะรับผิดชอบในเรื่องของภาพรวมการทำงานของ component ต่างๆ และช่วยให้ component ต่างๆ ทำงานร่วมกันได้อย่างราบลื่น

ส่วน react-native module จะรับผิดชอบในการวาด component บนหน้าจอ และมีพวก component พื้นฐานต่างๆ อย่าง <image/>, <text/> เป็นต้น แถมมาให้

คราวนี้ได้เวลาเติม code ในขั้นที่สอง (สร้าง component) และขั้นที่สาม (Render บนอุปกรณ์ IOS) กันแล้ว

ในขั้นตอนที่สองนั้น เราเลือกใช้วิธีสร้าง component แบบ Stateless Functional (ผมได้กล่าวถึงวิธีการสร้าง component แบบนี้เอาไว้ในคอร์ส React Basic ไว้แล้ว) โดยใช้วิธีเขียนฟังก์ชั่นแบบ Arrow Function (สามารถไปหาอ่านได้ในคอร์ส ES6 for React ได้เช่นกัน) ซึ่งในที่นี้ App component ไม่มีการรับ argument เราจึงเขียนดังนี้

ซึ่งเวลาเราเขียน Arrow Function สิ่งแรกที่ต้องระบุก็คือ argument ซึ่งหาก มันไม่มี argument ก็ให้ใส่เป็น วงเล็บว่างๆ ไว้แบบ code ข้างต้น

ส่วนในขั้นตอนที่สาม จะเป็นการ register component สำหรับ mobile app โดยทำผ่าน registerComponent อันเป็นฟังก์ชั่นที่รับ parameter สองตัว ตัวแรกคือ Application key ซึ่งในที่นี้เราเลือกใช้ชื่อของโปรเจ็กท์ ส่วนตัวที่สองคือ callback function ที่ return component หลักออกมา นั่นหมายความว่า หนึ่งโปรเจ็กท์จะมี component หลัก เพียงตัวเดียวเท่านั้นที่ถูกนำมา render ไว้บน mobile app.

หากสังเกตให้ดี ผมได้ทำการ refactor การ import react-native โดยใช้วิธี destructuring เพื่อดึง Text และ AppRegistry มาใช้โดยตรง

จากนั้นให้เปิด terminal เข้าไปที่ root path ของ albums แล้วพิมพ์คำสั่งต่อไปนี้

สำหรับคนที่พัฒนา android ให้รันคำสั่งต่อไปนี้

หากไม่มีข้อผิดพลาด เราจะเห็นภาพนี้

screen-shot-2559-11-21-at-6-51-41-pm

คราวนี้ก่อนจะไปต่อ เรามาดูกันซักหน่อยดีกว่าว่า หน้าตาของ app. ที่เราจะสร้างมันเป็นอย่างไร

Mockup

เรากำลังจะสร้างระบบที่มีหน้าจอดังต่อไปนี้

screen-shot-2559-11-21-at-6-57-44-pm

นั่นคือ โดยหลักๆ แล้ว เราจะมีสอง component ใหญ่ๆ นั่นคือ Header กับ Card โดยภายใน Card component เราจะแบ่ง ui ออกเป็น section ต่างๆ

ดังนั้น component แรกที่เราจะสร้างก่อนเพื่อนก็คือ Header

Header component

ก่อนที่จะสร้าง component แรกของเราขึ้นมา ให้ทำการจัดทำโครงสร้าง folder ให้พร้อมสำหรับการพัฒนาเสียก่อน โดยภายใต้ albums ให้เราสร้าง folder src ขึ้นมา

โดย folder src\ นี้ มีไว้เก็บ source code ทั้งหมดของโปรเจ็กท์ จากนั้นให้เราสร้าง folder ที่ชื่อว่า components\ ไว้สำหรับเก็บ component ทั้งหมดของโปรเจ็กท์

ณ ที่แห่งนี้ เราจะทำการสร้าง component ตัวแรกของเราขึ้นมา ชื่อว่า header.js

จากนี้ไป แต่ละ component ที่เรากำลังจะสร้าง จะต้องประกอบด้วยขั้นตอนหลักๆ อย่างน้อย 3 ขั้นตอนดังนี้

ก่อนอื่นเรามาเติม code ในขั้นตอนที่ 1 และ 2 กันก่อน ดังนี้

คราวนี้เรามาว่ากันที่ขั้นตอนที่ 3 กัน นั่นคือ การเปิดให้ component ตัวอื่นสามารถนำ Header component ไปใช้ได้

เนื่องจากตอนนี้โปรเจ็กท์ albums ได้สร้าง App component ขึ้นมาทำหน้าที่เป็น root component ดังนั้น ทุกๆ component ที่เราจะสร้างในโปรเจ็กท์ต่อจากนี้ไปจะต้องมีศักดิ์เป็นลูกของ App เป็นอย่างน้อย

และความสัมพันธ์ระหว่าง App component กับ Header component จะเป็นไปดังรูป

screen-shot-2559-11-21-at-7-31-19-pm

ดังนั้น เราต้องเปิดให้ Header ถูกเรียกใช้จาก App component ได้ อีกประการหนึ่ง หากยังจำกันได้ ภายใน App component เราได้ทำการ register component เพื่อให้มัน render ไปบน mobile screen และ React Native จะยอมให้มีการ register เพียงหนึ่ง component เท่านั้น นั่นคือ root component ดังนั้น เราจึงต้องให้ component ทุกตัวจากนี้ไปต้องมีศักดิ์เป็นลูกของ App เท่านั้น

จากนั้นให้เราเขียน code ภายในขั้นตอนที่ 3 ให้สมบูรณ์ ดังนี้

จากนั้นเปิดไฟล์ index.ios.js (หรือ index.android.js ในกรณีของ android) ขึ้นมา แล้วเปลี่ยน code ดังนี้

เนื่องจากงานนี้ เราไม่จำเป็นต้องใช้ Text component ของ react-native module แล้ว เราจึงทำการตัด Text ออกจากการ import เพราะเราเปลี่ยนการใช้ <Text> มาใช้ <Header> แทน

จากนั้นให้เปิด emulator แล้วทำการ refresh หน้าจอ ก็จะเห็น text เปลี่ยนไปเป็น Album! (อาจจะมองไม่ชัด เพราะมันดันไปซ้อนอยู่กับตัวอักษรตรงมุมซ้ายบน)

ตกแต่ง component ด้วย style

ใน React Native นั้น การจะตกแต่งหน้าจอนั้น สามารถใช้ Javascript object เพื่อการนี้ได้ คล้ายๆ กับ React Dom (React สำหรับเว็บ)

เราจะมาตกแต่ง Header component โดยเปิดไฟล์ albums/src/components/header.js ขึ้นมาแล้วปรับแก้ code ดังนี้

จาก code ข้างต้น ได้มีการเพิ่มตัวแปรแบบ const ชื่อว่า styles ขึ้นมาเพื่อนำมาใช้ภายใน component

จุดที่อยากให้สังเกตก็คือ การเปลี่ยนแปลงภายใน code ของ Header component ก็คือเราได้ทำการเปลี่ยนแปลงรูปแบบของ arrow function

จาก code เดิมของ Header

มาเป็น

จะเห็นว่า ตัว arrow function ของ code บน กับล่างจะต่างกันตรงที่ code บนจะใช้ ( ) มาครอบ code ภายใน และไม่ต้องมีการระบุคำว่า return ซึ่งเป็นสิ่งที่ ES6 จัดเตรียมไว้ให้เราเพื่ออำนวยความสะดวกในการเขียน code ที่มี return จาก code เพียงบรรทัดเดียว ทาง ES6 จะอนุญาติให้เราไม่ต้องครอบ { } และไม่ต้องระบุคำว่า return ใน code ก็ได้

แต่สำหรับ Arrow function ที่มีหลาย expression จำเป็นจะต้องครอบด้วย { } และระบุ return เอาไว้

ครอบ text ด้วย View component

กลับมาดูที่ wireframe อีกครั้งหนึ่ง

screen-shot-2559-11-21-at-6-57-44-pm

จะเห็นว่า Header นั้นตำแหน่งของคำว่า Albums จะอยู่ตรงกลางของ component ซึ่งหากเราต้องการจะทำเช่นนั้น เราก็จะต้องหา component อะไรซักตัวมาครอบ <Text> ไว้

สำหรับ React Dom นั้นเรามี <div> component (แบบเดียวกับ <div> ของ html) แต่สำหรับ React Native เราจะใช้ <View> แทน ดังนี้

screen-shot-2559-11-21-at-8-19-08-pm

ดังนั้นเราจะต้องปรับ code ใน Header ใหม่เพื่อให้ <Text> ถูกครอบโดย <View> ดังนั้นให้เปิดไฟล์ albums/src/conponents/header.js แล้วปรับ code ดังนี้

คราวนี้หากเราเปิด emulator แล้วทำการ refresh หน้าจอ จะตัว component จะมีสี background เป็นสีเทา ตามที่เราตกแต่งเอาไว้

จัดตำแหน่ง component ด้วย Flexbox

React Native จะใช้ Flexbox ในการจัดตำแหน่ง component ต่างๆ ในหน้าจอ ซึ่ง Flexbox ใน React Native นั้นจะใช้ property อยู่สองตัว นั่นคือ justifyContent สำหรับจัดตำแหน่งในแนวดิ่ง (vertical) และ alignItems สำหรับจัดตำแหน่งในแนวระนาบ (horizontal)

component ทุกตัวนั้น จะมีตำแหน่งโดย default อยู่ที่มุมซ้ายบน ดังรูป

screen-shot-2559-11-21-at-8-56-24-pm

หากเราปรับค่า justifyContent ให้เป็น ‘flex-end’ มันจะทำการจัดวางไว้ที่ด้านล่างสุดในแนวดิ่ง ดังรูป

screen-shot-2559-11-21-at-8-57-18-pm

หากเราปรับ justifyContent ให้มีค่าเป็น ‘center’ มันจะปรับให้ component อยู่ตรงกึ่งกลางตามแนวดิ่ง ดังรูป

screen-shot-2559-11-21-at-8-57-54-pm

และหากเราปรับค่า justifyContent ให้เป็น ‘flex-start’ มันจะปรับให้ component อยู่ในตำแหน่งด้านบนสุดตามแนวดิ่ง ดังรูป

screen-shot-2559-11-21-at-8-58-04-pm

ส่วนค่า alignItems หากเราปรับให้มีค่าเป็น ‘flex-start’ มันจะจัดวาง component ไว้ด้านซ้ายสุดในแนวระนาบ ดังรูป

screen-shot-2559-11-21-at-8-58-30-pm

หากเราปรับให้ alignItems มีค่าเป็น ‘center’ มันจะจัดวาง component ไว้ตรงกลางในแนวระนาบ ดังรูปscreen-shot-2559-11-21-at-8-58-50-pmและหากเราปรับให้ alignItems มีค่าเป็น ‘flex-end’ มันจะจัดวาง component ไว้ตรงด้านขวาในแนวระนาบ ดังรูป

screen-shot-2559-11-21-at-8-58-59-pm

ดังนั้น ให้เรานำความรู้ที่ได้มาปรับแต่งการแสดงผลของ Header component ดังนี้

ในที่นี้เราจะปรับ text อยู่ตรงกลางทั้งในแนวดิ่ง และแนวระนาบ รวมทั้งมีการปรับแต่งค่าแสงเงาเพื่อเพิ่มความดูดีให้กับ Header อีกด้วย

หมายเหตุ: elevation ใช้สำหรับ android เท่านั้น ใช้สำหรับแสดงค่า แสงเงาที่สอดคล้องกับตำแหน่งการจัดวาง component ในแกน z (z-ordering) มีค่าเป็นตัวเลขจำนวนเต็ม

เมื่อทำการ refresh หน้าจอ emulator จะเห็นภาพดังนี้

screen-shot-2559-11-21-at-10-06-49-pm

Refactor เพื่อ reusability

เราจะใช้ props เพื่อทำให้ Header component สามารถนำไป reuse ได้มากขึ้น โดยคำที่ปรากฎอยู่บน Header สามารถเปลี่ยนแปลงได้อย่างยืดหยุ่น โดยให้เราทำการปรับ code ใน albums/src/components/header.js ดังนี้

จาก code ข้างต้นเราจะใช้ props ชื่อ headerText ที่รับมาจาก component แม่ (App component) มาใช้ในการแสดงผลเป็น text หลัก นอกจากนี้เรายังจะต้องทำ document ด้วยการสร้าง proptypes ขึ้นมาอีกด้วย

จากนั้นให้เปิดไฟล์ index.ios.js (หรือ index.android.js) ขึ้นมา แล้วแก้ code ดังนี้

ซึ่งนั่นจะทำให้ text ที่แสดงบน Header มีค่าเท่ากับ ‘Albums’ นั่นเอง

screen-shot-2559-11-21-at-10-36-34-pm

สรุป

เนื้อหาในตอนนี้เป็นการสร้าง component ขึ้นมาตามหลักการทั้งหมดที่เคยพูดไว้แล้วภายใน React Basic course หากท่านใดยังไม่ได้อ่าน tutorial ทั้ง 12 ตอนภายใน course ดังกล่าว ผมขอแนะนำให้กลับไปอ่านให้จบเสียก่อนมาเริ่มศึกษาตาม tutorial ในชุด React Native นี้