ที่สุดของการทำ Mobile Applicationให้หยุดที่ FFR (Flutter , Firebase & Redux)

References (ลอกมาบ้าง ดูเป็นตัวอย่างบ้าง เรียบเรียงใหม่บ้าง)

ขอกราบบุคคลทุกท่านที่ช่วยกันพัฒนา Developer คร๊าบบบ

Introduction

บทความนี้ยาวมากๆ นะครับ เรียกว่าผมเขียนไว้อ่านและใช้เองเลยก็ได้ คิดว่าใช้ความเข้าใจเยอะมากๆ และผมอาจจะไม่ได้ลงลึกในเนื้อหาอะไรไปบ้าง ข้ามอะไรไปบ้างก็ขออภัยมา ณ.ที่นี้เลยนะครับ คิดซ่ะว่าผมเป็นคนต่อ Lego ที่ประกอบไปด้วย Lego 3 ชิ้นใหญ่ๆ คือ Flutter , Firebase และ Redux ส่วนถ้าอยากจะเข้าใจว่า Lego แต่ละชิ้นมีที่มายังไง รบกวนค้นคว้าต่อเองนะคร๊าบบบ ยินดีรับคำติชม แก้ไข และ ปรับปรุงทุกประการ คุณภาพของ Code อาจจะไม่สวยงามมากเท่าไหร่ เน้นใช้งานและอธิบายเป็นหลัก ผมใช้พลังงานในการเขียนบทความนี้มากนะครับ เพราะผมเห็นว่าเป็นเรื่องที่สำคัญมาก และสามารถทำให้บริษัท Software เล็กๆ หรือ StartUp รายย่อยๆ สามารถทำ Mobile Application เพื่อทำให้โลกนี้น่าสนใจมากขึ้นเนอะ 555+

  1. คงไม่ต้องอธิบายมากแล้วนะครับว่า Flutter คืออะไร ยังไงใครจะอ่านบทความนี้ต่อต้องเขียน Flutter ได้บ้างนะครับ ไม่งั้นไม่มีประโยชน์ ถ้าไม่เข้าใจไป Search มาก่อนว่า Flutter คืออะไร นะครับ ตอนนี้มี Framework หลายตัวเอาไว้ใช้ พัฒนา Mobile Application นะครับ ผมแนะนำว่า ณ ขณะที่เขียนอยู่ให้เลือกแค่ 2 ตัวพอนะครับ “Flutter VS React-Native” ยังอยากศึกษาเพิ่มเติมอยู่ไปหา Course เรียนนะครับ คนทำ Course ดีๆ และฟรีด้วย เช่น https://www.udacity.com/course/build-native-mobile-apps-with-flutter--ud905 (อันนี้ Official จาก google เองเลยครับ) เช่น http://androidthai.in.th/android-flutter (อันนี้ผมว่าเจ้าของบทความเค้าทำแยกๆ เป็น ส่วนๆ เล็กๆ เหมาะกับการเอามาประติดประต่อกันดีครับ เป็นภาษาไทยด้วย) บางคนอ่านมาถึงตรงนี้อาจจะสงสัยว่าที่เคยรู้ๆ มา ถ้าเขียน App บน IOS ใช้ Xcode พัฒนาด้วยภาษา Objective-C , Swift ? เปล่า ถ้าเขียน App บน Android ใช้ Android Studio พัฒนาด้วยภาษา Java , Kotlin ? เปล่า คือจริงๆ ถ้ามีทีมที่ใหญ่พอ มีคุณภาพพอ เวลามากพอ เขียน Native แยกไปแต่ละ Platform อาจจะเป็นคำตอบของคุณมากกว่านะครับ แต่ผมอยากทำทีเดียวจบอ่าครับ :)
  2. ทำไมต้องใช้ Firebase … ไม่พูดอีกเช่นกันนะครับ ถ้าอยากจะทำ Application ที่สามารถจบที่ทีมเล็กๆ รีบออกผลงาน เน้น Fail Fast Fail Often ถ้าไม่ใช้ firebase แล้วใช้อะไร ??? มีเนื้อหาสอนเฉพาะที่ใช้ Firebase Cloudstore กับ Flutter ตรงๆ นะครับ หากอยากดูแค่ 2 ส่วนนี้ตาม Link ไปได้เลย https://codelabs.developers.google.com/codelabs/flutter-firebase/#0 แต่ทำ Application จริงๆ รองรับไอเดียอันมหาศาลของ CEO Start up สมัยนี้ ผมว่ายังไงก็ไม่พอครับ
  3. สุดท้ายทำไมต้องใช้ Redux … ตอบบบบ มันยากดีครับ ใช้แล้วดูเท่ห์ 555+ ซึ่งจริงๆ หลังจากค้นคว้าเพิ่มผมว่าใช้อันอื่นเถอะครับ ถ้าไม่ได้เคยเขียน Redux กับ React มาก่อนแนะนำ ให้ไปใช้ Bloc ,Scoped Model , Flutter flux นะครับ หรือ ลอง Search ดูว่าเค้าใช้อะไรกัน ลอง Search google ว่า “Flutter State Management” แต่ถึงยังไงก็ต้องมีการใช้อะไรบางอย่างเพื่อการจัดการ State นะครับ จำเป็นสุดๆ เว้นว่า App คุณเล็กมากๆ เล็กมากๆ จนไม่รู้จะทำ App มาเพื่ออะไร ผมว่าไม่ต้องใช้ก็ได้ครับ 555+ ปล. อ่านมาถึงตรงนี้ใครงง ว่า State คืออะไร …. ปิดบทความนี้ทิ้งเลยครับ … เดี๋ยวธาตุไฟจะเข้าแทรก แต่ถ้ายังดันทุรังอยู่จะอธิบายให้คร่าวๆ State ของ Flutter เรียกได้ว่าได้แรงบัลดาลใจมากจาก State ของ React (จริงๆ คือลอกมาเลย) Concept ของ State (นิยามส่วนตัว) คือ ชุดของตัวแปร ณ ขณะใดขณะหนึ่ง โดยเมื่อชุดของตัวแปรมีการเปลี่ยนค่าไปโดยคำสั่ง setState จะไปบังคับให้ UI ของ Application เรา Render ใหม่โดยอัตโนมัติ …. อธิบายได้แค่เนี้ย ให้อยากรู้เรื่องเยอะกว่านี้ผมแนะนำไปเล่น React นะครับ :)

