สร้างแอป Twitter แบบง่ายๆ ด้วย React และ Recompose

Sayamrat Kaewta
dumpsayamrat
Published in
3 min readAug 18, 2017

สร้างแอป Twitter แบบง่ายๆ

ในบทความนี้ผมจะแสดงการนำ Recompose มาใช้ร่วมกับ React ในการสร้างแอป twitter แบบง่ายๆ ให้ดูนะครับ โดยผมจะพยายามแสดงให้เห็นประโยชน์ของ Recompose กับ React เมื่อมาใช้ในการสร้างแอปจริงๆ

สำหรับคนที่ไม่เข้าใจ Function Composition กับ Higher-order Component ผมแนะนำให้อ่านบทความนี้ก่อนนะครับ พื้นฐานก่อนศึกษา Recompose สำหรับ React

โดยแอป Twitter ของเราก็จะมีหน้าตา mockup ประมาณนี้

รูป mockup

โดยแอปนี้จะมีสเปคคร่าวๆ ตามนี้

  • สามารถพิมพ์ข้อความและทวีตลงไปได้
  • มีการจำกัดตัวอักษรไว้ที่ 140 ตัวอักษรและแสดงจำนวนตัวอักษรที่เหลือข้างๆ ปุ่ม “Tweet”
  • ถ้าไม่ได้พิมพ์อะไรเลยหรือพิมพ์ตัวอักษรเกินกว่าที่กำหนดปุ่ม “Tweet” จะถูก disable ไว้
  • ถ้าจำนวนตัวอักษรที่เหลือติดลบสีจะเปลื่ยนเป็นสีแดง

เริ่มแรกให้ทำการติดตั้ง React ก่อนเลยนะครับจะติดตั้งผ่าน create-react-app หรือจะ set up ขึ้นมาเองก็ได้ โดยสร้างโครงโปรเจคประมาณนี้ก่อนนะครับ

จากโค้ดด้านบนก็ไม่มีอะไรมากนะครับเพียงแค่มี TweetHome เป็น component ที่ไว้แสดง TweetBox ไว้ด้านบนและ Tweets แสดงด้านล่าง (Gist อาจจะดูยากหน่อยนะครับ ใจจริงอยากให้ TweetHome.js อยู่ข้างบนสุด)

เราก็จะได้หน้าตาแอปแบบนี้ออกมานะครับ

Tweet-1

ต่อไปเราจะนำเอา Recompose พระเอกของงาน มาใช้งานสักทีนะครับ วิธีติดตั้งก็เพียงแค่พิมพ์คำสั่ง npm install --save recompose หรือ yarn add recompose

ขั้นตอนต่อไปเราจะสร้างส่วนของกล่องทวีตนะครับ (ส่วนด้านบนของรูป mockup)

จากโค้ดข้างบนนะครับที่ไฟล์ TweetHome.js บรรทัดที่ 14 เราจะใช้ฟังก์ชั่น compose ของ Recompose มาใช้ในการประกอบหลายๆ High-order component (HOC) เข้าด้วยกันแล้วนำไปเก็บไว้ในตัวแปร enhance

ชึ่งข้างในประกอบไปด้วยการกำหนด state ของ component นี้มาสามตัว limit user และ messageโดยใช้ฟังก์ชัน withState ฟังก์ชัน withState รับ parameter เข้าไป 3 parameter ตัวแรกเป็นการกำหนดชื่อของ state ตัวต่อมาเป็นการกำหนดชื่อของฟังก์ชันที่ใช้ในการอัปเดตค่าของ state และตัวสุดท้ายเป็นการกำหนดค่าเริ่มต้นของ state นั้น

และทำการกำหนด handler onMessageChange โดยใช้ฟังก์ชัน withHandlers ฟังก์ชันนี้จะรับ Object โดยแต่ละ property ของ Object จะต้องเป็น higher-order functions ที่รับ props และรีเทิร์น ฟังก์ชัน handle ออกไป

จากฟังก์ชัน withHandlers บางคนอาจจะสงสัยว่าทำไมต้องใช้ฟังก์ชัน withHandlers ด้วย ทำไมไม่ใช้ mapProps หรือ withProps ชึ่งก็ใช้ได้เหมือน ลองมาดูตัวอย่างข้างล่างนี้ดูนะครับ