Chapter I — Knowledge Preparation

ขอกล่าวถึงหลักการทำ Application ที่ส่วนตัวผมมองก่อนนะครับ หลักๆ มันจะต้องมี Frontend (คือหน้าตาที่ให้ผู้ใช้ Application ได้ใช้งาน) และ Backend (คือส่วนที่ทำให้ Application ทำงานได้จริงๆ) บาง App ถ้ามันเล็กมากไม่ต้องมี Backend ก็ได้แต่ถ้าอย่างนั้นก็ไม่ต้องทำหรอกครับ ผมว่า Search หาดีๆ ก็มีคนทำให้แล้ว

Frontend ที่เลือกใช้คือ Flutter
Backend ที่เลือกใช้คือ Firebase (ในส่วนเนื้อหานี้จะพูดแค่ส่วนของ Cloud Firestore เท่านั้นนะครับ)

ข้อดีของการใช้ Service Firebase ทางอ้อมคือ ต่อไปแทบไม่ต้องทำอะไรเองเลย เพราะมี Service ที่เตรียมไว้ใช้กับ Firebase เยอะมากกกก ที่ต้องใช้แน่ๆ คือ Firebase Authentication จะมาเสียเวลาเขียนเองทำเพื่อ ??? แล้วมีคนเขียนบทความ Firebase Authentication ด้วย Application Line ไว้อีก โอ้จบนะ ผมจะไม่ขอพูดถึงเรื่องค่าใช้จ่ายนะครับอันนี้เป็น Bussiness Decision ที่ผมจะไม่ขอยุ่งนะครับ เอาเป็นว่า ทดลองทำฟรีจนถึง Production แล้วถ้าต้องถึงขั้นจ่ายเงินแล้ว ยังไม่มีจ่ายผมว่าเลิกทำ app นั้นเถอะครับ เคยมี GDE (Google Developer Expert) คนนึงพูดไว้ผมจำไม่ได้ละว่าใคร แต่ขอยกคำพูดเค้ามาล่ะกันเท่ห์ดี

ถ้าใช้ Firebase ถึงขั้นเสียเงินแล้วแต่ยังไม่มีรายได้จากการทำ applcation ความผิดไม่ได้อยู่ที่ Firebase แล้วละ ความผิดอยู่ที่ application คุณ

https://medium.com/linedevth/%E0%B8%AA%E0%B8%A3%E0%B9%89%E0%B8%B2%E0%B8%87%E0%B8%A3%E0%B8%B0%E0%B8%9A%E0%B8%9A-firebase-custom-authentication-%E0%B8%94%E0%B9%89%E0%B8%A7%E0%B8%A2-line-login-v2-1-42f7dc35c9bb

https://github.com/flutter/plugins/blob/master/FlutterFire.md

Cloud Firestore

หลักๆ มันคือ NoSQL Database ที่มัน Query ได้ และแถมทำงาน Offline ได้ด้วย (ยังไม่ได้ดูจริงจังนะครับ คือ มันสามารถ sync Online กับ Offline Database ได้เวลา Net พัง) คือปกติแล้ว ถ้าเป็น NOSQL ส่วนใหญ่จะ Query ลำบาก ผมคิดว่า Cloud Firestore ทำมาเพื่อแก้ปัญหาจุดนี้เลย โดย Cloud firestore น่าจะถูกพัฒนามาจาก Firebase Realtime Database ด้วย ถ้าใครเมพจัดผมแนะนำนะครับ ใช้ Firebase Realtime Database คู่กับ Cloud Firestore เลย เรียกว่าถ้าจัดการดีๆ ผมว่า ต่อให้ User เป็นแสนคน ยังน่าจะไม่เสียเงินเลยครับ ปล.ตอนที่เขียนบทความอยู่ Cloud Firestore ยังเป็น Beta อยู่นะ … ข้อเสียก็มีนิดหน่อย ที่ผมเจอชัดๆคือ มัน Export JSON ออกมายังไม่ได้ ไม่เหมือน Firebase Realtime Database สรุปก็เอาไว้เก็บข้อมูลแหละ หน้าตาก็จะประมาณนี้

พอเป็นแบบนี้ก็คุยกันง่ายละ ต่อไปอยากจะทำ Web ก็สามารถเก็บข้อมูลเข้าที่เดียวได้เลย เบ็ดเสร็จ ผมยังคิดไม่ออกจริงๆ ว่าถ้าไม่ใช้ Firebase ผมจะใช้อะไรมาทดแทนได้

Redux

http://codesheep.io/2017/01/06/redux-architecture/

ใครเห็นภาพนี้แล้ว ตกใจผมแนะนำว่าปิดบทความนี้นอนเลยครับ 555+ เอาจริงๆ ผมไม่กล้าอธิบาย Redux เลย เคยสอนก็แล้ว ผมว่าไม่มีใครเข้าใจที่ผมสอน เอาจริงๆ ผมว่าผมเองก็ยังไม่เข้าใจมัน 100% เลย แต่ผมว่ามันเท่ห์ดี 555+ ตามไปอ่านบทความใน Link รูปภาพเด้อ จาก ท่านอดีตนายกสมาคมโปรแกรมเมอร์ไทย คุณ Ping … ตอนนี้ไปอยู่ Facebook ละ :) อธิบายไว้ดีมาก ผมอ่านประมาณ 10 รอบละ

มาถึงตรงนี้ผมจะติต่างว่าผู้อ่านทุกท่านพอเข้าใจ Redux แบบผิวเผินนะครับ ไม่งั้นมันจะอธิบายไม่จบไม่สิ้น จะขออธิบายในส่วนที่มีปัญหาสำหรับการใช้ Redux กับ Firebase ก่อนนะครับ ก่อนอื่นคือ ขอเกริ่นก่อนว่า ถ้าใช้ Redux เฉยๆ รูปมันจะเป็นแบบนี้

http://codesheep.io/2017/01/06/redux-architecture/

อันนี้คือแบบ ไม่คิดจะเรียก API จากภายนอกเลย ซึ่งมันไม่มีทางเป็นไปได้อยู่แล้วจริงมั้ยครับ ??? แต่ก็ต้องอธิบายก่อน จากรูปกล่าวคือถ้า มีการกดอะไรบางอย่างมาจากหน้า UI ภายใน Application (ใน React เรียก View (Component) ใน Flutter เรียก Widget) ระบบจะทำการส่งคำสั่งผ่าน methode dispatch เพื่อ ส่ง action ไปที่ Reducer แต่เนื่องจากเราใช้ Firebase ด้วยเพราะฉะนั้น มันจะวุ่นวายตรง dispatch จะต้องทำหน้าที่ส่ง action ขึ้นไปที่ Firebase ก่อน รูปมันจึงเป็นแบบนี้

มันก็มี Middleware มาเสียบเพื่อให้ Firebase ทำงานได้แล้วเมื่อได้รับผลจาก Firebase มาค่อยส่งเป็น action object เพื่อไปยัง Reducer เพื่อทำงานต่อปายยย

Chapter I — Flutter with Redux(Only)

เพื่อเป็นการปูพื้น Redux ไปในตัวผมจะขออธิบาย Redux ให้ฟังคร่าวๆ พร้อมกับ Flutter ไปเลย ทุกคนสามารถ Clone มารันดู แล้วอ่านตามได้เลยครับ เริ่มต้นด้วยการทำจากตัวอย่าง official counter ของ Flutter เลยนะครับ และค่อยๆ ทำการ เปลี่ยนมาเป็น Redux อย่างสมบูรณ์ (สามารถข้ามไป Chapter-II ได้เลยนะครับถ้าคล่อง Redux แล้ว) แต่ถ้าอยากทบทวนก็ตามๆ อ่านมานะครับ จะพยายามเขียนแบบง่ายที่สุดเท่าที่จะทำได้