compare mapProps and withHandler

จากโค้ดข้างบนทั้ง enhance และ enhance2 ทำงานได้เหมือนกันทั้งคู่นะครับแต่จะต่างกันตรงที่ว่า onMessageChange ของ enhance2 จะถูกสร้างใหม่ทุกครั้งใหม่ทุกครั้งที่มีการอัปเดต state หรือ props ผมจึงแนะนำว่าเวลาที่จะทำฟังก์ชัน handle ตัว Event ต่างๆ ให้ใช้ withHandler ดีกว่านะครับจะช่วยเรื่อง Performance ของแอปได้ระดับนึง อ่านต่อเพิ่มเติมได้ที่นี้เลย recompose/withHandler

มาต่อที่ TweetHome.js ดูที่บรรทัดที่ 23 ตัวแปร TweetHome มันเป็นเพียงแค่ ฟังก์ชันที่รับ props เข้าไปและรีเทิร์น JSX ออกมา และนี้คือสิ่งที่ผมชอบมากๆ ของ Recompose มันทำให้ผมไม่ต้องมาปวดหัวกับการใช้ class this bind คือมันทำให้ผมลืมเรื่อง class ใน Javascript ไปได้เลย

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

มาต่อที่ไฟล์ TweetBox.js ไฟล์นี้เราก็จะทำการนำ props ที่ได้จาก TweetHome มาคำนวนค่าต่างๆ ที่จำเป็นต้องใช้ใน TweetBox โดยใช้ฟังก์ชัน mapProps จะมีตัวที่น่าสนใจคือฟังก์ชัน flattenProp ฟังก์ชันนี้มีหน้าที่คล้ายเครื่องหมาย … (Spread) ของ Javascript คือมันจะแยก property ต่างๆ ของ Object ที่กำหนด ออกไปเป็น props ของ Base Component

ตอนนี้แอปจะหน้าตาประมาณนี้นะครับ

โดยยังไม่สามารถทวีตและแสดงได้

ขั้นตอนสุดท้ายเราจะทำให้แอปนี้สมบูรณ์ตามสเปคที่เราเขียนไว้เมื่อตอนต้นบทความนะครับ

จากโค้ดที่เพิ่มเข้ามาในไฟล์ Tweet.js ก็ทำการแสดงข้อมูลแต่ละทวีตโดยใน component นี้มีการใช้ฟังก์ชัน onlyUpdateForKeys เป็นฟังก์ชันที่รับ Array ที่เก็บ key ที่เราต้องการตรวจสอบเข้าไป หากมี props อันใดอันหนึ่งที่กำหนดไว้มีการเปลื่ยนแปลงขึ้นมา component ก็จะ render ใหม่ สะดวกใช่ไหมล่ะครับ ไม่ต้องมานั่งเขียน shouldComponentUpdate() เองให้เหนื่อย

หน้าตาแอปตอนนี้ก็จะได้ดังรูปด้านล่างครับ

สรุป

ก็อย่างที่เห็นครับ Recompose ช่วยให้โค้ดดูอ่านง่ายสะอาดตามาก ทำให้ผมสามารถแยกการพัฒนาระหว่างการจัดการ State ใน Component กับการแสดงผลได้ พวก High-order Component ต่างก็สามารถ Test ได้ง่ายๆแน่นอนครับยิ่ง Component ธรรมดา ยิ่งง่ายใหญ่ ไม่การคำนวนหรือ Tranfrom ข้อมูลเลย มีเพียงแต่การแสดงผล และอีกอย่างถ้าแอปที่มีขนาดใหญ่หรือซับซ้อนมากกว่านี้บวกกับเราออกแบบมันดีพอ พวก High-order Component ที่สร้างขึ้นก็จะสามารถ Reusable

ผมได้ทำแอปแบบเดียวกันแต่ว่าเขียนอยู่ในรูปแบบปกติที่ไม่ได้ใช้ Recompose ใน Github ของผมไปดูกันได้เลยแล้วลองดูซิว่าชอบแบบไหนมากกว่ากัน https://github.com/dumpsayamrat/tweet-box

Recompose ยังมี API ที่เจ๋งๆ อีกเยอะนะครับไม่ว่าจะเป็น branch, onlyUpdateForPropTypes, lifecycle ลองตามไปดูกันได้

--

--