ถ้าใครขี้เกียจ Clone เอาเลยครับ

git clone https://github.com/taforyou/flutter_redux_counter_example

ถ้าอยากค่อยๆ ทำตามก็เริ่มเลยครับ ผมใช้ mac เลยเปิด terminal นะครับ ใครใช้ windows ก็ตามสบายเด้อ

flutter create flutter_redux_counter_medium

รอไปสักแปปเด้ออออ ได้หน้าตาประมาณนี้นะ เสร็จแล้วพิมพ์คำสั่งสุดเท่ห์หลังจาก Cd เข้าไปใน folder ที่เพิ่งสร้างขึ้นมา (ในที่นี้คือ flutter_redux_counter_medium)

Code .

เพื่อเปิด Editor ขึ้นมา คือ จริงๆ จะพิมพ์ Flutter run เลยก็ได้นะครับ แต่ผมชอบไปทำใน Visual Code มากกว่าเพราะมันมี Terminal อยู่ข้างในแล้ว

ปล.ผมใช้ Genymotion เป็น Emulator นะครับ ใช้เครื่อง Samsung Galaxy S8–7.0.0 API 24 1440x2960 และ VSCODE เป็น IDE + Editor นะครับ ใครสะดวกใช้ Android Studio ก็อาจจะดีกว่าก็ได้นะ :)

รอไปสักแปปเด้ออออ เพื่อฟามชัวร์ลองรันหนึ่งรอบ พิมม์คำสั่งใน Terminal ถ้าใช้ VSCODE นะครับ แต่ถ้าใช้ Android Studio กด ปุ่ม Play มั้งครับถ้าจำไม่ผิด

flutter run

ไม่ว่าจะ Emulator หรือ Devices จริง ที่ควรจะได้หน้าตาตาม Step จะได้ประมาณนี้นะครับ เอ้อ อย่าลืมเปิด Genymotion ขึ้นมาด้วยนะครับ สักเกตุดีๆ ตรงขวาล่าง(ตามรูป) จะเขียนชื่อ Devices ที่กำลังเปิดอยู่ด้วย

ลองกด + เล่นดูนะครับ จะเห็นว่าตัวเลขจะเพิ่มขึ้น

Tips เล็กน้อย หากไปที่ Terminal ใน VSCODE หากกด r (ตัวเล็ก) จะทำการสั่งสั่งให้ Application ที่ Build มาแล้ว Hot Reload กล่าวคือ ไมต้องบิ้ว Application ใหม่ทำให้ประหยัดเวลามากๆ เวลาอยากจะแก้ไขอะไร แต่หาก Hot Reload เองไม่ได้ทำการ Reset State ภายใน application หากอยากให้ State Reset ด้วยให้กด R (ตัวใหญ่ Shift + r) จะทำการสั่ง Restart Application หากอยากลองเล่นลองกด + ไปเรื่อยๆ หากลองกด r เล็ก จะเห็นว่า ตัวเลขไม่กลับเป็น 0 หากแต่กด R ใหญ่ ตัวเลขจะถูก Reset กลับไป 0 ครับผม

จากนี้ต่อไปเราจะมาเริ่มการถอดชิ้นส่วนออกมาเพื่อแปลงเป็น Redux แล้วนะครับ มี 2 ส่วนหลักๆ คือ

  1. เลข 0 ที่แสดงออกมาเกิดจาก State ภายใน Application
รูปภาพที่แสดงเลขจากตัวแปร _counter ที่เก็บภายใน State ของ Class _MyHomePageState
การนำค่าจาก State มาแสดงผล

จากรูปจะเห็นได้ว่า Application นำตัวแปรที่ชื่อ _counter ซึ่งอยู่ภายใน widget ที่มี State เป็นของตัวเองเพื่อนำค่าของ _counter มา Show

class ที่เป็น StateFull (คือสามารถเก็บ State ได้)

2. ปุ่ม + เป็นการเรียกคำสั่ง setState เพื่อเพิ่มเลขและทำให้เลขที่แสดงเปลี่ยนไป

ปุ่มที่สามารถกดเพื่อเพิ่มเลขได้
widget ที่แสดงปุ่มกดภายใน Application เมื่อกดปุ่มจะทำการเรียก function _incrementCounter
function _incrementCounter ที่สั่ง setState โดยที่ทำให้ตัวแปร _counter ภายใน class เพิ่มขึ้นทีละ 1

จากรูปด้านบนจะเห็นได้ว่าสิ่งที่เราจะต้องทำการถอดและแปลงมาเพื่อใช้ Redux มีอยู่ 2 ส่วน โดยจากตัวอย่างนั้นตัวเลขที่ Show ใน widget แต่เดิมเราเอาค่ามาจาก State แต่หากเป็น Redux แล้ว ตัวเลขที่ Show เราจะนำมาจาก store และหากเราจะต้องการเพิ่มเลขไป เราจะต้อง dispatch Action ขึ้นไปที่ Reducer ที่อยู่ภายใน Store เพื่อทำการบอกให้เพิ่มเลขขึ้นไปและ Widget ที่อยู่ภายใน Store จะทำการเปลี่ยนค่าตามที่ Store มีการแก้ไข ดังภาพการทำงานของ Flux ดังนี้

http://www.siamhtml.com/getting-started-with-flux/

จากภาพให้มองว่า View = Widget ไปเลยครับ มาลุยกันต่อเลยนะครับ ก่อนจะเริ่มการผ่าตัดแยกชิ้นส่วนเรื่องต่อไปเป็นเรื่องที่ผมปวดหัวมากพอสมควร คือการจัดเรียง Folder เพื่อให้รองรับการเติบโตของ Application ในอนาคต แม้แต่ท่านศาสดา Dan Abramov เองก็บอกว่า จัดๆ ไปเถอะ เดี๋ยวมันก็ลงตัวเอง (จำคำพูดน้อง Panot มายังไงเจ้าตัวมาอ่านก็มาช่วย Edit ด้วยนะ 555+)

ผมเขียนเป็นขั้นๆ แล้วกันนะครับ

Redux Surgery Step-I Folder Orientation

Redux จริงๆ มันก็คือ Function และ Class ประกอบกัน หรือกล่าวคือมันเป็นเพียงแค่ Design Pattern ประเภทหนึ่งเท่านั้นเอง จะว่าเป็น MVC ก็อาจจะพูดได้ หรือ อาจจะเป็น Singleton ก็เป็นได้เช่นกัน ไม่มีมีความสามารถพิเศษอะไรขนาดนั้น สิ่งแรกที่ควรจะทำก่อนคือการจัดการ Folder ผมเอาภาพมาประกอบเพื่อความเข้าใจอีกรอบนะครับจะได้ไม่ต้องเลื่อนขึ้นไปดู

http://codesheep.io/2017/01/06/redux-architecture/

เพราะฉะนั้นเรามาเริ่มกันที่การจัดเรียงโครงสร้าง Folder กันดีกว่าครับ ผมสร้าง Folder เพิ่มตามนี้นะครับ

โครงสร้างหน้าตาจากที่ดูมาหลายๆ references ผมอยากทำแบบเนี้ย 555+
ปล. ถ้า Clone Project มา หรือ Check out ตาม Step แล้วมันยังไม่ได้โครงสร้างแบบนี้ไม่เป็นไรนะครับ เพราะว่าจริงๆ จะค่อยๆ ทำไปเรื่อยๆ สุดท้ายผมคาดหวังไว้แบบนี้เฉยๆ

Redux Surgery Step-II Add-ons Packages Dependencies

ต่อไปก่อนจะทำอะไรเพิ่มเราต้องทำการเพิ่ม Packages เข้าไป 2 ตัวก่อนครับ ใน file pubspec.yaml

พิมพ์บรรทัดที่ 7,8 เพิ่มนะครับ

โดยปกติแล้วหลังจากที่เรากด Save ตัว IDE ที่เราใช้จะไปทำการ Load Dependencies ที่ต้องการมาให้เองเลย หรือ ถ้าไม่มั่นใจเราสามารถพิมพ์

flutter packages get

ได้ใน terminal ภายใน project ของเราหรือ แม้แต่รอตอนบิ้วทีเดียวเลยก็ได้เดี๋ยวมันจะทำการ Load dependencies ที่เราเพิ่มเข้าไปโดยอัตโนมัติอยู่แล้วครับ

Redux Surgery Step-III [EDIT] appState.dart , main.dart [ADD] appReducers.dart

ที่ผมตั้งชื่อ file ว่า appState เพื่อให้ดูเหมือนว่ามันเก็บ State ทุกอย่างไว้ภายใน Application หรือจริงๆ ถ้าพูดให้ถูกคือมันเก็บใบ Store ถ้าเปรียบเทียบกับรูป Redux ผมคิดว่ามันคือส่วนนี้ตามภาพครับ

ก็จะสังเกตได้ว่ามันอยู่ภายใน Store นะครับ และจริงๆ ทุกอย่างที่เกี่ยวกับ Redux ก็อยู่ใน Store ด้วย จำ Keyword นี้ไว้ก่อนนะครับ เดี๋ยวจะอธิบายเพิ่มภายหลัง โดย file appState.dart ก็จะประมาณนี้ครับ

มันควรจะแค่เนี้ยแหละครับ ทำไมมันต้องหน้าตาแบบนี้ ?? ผมลอกเค้ามาครับอย่าถามผมเยอะครับ 555+ แต่ถ้าให้เดาก็น่าจะพอเดาได้เนอะครับ เพราะว่า State ของเราที่มีใน counter application ตอนนี้เรามีแค่จำนวนที่เรานับว่ากดปุ่ม + ไปกี่ครั้งถูกไหมครับ งั้นก็น่าจะมีแค่ตัวแปรเดียวก็น่าจะพอเนอะคือ count โดยชนิดของมันคือ integer ยังไม่พอ มีโรงงานมาด้วย factory ตรงบรรทัดที่ 9 ใช้คำว่า factory …. factory คืออะไร ? ในความหมายโดยทั่วไปคือ Methode ที่ทำหน้าที่สร้างอ็อบเจกต์ โดยที่ไม่ใช้ constructor อยากอ่านเพิ่มเติม Search “Factory Design Pattern” นะครับ ถ้าไม่สนใจก็ข้ามไปเพราะผมเองก็ไม่สนใจ เห็นเค้าใช้แบบนี้ผมก็ใช้ตาม จบ

จริงๆ ใครอ่านมาถึงตรงนี้อยากจะไปปูพื้นเรื่องภาษาที่ใช้เขียนก็ได้นะครับ Flutter เราใช้ภาษา Dart ซึ่ง Google เป็นผู้พัฒนาขึ้นมาตั้งแต่ปี 2011

โดยโครงสร้างภาษาผมว่าเค้าลอก Java มา 555+ ใครเก่ง Java ผมว่าได้เปรียบมากครับ

มาต่อกันที่ main.dart

ตั้งใจอ่านดีๆ นะครับผมจะอธิบายเป็นขั้นเป็นตอนเพื่อให้ค่อยๆ follow กันได้ ใครอยากดูตามเปิด code ดูได้เลยครับ ไป Checkout git ที่ขั้นตอนนี้ได้เลย

//ไม่รู้ทำไมต้อง final เหมือนกันครับไปลอกเค้ามาไว้เดี๋ยวเข้าใจเพิ่มละมาเขียนต่อ

เริ่มกันที่บรรทัดที่ 9 เราประกาศตัวแปรชื่อ store และนำมันมาห่อด้วย AppState ซึ่งเราเพิ่งเขียนขึ้นมาเองจากด้านบนเนอะ เพราะฉะนั้นเราจึงต้อง Import บรรทัดที่ 4 มาด้วย

และ Class store นี้อยู่ภายใน Redux นะครับ เพราะฉะนั้น ถ้าเราไม่ได้ import บรรทัดที่ 2 มาจะพังเช่นกัน

จะเห็นได้ว่า Parameteres ที่ต้องการสำหรับการสร้าง store ก็จะมี appReducer ซึ่งก็เป็นตัวแปรที่ผมสร้างขึ้นมาเองเช่นกันเดี๋ยวจะอธิบายเพิ่มในลำดับต่อไป และ initialState ซึ่งก็น่าจะเดาได้ว่าจริงๆ มันก็คือ State เริ่มต้นของ Application ที่จะกำหนดให้ว่าเป็นอะไรถูกต้องไหมครับ เพราะฉะนั้นสังเกตให้ดี ว่าเราก็เรียก Methode AppState.initial() นี้ใน appState.dart นั้นแหละ สิ่งที่มัน Return กลับมาก็คือ State ซึ่งตอนนี้ มันคือจะ Return กลับมาเป็นตัวแปร count ที่มีค่าเท่ากับ 69 (ย้อนไปดูรูป appState.dart ด้านบน)

ปล.ผมใส่ ค่า 69 เพื่อให้เห็นความแตกต่างเฉยๆ ครับ เพราะจากตัวอย่างปกติ ค่ามันเริ่มต้นที่ 0

ต่อมาบรรทัดที่ 14 เมื่อสร้าง store ได้แล้ว เราเลยเอา store ยัดลงไปใน Class MyApp จากตัวอย่าง ก็เปรียบได้ว่า store จะคลุมทั้ง Class MyApp และ Class ที่อยู่ภายใต้มันเช่นเดียวกัน คล้ายๆ Unidirection flow ของ React เลย คือทำงานจากบนลงล่าง

ต้องเพิ่มบรรทัดที่ 21 และแก้ไขบรรทัดที่ 24 ด้วย เนื่องจากเรายัด store ลงไปใน MyApp ก็ต้องประกาศตัวแปรมารับด้วย ยัดลงไปดื้อๆ มันบาป … พังสิครับ

มาถึงตรงนี้คือพระเอกของงานแล้วครับ จากตัวอย่างเดิมถ้าเปิดดู Code main.dart เดิมๆ เลยจะเห็นว่าจุดที่แตกต่างกันคือตรงบรรทัดที่ 28 ตรงนี้คือเป็นการเชื่อมต่อหระหว่าง Store ของ Redux ที่ประกาศมา และ ทำงานร่วมกับ Flutter Redux เพราะฉะนั้นเราจึงต้อง import บรรทัดที่ 3 เข้ามาไม่งั้นพังครับ และกล่าวคือ StoreProvider<AppState> ในบรรทัดที่ 28 คือ Widget ที่มี Parameteres 2 ตัว ตัวที่หนึ่งคือ store ในบรรทัดที่ 29 ซึ่งก็รับ store ที่เราประกาศไว้ตั้งแต่ด้านบนนั้นแหละ แต่มันถูกยัดลงมาแล้วอยู่ใน MyApp เรียบร้อย และ Parameteres ตัวที่สองคือ Child ที่มี Widget MeterialApp ครอบอยู่แค่นั้นเอง

https://pub.dartlang.org/packages/flutter_redux#-readme-tab-

ตามนั้นครับแปลตรงตัวก็คือ StoreProvider เอาไว้ที่ Widget ตัวนอกสุด แล้วมันจะสามารถส่งต่อไปยังลูกชั้นล่างได้หมดเลย ชิวๆ สบายๆ

เมื่อส่งมาแล้วก็มารับสิครับ รออะไร ไปต่อที่นางเอกของงานที่มารับ Store ครับ บรรทัดที่ 117 StoreConnector<AppState, int> ตรงนี้เนื่องจากตอนนี้ตัวอย่างเรายังง่ายอยู่เราเลยระบุไปเลยว่า Store ที่เรารับมาเป็น int จาก State ที่เราได้กำหนดไว้ ซึ่งๆ จริงๆ อนาคตมันจะซับซ้อนกว่านี้อีกคือ ไม่ใช่ int ล่ะ อาจจะเป็น Class เลยแล้วค่อยเอามาใช้ต่อก็โหดกันเข้าไปอีก ตอนนี้เอาแค่นี้ก่อนเนอะ เช่นเดิมครับ everything in flutter are widget เพราะฉะนั้น StoreConnector มันก็แค่ Widget ตัวนึงที่มา Wrap ไว้เสยๆ โดยมี Parameteres 2 ตัวแรกคือ converter ที่รับ store มา เราก็ระบุไปชัดเจนอีกด้วยว่าเอาค่าตัวแปร count ที่อยู่ใน state นะ โดยพิมพ์ว่า store.state.count เสร็จแล้ว Parameteres ตัวที่สองคือ builder ประกาศมาเพื่อมารับ store.state.count โดย count ที่ประกาศมารับก็คือ store.state.count นั้นเอง ซึ่งตอนนี้มีค่าเป็น 69 เสร็จแล้ว builder ก็ มี Widget อีกตัวคือ Text จากเดิมๆ ที่ main.dart เราเอาค่าตัวแปร _counter มาแสดง ก็กลายเป็นเราเอา count จากใน store มาใช้แทน

เพราะฉะนั้นหากสั่งรัน App ตอนนี้ด้วยคำสั่ง

flutter run

หน้าตาของ App ที่ได้ตอนนี้ต้องเป็นแบบนี้

สวดยอดมั้ยยยย 555+ ทำไมผมโคตรเหนื่อยเลย อธิบายยาวววมากก เพิ่งได้เลข 69 มา เห็นมั้ยครับ เลขที่ได้มานั้น เราได้มาจาก appState ล้วนๆ ระหว่างนี้ลองไปแก้เลขใน AppState.initial() ดูให้มัน return เลขอื่นออกมา แล้วกด R (ตัวใหญ่) ก็จะพบว่าเลขที่แสดงของ App จะเปลี่ยนไปครับผม แต่ตอนนี้ยังกด + อะไรไม่ได้นะครับ เพราะเรายังไม่ได้ผูก Action เข้ากับ Store เลยติดตามตอนต่อไป

ผมอธิบายข้ามไปนิดนึงเพราะผมขี้เกียจย้อน คือ บรรทัดที่ 10 appReducer ซึ่งขอข้ามไป Step หน้าเลยนะครับ ตอนนี้หน้าตาของ appReducer ไม่มีอะไรเลย โล่งๆ เพราะเรายังไม่ได้ส่ง action อะไรมาที่ reducer เลยเด้อแต่ตอนสร้าง store เหมือนมันบังคับให้มีผมเลย เออ มีไว้ก่อน อย่าเพิ่งไปสนใจมากครับ

Redux Surgery Step-IV [ADD] appAction.dart [Edit] appReducer.dart, main.dart

!!! อย่าเพิ่งอ่าน Part นี้เลยครับขอเกาก่อนๆ

!!! เนื้อหาใน Part นี้ผมเองไม่ชัวร์ว่าจะอธิบายถูกหรือเปล่านะครับ อันนี้เอาตามที่เข้าใจก่อนถ้าเข้าใจมากกว่านี้จะมาอธิบายให้ฟังเพิ่ม !!!

ก่อนอื่นต้องทำความเข้าใจก่อนว่า State ใน Application นั้นเป็น Immutable หรือ pure function (ไม่สามารถแก้ไขได้) สิ่งที่เราทำได้จริงๆ เอาของเดิมมาแล้วสร้างขึ้นมาใหม่ โดยหลักการที่จะทำนั้นคือ เมื่อ มีการ dispatch action เพื่อไป ที่ Reducer โดยจะ มี Action บอกว่าทำอะไร และ State เดิมทำอะไร และ Return State ใหม่กลับไป โดยถ้า action default หรือ action ที่เกิดจากการส่งผิดพลาด อาจจะ Return State เดิมกลับไปเฉยๆ ก็ได้ โดยการ dispatch action จาก counter application ของเรานั้นมาจากการกดปุ่ม ก็เลยไปแก้ไข main.dart ก่อนดังนี้

จะเห็นได้ว่าเราเอา StoreConnector มา ครอบไว้ โดยถ้ามีการกดปุ่มบรรทัดที่ 138 ก็จะไปเรียก callback นั้นก็คือบรรทัดที่ 133 เพื่อ dispatch action ออกไป ซึ่งเราเองก็ต้องไปสร้าง Class IncrementalAction ขึ้นมา

!!! ตรงนี้ยังไม่แน่ใจว่าเอาไว้ทำไมด้วยซ้ำ ยังไม่ค่อย Clear เท่าไหร่ครับ

จริงๆ การ dispatch นั้นจะยิงไปที่ Reducer โดยตรงใน file appReducer.dart

// ข้อดีคือ เมื่อเราอยากได้ Global State ที่ Sync ระหว่าง App ทั้งหมด เราจะได้จัดการได้ง่าย

// อาจจะไม่เห็นภาพใหญ่ทั้งหมด แต่เพราะจำเป็นต้องทำแบบนี้ ไม่งั้นจะไม่เข้าใจเป็นอย่างมาก อยากจะอธิบายคร่าวๆ ว่า

Chapter II — Flutter with Firebase and Redux (สุดท้ายนี้โหดร้ายมากๆ)

ส่วนนี้โหดร้ายต่อมนุษย์มากที่สุดแล้วครับ เพราะต้องเพิ่ม Middleware มาเพื่อช่วยจัดการ Firebase Cloudstore ด้วย

// Part นี้ยังเขียนไม่เสร็จนะครับ

//เริ่มอธิบาย counter app with redux Only อธิบายการใช้ StoreConnector และ outline ที่ถูกต้อง

Final Chapter — Conclusion

แฮ๊ะๆ โฆษณาเลยละกันครับขออนุญาติหารายได้บ้าง ว่าจะจัด Workshop Flutter อยู่นะครับ ใช้เวลาประมาณ 2 วันเต็ม เสาร์ — อาทิตย์ โดยเนื้อหาหลังเรียนจบก็จะเป็นเป็น Application เล็กๆ ตัวนึงที่อยู่บน App store หรือ Google Play แต่ก็สามารถต่อ ยอดไปทำ Application อื่นได้อีกเยอะ โดยจะเริ่มตั้งแต่ พื้นฐานของการจัด Widget ภายใน Flutter , ความเข้าใจถึงการใช้ State ภายใน Application และ การจัดการ State เดี๋ยวขอคิดก่อนนะครับว่าจะสอน Redux , ScopedModel หรือ Bloc ยังคิดไม่ออกเดี๋ยวดูเสียงส่วนมากก่อน

โดยตั้งใจไว้ว่าจะทำเป็น Pilot แค่ 2 รุ่นที่มาเรียนในราคาพิเศษ โดย Pilot 2 รุ่นแรก สามารถเรียนซ้ำในรุ่นต่อๆ ไปได้อีก 1 ครั้ง เพราะคิดว่า 2 รุ่นแรกคงติดๆ ขัดๆ มาก ยังไม่มีรายละเอียดอะไรชัดเจนทั้งนะครับ ยังไง Add Line ผมไว้ก่อนแล้วกันครับ Line ID :: taforyou

ขอบคุณครับ

Like what you read? Give Chanon Yaklai a round of applause.

From a quick cheer to a standing ovation, clap to show how much you enjoyed this story.