วิธีพัฒนาแอปโซเชียลมีเดีย: คู่มือทีละขั้นตอน
ในบทความนี้ เราจะพูดถึงโซเชียลเน็ตเวิร์ก ประเภทต่าง ๆ ของแอปโซเชียลมีเดีย ประโยชน์ และฟีเจอร์ที่จำเป็นต้องมี
นอกจากนี้ เรายังจะดูวิธีการสร้างโซเชียลเน็ตเวิร์กทีละขั้นตอน โดยจะใช้ Back4app เป็นแบ็กเอนด์ และ Next.js เป็นฟรอนต์เอนด์
Contents
โซเชียลเน็ตเวิร์กคืออะไร?
โซเชียลเน็ตเวิร์กคือแอปโซเชียลมีเดียที่เปิดให้ผู้คนเชื่อมต่อและมีปฏิสัมพันธ์กันได้
เมื่อผู้ใช้สองคนเชื่อมต่อกันแล้ว พวกเขาจะสามารถแชร์ข้อมูลผู้ใช้ พูดคุยแลกเปลี่ยนข้อความ ส่งรูปภาพ แชร์โพสต์ และอื่น ๆ อีกมากมาย
ทุกวันนี้ แอปโซเชียลมีเดียได้รับความนิยมอย่างสูง แทบทุกคนล้วนสมัครใช้งานแอปโซเชียลมีเดียอย่างน้อยหนึ่งแอป จากงานวิจัยของ Buffer แพลตฟอร์มโซเชียลมีเดียที่ได้รับความนิยมที่สุดได้แก่:
- Facebook (2.96 พันล้านผู้ใช้งานต่อเดือน)
- YouTube (2.2 พันล้านผู้ใช้งานต่อเดือน)
- Instagram (2 พันล้านผู้ใช้งานต่อเดือน)
- TikTok (1 พันล้านผู้ใช้งานต่อเดือน)
- Snapchat (500 ล้านผู้ใช้งานต่อเดือน)
MAUs ย่อมาจาก Monthly Active Users คือจำนวนผู้ใช้งานที่มีปฏิสัมพันธ์กับแพลตฟอร์มโซเชียลมีเดียของคุณในแต่ละเดือน
แม้ว่าตลาดแอปโซเชียลมีเดียจะกว้างใหญ่มาก แต่การพัฒนาแอปโซเชียลมีเดียนั้นไม่ใช่เรื่องง่าย
นี่ถือเป็นหนึ่งในโปรเจกต์ไอทีที่ซับซ้อนที่สุด คุณอาจประเมินความยากในการสร้างแอปโซเชียลเน็ตเวิร์กต่ำเกินไป จนประสบความล้มเหลวและขาดทุนอย่างมหาศาล
ประเภทของแอปโซเชียลมีเดีย
อย่างที่ได้กล่าวไปในส่วนก่อนหน้า โซเชียลเน็ตเวิร์กเป็นเพียงหนึ่งในประเภทของแอปโซเชียลมีเดีย ประเภทอื่น ๆ ได้แก่:
- Media-sharing networks (Instagram, TikTok, YouTube)
- Content-sharing networks (Pinterest, Tumblr, Flickr)
- Consumer review networks (Trustpilot, Angi, Choice)
- Blogging and publishing networks (Medium, Twitter)
- Discussion forums (Reddit, Quora, HackerNews)
- Relationship networks (Tinder, Bumble)
ประโยชน์ของการพัฒนาแอปโซเชียลมีเดีย
การสร้างแอปโซเชียลมีเดียมีประโยชน์หลายประการ ไม่ว่าจะเป็นการสร้างรายได้จากโฆษณา การทำเงินจากฟีเจอร์พิเศษ การเก็บข้อมูลผู้ใช้ที่มีค่าเพื่อวิเคราะห์เชิงลึก การได้สปอนเซอร์ร่วมกับบริษัทอื่น และอื่น ๆ อีกมากมาย
อีกหนึ่งข้อดีของแอปโซเชียลมีเดียคือมูลค่าในการขายต่อที่สูงมาก หากแอปของคุณประสบความสำเร็จในระดับหนึ่ง (มีฐานผู้ใช้พอสมควร) คุณก็สามารถขายต่อให้กับบริษัทอื่นได้อย่างง่ายดาย ยกตัวอย่างเช่น Twitter เคยถูกซื้อไปในราคา 44 พันล้านดอลลาร์ และ MySpace ถูกซื้อไปที่ 87 ล้านดอลลาร์
ในมุมมองของนักพัฒนา การสร้างโซเชียลเน็ตเวิร์กในรูปแบบง่าย ๆ ช่วยให้คุณได้ทำความเข้าใจกับเครื่องมือที่ใช้งาน และทำให้รู้ว่าการพัฒนาอะไรแบบนี้จริง ๆ แล้วมีความยากเพียงใด
ฟีเจอร์สำคัญที่แอปโซเชียลมีเดียควรมี
แอปโซเชียลมีเดียอาจมีฟีเจอร์ที่หลากหลาย แต่ก็ยังมีฟีเจอร์พื้นฐานบางอย่างที่ทุกแอปควรมีเพื่อความสำเร็จ
บัญชีผู้ใช้
แอปโซเชียลมีเดียทุกแอปล้วนเปิดโอกาสให้ผู้ใช้สร้างบัญชีของตนเอง เมื่อผู้ใช้สร้างบัญชีเรียบร้อยแล้ว พวกเขาจะเพิ่มข้อมูลส่วนตัวและตั้งค่าต่าง ๆ ตามความต้องการของตนได้ เช่น เลือกใช้ฟีเจอร์ที่สนใจ เพิ่มความสนใจของตัวเอง หรือซ่อนคอนเทนต์บางส่วนเป็นต้น
ข้อดีจากมุมมองธุรกิจคือ เมื่อมีบัญชีผู้ใช้ คุณสามารถสร้าง “โปรไฟล์ผู้ใช้” ที่สามารถระบุได้ว่าผู้ใช้นั้นชอบอะไร มีปฏิสัมพันธ์กับใคร และใช้ข้อมูลเหล่านี้ในการปรับโฆษณาให้เหมาะกับผู้ใช้แต่ละคนได้
การเชื่อมต่อระหว่างผู้ใช้
แอปโซเชียลมีเดียจะเปิดให้ผู้ใช้เชื่อมต่อกัน เช่น เพิ่มเป็นเพื่อน ติดตาม หรือกด subscribe เมื่อผู้ใช้สองคนเชื่อมต่อกันแล้ว ระบบฟีดของแต่ละคนจะเปลี่ยนไปตามการเชื่อมต่อนั้น
การแชร์คอนเทนต์
จุดประสงค์ของแอปโซเชียลมีเดียทุกแอปคือการแชร์คอนเทนต์ ถ้าแอปของคุณไม่อำนวยความสะดวกในการแชร์คอนเทนต์ ผู้ใช้ก็ยากที่จะสนใจ
ในการพัฒนาแอปโซเชียลมีเดีย ควรให้ความสำคัญกับแนวปฏิบัติที่ดีที่สุดด้าน UI/UX การโพสต์อะไรบางอย่างควรทำได้ง่ายและใช้เวลาเพียงไม่กี่คลิก
การค้นหาและการค้นพบคอนเทนต์
อัลกอริทึมการค้นหาและการค้นพบคอนเทนต์ที่ดีเป็นหัวใจสำคัญของการสร้างแอปโซเชียลมีเดียที่ประสบความสำเร็จ
แอปควรเอื้อให้ผู้ใช้ค้นหาคอนเทนต์ที่สนใจได้ง่าย และควรมีระบบฟีดที่ปรับให้เหมาะกับความสนใจของผู้ใช้ พร้อมฟังก์ชันการค้นหาที่หลากหลาย
การแจ้งเตือน
คุณควรพิจารณาใช้การแจ้งเตือนแบบพุช (Push Notifications) เพื่อสร้างการมีส่วนร่วมและกระตุ้นให้ผู้ใช้กลับมาใช้งาน
การแจ้งเตือนแบบพุชเป็นช่องทางสื่อสารที่มีประสิทธิภาพ ช่วยแจ้งผู้ใช้เมื่อมีเหตุการณ์ต่าง ๆ เช่น มีเพื่อนโพสต์ มีอีเวนต์ใหม่ หรือเมื่อผู้ใช้ขาดการใช้งานไปนาน เป็นต้น
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Push Notifications และวิธีผสานเข้ากับโปรเจกต์ของคุณ สามารถดูได้ที่ What are Push Notifications?
วิธีสร้างแอปโซเชียลมีเดีย
ในส่วนของบทความนี้ เราจะมาเรียนรู้การสร้างแอปโซเชียลมีเดียทีละขั้นตอน โดยใช้ Back4app เป็นแบ็กเอนด์ และใช้ React ร่วมกับเฟรมเวิร์ก Next.js เป็นฟรอนต์เอนด์
สิ่งที่ต้องเตรียม
เทคสแตกที่เราจะใช้มีดังนี้:
- ความคุ้นเคยกับ JavaScript ES6
- ความคุ้นเคยกับ React/Next.js และ React hooks
- ความเข้าใจพื้นฐานเกี่ยวกับ Backend as a Service (BaaS)
- Node.js v16+ ติดตั้งบนเครื่อง และมีเครื่องมือแก้ไขโค้ดพร้อม
Back4app คืออะไร?
Back4app เป็น Low-code backend ที่ยอดเยี่ยมสำหรับการสร้างเว็บและโมบายล์แอปสมัยใหม่ได้อย่างรวดเร็ว มาพร้อมฟีเจอร์หลากหลาย ไม่ว่าจะเป็นฐานข้อมูลแบบเรียลไทม์ ระบบจัดการผู้ใช้ Cloud Code functions การแจ้งเตือนแบบพุช การผสานโซเชียล API SDKs และอื่น ๆ อีกมากมาย!
ด้วยการใช้ Back4app คุณสามารถส่งต่อภาระงานส่วนใหญ่ในฝั่งแบ็กเอนด์ได้ ทำให้คุณโฟกัสเฉพาะตรรกะหลักของธุรกิจและการพัฒนาฟรอนต์เอนด์
นอกจากนี้ คุณยังไม่ต้องกังวลเรื่องโครงสร้างพื้นฐานเบื้องหลังหรือการขยายระบบ เพราะ Back4app จัดการทั้งหมดให้ เหมาะอย่างยิ่งสำหรับเร่งกระบวนการพัฒนาแอปโซเชียลมีเดีย
Back4app มีแพ็กเกจฟรีที่เหมาะสำหรับการทดสอบหรือสร้างต้นแบบ และเมื่อแอปเติบโตขึ้น คุณสามารถอัปเกรดเป็นแพ็กเกจระดับพรีเมียมที่มี ราคาที่คาดการณ์ได้
ทำไมถึงควรใช้ Back4app ในการสร้างโซเชียลเน็ตเวิร์ก?
- ใช้งานง่ายมาก
- มีระบบยืนยันตัวตน (Authentication) ในตัว พร้อมรองรับ Social Auth
- รองรับ Push notifications และการส่งอีเมล ได้อย่างง่ายดาย
- ขยายระบบ (Scaling) ได้แบบอัตโนมัติ
แนะนำโปรเจกต์
ในบทความนี้ เราจะสร้างโซเชียลเน็ตเวิร์กอย่างง่ายที่ให้ผู้ใช้สร้างบัญชี ยืนยันตัวตน ตั้งค่าโปรไฟล์ และสร้างโพสต์ได้
ฝั่งแบ็กเอนด์เราจะใช้ Back4app และฝั่งฟรอนต์เอนด์เราจะใช้ React ร่วมกับ Next.js เพื่อสร้างแอปโซเชียลมีเดีย
ขั้นแรก เราจะสร้างแอปบน Back4app ตั้งค่าโมเดลฐานข้อมูล จากนั้นจึงไปต่อที่ฝั่งฟรอนต์เอนด์
ฝั่งฟรอนต์เอนด์เราจะติดตั้ง Parse SDK ตั้งค่าระบบยืนยันตัวตน และสร้างหน้าต่าง ๆ เช่น หน้าเข้าสู่ระบบ หน้า sign-up และหน้าโปรไฟล์
ผลลัพธ์สุดท้ายจะมีหน้าตาแบบนี้:
สร้างแอป
ขั้นตอนต่อไปนี้จำเป็นต้องมีบัญชี Back4app หากยังไม่มี ให้ สมัครฟรี ก่อน
เมื่อคุณเข้าสู่บัญชี Back4app แล้ว จะเห็นรายการแอปของคุณ ให้คลิก “Build new app” เพื่อเริ่มสร้างแอป
Back4app มีตัวเลือกในการสร้างแอปอยู่ 2 แบบ:
- Backend as a Service (BaaS)
- Containers as a Service (CaaS)
BaaS คือโซลูชันแบ็กเอนด์ที่ใช้ Parse เต็มรูปแบบ ส่วน CaaS ใช้สำหรับดีพลอยแอปพลิเคชันที่บรรจุเป็น Docker container
เนื่องจากเรากำลังสร้างโซเชียลเน็ตเวิร์ก เราจึงเลือกใช้ “Backend as a Service”
จากนั้น ตั้งชื่อแอปของคุณ เลือกประเภทฐานข้อมูลเป็น “NoSQL” แล้วคลิก “Create”
Back4app จะใช้เวลาประมาณ 2 นาทีในการเตรียมสิ่งต่าง ๆ ให้พร้อมสำหรับแอปของคุณ เมื่อเสร็จแล้ว ระบบจะพาคุณไปยังหน้าฐานข้อมูลของแอป
Database Classes
ต่อไป เราจะเตรียมฐานข้อมูลเพื่อการพัฒนาแอปโซเชียลมีเดีย
คุณจะสังเกตเห็นว่ามีคลาสอยู่แล้ว 2 คลาส ได้แก่ User
และ Role
โดยค่าเริ่มต้น คลาสทุกคลาสใน Back4app จะมีฟิลด์ต่อไปนี้:
+-----------+-------------------------------------------------------------------------+
| Name | Explanation |
+-----------+-------------------------------------------------------------------------+
| objectId | Object's unique identifier |
+-----------+-------------------------------------------------------------------------+
| updatedAt | Date time of the object's last update. |
+-----------+-------------------------------------------------------------------------+
| createdAt | Date time of object's creation. |
+-----------+-------------------------------------------------------------------------+
| ACLs | Allow you to control the access to the object (eg. read, update). |
+-----------+-------------------------------------------------------------------------+
เราจะปรับ User
เล็กน้อย โดยเพิ่มฟิลด์ description
และ avatarUrl
ผู้ใช้จะสามารถแก้ไขข้อมูลทั้งสองนี้ได้ภายหลังจากหน้า settings
ให้คลิกปุ่ม “+ Column” ด้านขวาบนของหน้าจอ แล้วเพิ่มฟิลด์สองฟิลด์นี้:
+-----------+-------------+--------------------+----------+
| Data type | Name | Default value | Required |
+-----------+-------------+--------------------+----------+
| String | description | Another cool user! | yes |
+-----------+-------------+--------------------+----------+
| String | avatarUrl | <some_image_url> | yes |
+-----------+-------------+--------------------+----------+
อย่าลืมแทนที่
<your_image_url>
ด้วยลิงก์รูปภาพจริง ๆ ที่ลงท้ายด้วย .png, .jpg หรือ .jpeg หากยังนึกไม่ออก สามารถใช้ ลิงก์นี้ ได้
ต่อไป ให้เราสร้างคลาสใหม่ชื่อ Post
แต่ละโพสต์จะมีผู้เขียน (author) และข้อความ (content)
ให้คลิก “Create a class” ที่มุมซ้ายบนของหน้าจอ ตั้งชื่อว่า Post
เลือก “Protected” และคลิก “Create class & add columns”
จากนั้นเพิ่มสองคอลัมน์ตามด้านล่าง:
+-----------------+---------+---------------+----------+
| Data type | Name | Default value | Required |
+-----------------+---------+---------------+----------+
| Pointer -> User | author | <leave blank> | yes |
+-----------------+---------+---------------+----------+
| String | content | <leave blank> | yes |
+-----------------+---------+---------------+----------+
Back4app Database Security
เกี่ยวกับการรักษาความปลอดภัยของฐานข้อมูลใน Back4app มีสองแนวทางที่สามารถใช้ได้:
- Class Level Permissions (CLPs)
- Access Control Levels (ACLs)
CLPs จะโฟกัสการกำหนดสิทธิ์การเข้าถึงในระดับคลาส ทำให้ควบคุมการเข้าถึงและการแก้ไขข้อมูลได้อย่างละเอียด ส่วน ACLs จะให้หรือจำกัดสิทธิ์การเข้าถึงแก่อ็อบเจ็กต์แต่ละรายการ และอ้างอิงตามบทบาทหรือสิทธิ์ที่กำหนดไว้
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Parse Security สามารถดูได้ที่บทความ Parse Server Security
เราต้องการให้เฉพาะผู้ใช้ที่เข้าสู่ระบบ (authenticated) เท่านั้นที่สามารถสร้างโพสต์ได้ และให้เฉพาะเจ้าของโพสต์เป็นผู้แก้ไขหรือลบโพสต์ของตนเองได้ เราจึงจะตั้งค่า CLPs สำหรับคลาส Post
ให้เลือกคลาส Post
จากแถบด้านข้าง จากนั้นคลิกที่สามจุดมุมขวาบนของหน้าจอ เลือก “Security > Class Level Permissions” แล้วตั้งค่า CLPs ตามภาพ:
เยี่ยม แค่นี้ก็เรียบร้อย ฝั่งแบ็กเอนด์ของเราพร้อมใช้งานแล้ว เห็นไหมว่าไม่ยากเลย
โค้ดฝั่งฟรอนต์เอนด์
ในส่วนนี้ เราจะสร้างฟรอนต์เอนด์สำหรับโซเชียลเน็ตเวิร์กของเรา
เริ่มโปรเจกต์
เริ่มต้นด้วยการใช้ create-next-app
เพื่อบูตสแตรปโปรเจกต์ Next.js ใหม่:
$ npx create-next-app@latest back4app-social-network
√ Would you like to use TypeScript? ... No
√ Would you like to use ESLint? ... Yes
√ Would you like to use Tailwind CSS? ... No
√ Would you like to use `src/` directory? ... No
√ Would you like to use App Router? (recommended) ... No
√ Would you like to customize the default import alias? ... No
Created a new Next.js app in ~\back4app-social-network.
ตัวสร้างโปรเจกต์จะถามคำถามคุณหลายข้อ แนะนำให้เลือกใช้งานแค่ ESLint ส่วนออปชันอื่น ๆ อาจไม่จำเป็นสำหรับตัวอย่างนี้และจะทำให้โปรเจกต์ซับซ้อนขึ้น
โปรเจกต์ Next.js ที่ได้มาพร้อมไฟล์และโฟลเดอร์บางส่วนที่เราไม่จำเป็นต้องใช้ ให้ลบออกเพื่อลดขนาดโปรเจกต์ ได้แก่:
- โฟลเดอร์ pages/api
- โฟลเดอร์ styles
- ไฟล์ public/next.svg
- ไฟล์ public/vercel.svg
อย่าลืมลบการ import globals.css ในไฟล์ pages/_app.js ด้วย:
// pages/_app.js
import "@/styles/globals.css"; // remove this line
จากนั้นแทนที่โค้ดใน pages/index.js ด้วยเนื้อหาต่อไปนี้:
// pages/index.js
export default function Home() {
return (
<>
<p>Hello world!</p>
</>
);
}
สั่งรันเซิร์ฟเวอร์พัฒนา Next:
$ next dev
สุดท้าย เปิดเบราว์เซอร์ไปที่ http://localhost:3000 ถ้าทุกอย่างถูกต้อง คุณจะเห็นข้อความ “Hello world!” ปรากฏขึ้น
ตั้งค่า ChakraUI
เพื่อให้การสร้าง UI รวดเร็วขึ้น เราจะใช้ ChakraUI ซึ่งเป็นไลบรารีสำหรับ React ที่มาพร้อมคอมโพเนนต์สำเร็จรูป ระบบสไตล์ ฮุคเฉพาะ และอื่น ๆ
ติดตั้งผ่าน NPM ดังนี้:
$ npm i @chakra-ui/react @chakra-ui/next-js @emotion/react @emotion/styled framer-motion
จากนั้นหุ้ม Component
ของเราด้วย ChakraProvider
:
// pages/_app.js
import {ChakraProvider} from "@chakra-ui/react";
function MyApp({Component, pageProps}) {
return (
<ChakraProvider>
<Component {...pageProps} />
</ChakraProvider>
);
}
export default MyApp;
อย่าลืม import ไว้ด้านบนไฟล์ด้วย:
import {ChakraProvider} from "@chakra-ui/react";
สำหรับ Chakra ที่จะทำงานได้อย่างถูกต้อง เราต้องใส่สคริปต์ Color mode เพื่อให้การซิงก์ local storage ทำงานตามปกติ และหลีกเลี่ยงปัญหาหน้าจอกะพริบสี
แก้ไขไฟล์ pages/_document.js ดังนี้:
// pages/_document.js
import { Html, Head, Main, NextScript } from "next/document";
import {ColorModeScript, extendTheme} from "@chakra-ui/react";
export const theme = extendTheme();
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<ColorModeScript initialColorMode={theme}/>
<Main />
<NextScript />
</body>
</Html>
);
}
แค่นี้ก็เสร็จขั้นตอนเริ่มต้นของ Chakra
React Icons
เพื่อให้แอปดูดีขึ้น เราจะติดตั้ง react-icons ซึ่งเป็นไลบรารีที่ช่วยให้เราดึงไอคอนยอดนิยมต่าง ๆ เข้ามาใช้งานได้ง่าย ไม่ว่าจะเป็น Ant, Bootstrap, Heroicons, Font Awesome เป็นต้น
ติดตั้งด้วยคำสั่ง:
$ npm install react-icons --save
เมื่อเสร็จแล้ว คุณสามารถนำเข้าและใช้งานไอคอนได้ตามต้องการ เช่น:
import {FaMusic} from "react-icons/fa";
return (
<FaMusic/>
);
ดูรายชื่อไอคอนได้ที่ React Icons Docs
Layout และ Components
โดยทั่วไปแล้ว แอปโซเชียลเน็ตเวิร์กจะมี Layout ที่ใกล้เคียงกัน คือมี Header ส่วนบนและ Footer ส่วนล่างทุกหน้า เราจะมาสร้าง Layout กัน
เริ่มด้วยการสร้างโฟลเดอร์ใหม่ชื่อ components ที่โฟลเดอร์หลักของโปรเจกต์ และสร้างไฟล์ต่อไปนี้:
components/
├── header.js
├── footer.js
└── layout.js
เติมเนื้อหาในไฟล์ header.js ดังนี้:
// components/header.js
import NextLink from "next/link";
import {Box, Container, Divider, Heading, HStack, Link} from "@chakra-ui/react";
export default function Header() {
return (
<Box py={4}>
<Container
maxW="container.lg"
display="flex"
alignItems="center"
justifyContent="space-between"
>
<Heading as="h1" size="md">
<Link as={NextLink} href="/">
back4app-social-network
</Link>
</Heading>
<HStack spacing="1em">
<Heading size="sm">
<Link as={NextLink} href="/login">
Log in
</Link>
</Heading>
<Heading size="sm">
<Link as={NextLink} href="/signup">
Sign up
</Link>
</Heading>
</HStack>
</Container>
<Divider my={4}/>
</Box>
);
}
จากนั้นในไฟล์ footer.js:
// components/footer.js
import NextLink from "next/link";
import {Box, Container, Divider, Heading,
HStack, Link, Tag, Text, VStack} from "@chakra-ui/react";
import {FaGithub} from "react-icons/fa";
export default function Footer() {
return (
<Box py={4}>
<Divider my={4}/>
<Container
maxW="container.lg"
display="flex"
justifyContent="space-between"
alignItems="center"
>
<VStack alignItems="left">
<Heading size="sm">
A simple social network powered by Back4app.
</Heading>
<Link
as={NextLink}
href="https://blog.back4app.com/how-to-develop-a-social-media-app/"
>
Click here to learn how to build it!
</Link>
</VStack>
<Link href="https://github.com/duplxey/back4app-social-network">
<Tag background="black" color="white" py={2}>
<HStack>
<FaGithub size="1.5em"/>
<Text>View on GitHub</Text>
</HStack>
</Tag>
</Link>
</Container>
</Box>
);
}
ในโค้ดข้างต้น เราใช้คอมโพเนนต์ที่มีมาให้ของ Chakra เพื่อสร้าง Header และ Footer แบบเรียบง่าย และเนื่องจากเราใช้ Next.js จึงนำ Link
ของ Chakra มาทำงานร่วมกับ Link
ของ Next
สุดท้าย สร้าง layout.js เพื่อประกอบ Header และ Footer เข้าด้วยกัน:
// components/layout.js
import {Container} from "@chakra-ui/react";
import Header from "@/components/header";
import Footer from "@/components/footer";
export default function Layout({children}) {
return (
<>
<Header/>
<Container maxW="container.lg">
{children}
</Container>
<Footer/>
</>
);
}
จากนั้นนำ Layout
ไปใช้งานใน index.js:
// pages/index.js
import Layout from "@/components/layout";
export default function Home() {
return (
<Layout>
<p>Hello world!</p>
</Layout>
);
}
รอให้ Next recompile เสร็จแล้วเข้าไปที่ http://localhost:3000 ถ้าถูกต้อง เราจะเห็น Layout ใหม่ที่เราได้เพิ่มไว้
ตั้งค่า Parse.js
เริ่มต้นด้วยการติดตั้ง Parse ผ่าน NPM:
$ npm install parse
จากนั้นเพิ่มการตั้งค่า Parse ต่อจากส่วน import ในไฟล์ _app.js:
// pages/_app.js
// ...
import Parse from "parse/dist/parse";
const PARSE_APPLICATION_ID = process.env.NEXT_PUBLIC_PARSE_APPLICATION_ID;
const PARSE_JAVASCRIPT_KEY = process.env.NEXT_PUBLIC_PARSE_JAVASCRIPT_KEY;
Parse.initialize(PARSE_APPLICATION_ID, PARSE_JAVASCRIPT_KEY);
Parse.serverURL = "https://parseapi.back4app.com/";
// ...
เราไม่ได้ฮาร์ดโค้ดตัวแปร แต่ใช้ตัวแปรสภาพแวดล้อม (environmental variables) ใน Next.js ซึ่งจะโหลดโดยอัตโนมัติจากไฟล์ .env.local
ให้สร้างไฟล์ชื่อ .env.local ที่โฟลเดอร์หลักของโปรเจกต์ แล้วใส่ข้อมูลดังนี้:
NEXT_PUBLIC_PARSE_APPLICATION_ID=<parse_app_id>
NEXT_PUBLIC_PARSE_JAVASCRIPT_KEY=<parse_javascript_key>
อย่าลืมแทนที่
<parse_app_id>
และ<parse_javascript_key>
ด้วยค่าจริงของคุณเอง โดยไปที่แอป Back4app และดูที่ “App Settings > Security & Keys”
Context
เพื่อหลีกเลี่ยงการต้องส่งต่อ Parse instance ผ่าน props หลายชั้น เราจะใช้ React context แทน ซึ่งช่วยให้ส่งข้อมูลจากคอมโพเนนต์หนึ่งไปยังอีกคอมโพเนนต์ได้โดยไม่ต้องผ่าน props
สร้างโฟลเดอร์ชื่อ context และไฟล์ parseContext.js ภายใน:
// context/parseContext.js
import {createContext} from "react";
const ParseContext = createContext();
export default ParseContext;
จากนั้นหุ้ม Component
ของเราด้วย ParseContext.Provider
และส่ง Parse
instance ไปด้วย:
// pages/_app.js
// ...
function MyApp({Component, pageProps}) {
return (
<ChakraProvider>
<ParseContext.Provider value={Parse}>
<Component {...pageProps} />
</ParseContext.Provider>
</ChakraProvider>
);
}
export default MyApp;
อีกครั้ง อย่าลืม import ParseContext
ไว้ด้านบนไฟล์:
import ParseContext from "@/context/parseContext";
ขณะนี้ เราสามารถเรียกใช้ Parse
instance ได้ผ่าน useContext()
ในคอมโพเนนต์ต่าง ๆ ลองทดสอบการเชื่อมต่อใน index.js ดู
แทนที่โค้ดใน pages/index.js ด้วย:
// pages/index.js
import {useContext} from "react";
import ParseContext from "@/context/parseContext";
import {Button} from "@chakra-ui/react";
import Layout from "@/components/layout";
export default function Home() {
const parse = useContext(ParseContext);
async function testConnection() {
try {
await new parse.Query("TestClass").first();
console.log("Connection successful");
} catch (error) {
console.error("Connection failed: " + error);
}
}
return (
<Layout>
<p>Hello world!</p>
<Button onClick={() => testConnection()}>Parse.js test</Button>
</Layout>
);
}
รอให้ Next recompile จากนั้นเข้าไปที่ http://localhost:3000 เปิดคอนโซล แล้วกดปุ่ม “Parse.js test” ถ้าทุกอย่างถูกต้อง จะมีข้อความ “Connection successful” แสดงขึ้นมา
การยืนยันตัวตน (Authentication)
อย่างที่กล่าวไว้ในส่วน “Back4app คืออะไร?” Back4app มีระบบยืนยันตัวตนในตัวอยู่แล้ว การตั้งค่าระบบล็อกอิน/ล็อกเอาต์ด้วย Parse SDK จึงทำได้ง่ายมาก และ Parse จะจัดการเซสชันให้โดยอัตโนมัติ
เรามาสร้างฟอร์มสำหรับการยืนยันตัวตนกัน
เริ่มด้วยการสร้างไฟล์ signup.js ในโฟลเดอร์ pages และใส่โค้ดดังนี้:
// pages/signup.js
import NextLink from "next/link";
import {useState} from "react";
import {Button, Card, CardBody, CardFooter, CardHeader, FormControl,
FormLabel, Heading, HStack, Input, Link, Text, VStack,
} from "@chakra-ui/react";
import {FaUserPlus} from "react-icons/fa";
import Layout from "@/components/layout";
export default function SignUp() {
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
const onSubmit = async (event) => {
// implement logic
};
return (
<Layout>
<Card>
<CardHeader>
<HStack>
<FaUserPlus/>
<Heading as="h2" size="md"> Sign up</Heading>
</HStack>
</CardHeader>
<CardBody py={0}>
<VStack spacing="1em" alignItems="left">
<FormControl>
<FormLabel>Username</FormLabel>
<Input
placeholder="Username"
value={username}
onChange={(e) => setUsername(e.target.value)}
/>
</FormControl>
<FormControl>
<FormLabel>Password</FormLabel>
<Input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
/>
</FormControl>
</VStack>
</CardBody>
<CardFooter
w="full"
display="flex"
alignItems="center"
justifyContent="space-between"
>
<Text>
Already have an account?{" "}
<Link as={NextLink} href="/login">
Log in
</Link>
</Text>
<Button colorScheme="teal" onClick={onSubmit}>Sign up</Button>
</CardFooter>
</Card>
</Layout>
);
}
โค้ดข้างต้นจะสร้างหน้า /signup
ที่มีฟอร์มสำหรับสมัครบัญชี โดยให้ผู้ใช้กรอก username และ password
ต่อมาให้แก้ pages/signup.js เพื่อเพิ่มลอจิกดังนี้:
// pages/signup.js
// ...
import {useRouter} from "next/router";
import {useContext, useEffect} from "react";
import ParseContext from "@/context/parseContext";
export default function SignUp() {
const router = useRouter();
const parse = useContext(ParseContext);
const [username, setUsername] = useState("");
const [password, setPassword] = useState("");
// redirect the user if already logged in
useEffect(() => {
(async () => {
if (parse.User.current() !== null) {
await router.push("/");
}
})();
}, [router, parse.User]);
const onSubmit = async (event) => {
event.preventDefault();
if (!username || !password) {
console.error("Please fill out all the fields.");
return;
}
try {
await parse.User.signUp(username, password).then(() => {
router.push("/");
console.log("Successfully signed up.");
});
} catch (error) {
console.error(error.message);
}
};
return (
// ...
);
}
- หากผู้ใช้ล็อกอินอยู่แล้ว จะ redirect ไปที่
/
โดยใช้ฮุคuseRouter()
ของ Next - เราแก้ฟังก์ชัน
onSubmit()
ให้เรียกUser.signUp()
ซึ่งจะสร้างเซสชันผู้ใช้และเก็บคุกกี้ในเบราว์เซอร์ให้โดยอัตโนมัติ
ให้ทำแบบเดียวกันกับไฟล์ pages/login.js โดยดูโค้ดตัวอย่างได้ใน GitHub repo
เยี่ยม ตอนนี้ระบบยืนยันตัวตนเกือบเสร็จแล้ว ขั้นต่อไปคือปรับ header.js นิดหน่อยเพื่อแสดงชื่อผู้ใช้เมื่อผู้ใช้ล็อกอิน หรือแสดงลิงก์ Log in/Sign up หากยังไม่ล็อกอิน
แก้ components/header.js ดังนี้:
// components/header.js
import NextLink from "next/link";
import {Avatar, Box, Container, Divider, Heading, HStack, Link} from "@chakra-ui/react";
import {useContext, useEffect, useState} from "react";
import ParseContext from "@/context/parseContext";
export default function Header() {
const parse = useContext(ParseContext);
const [user, setUser] = useState(null);
useEffect(() => {
setUser(parse.User.current());
}, [parse.User]);
return (
<Box py={4}>
<Container
maxW="container.lg"
display="flex"
alignItems="center"
justifyContent="space-between"
>
<Heading as="h1" size="md">
<Link as={NextLink} href="/">
back4app-social-network
</Link>
</Heading>
{user != null ? (
<HStack>
<Avatar
size="sm"
name={user.attributes.username}
src={user.attributes.avatarUrl}
/>
<Heading size="sm">
<Link as={NextLink} href="/settings">
{user.attributes.username}
</Link>
</Heading>
</HStack>
) : (
<HStack spacing="1em">
<Heading size="sm">
<Link as={NextLink} href="/login">
Log in
</Link>
</Heading>
<Heading size="sm">
<Link as={NextLink} href="/signup">
Sign up
</Link>
</Heading>
</HStack>
)}
</Container>
<Divider my={4}/>
</Box>
);
}
รอให้ Next recompile แล้วทดสอบสร้างบัญชีใหม่ จะเห็นว่าหัวข้อใน Header เปลี่ยนไปตามสถานะล็อกอิน
ตอนนี้เรายังไม่ได้ทำระบบล็อกเอาต์ ดังนั้นถ้าต้องการล็อกเอาต์ ต้องลบคุกกี้ด้วยตัวเองก่อน
เมื่อคุณสร้างบัญชีเสร็จแล้ว ลองกลับไปดูฐานข้อมูลใน Back4app ตรงคลาส User
จะเห็นว่ามีผู้ใช้ใหม่ถูกสร้างขึ้น
หน้าตั้งค่าผู้ใช้ (User Settings)
ต่อไป เราจะทำให้ฟิลด์ description
และ avatarUrl
(ที่เราเพิ่มในคลาส User
) สามารถแก้ไขได้
สร้างไฟล์ใหม่ชื่อ settings.js ในโฟลเดอร์ pages และใส่โค้ดต่อไปนี้:
// pages/settings.js
import React, {useContext, useEffect, useState} from "react";
import {useRouter} from "next/router";
import {Button, Card, CardBody, CardFooter, CardHeader, FormControl, FormLabel,
Heading, HStack, Input, VStack} from "@chakra-ui/react";
import {FaCog} from "react-icons/fa";
import ParseContext from "@/context/parseContext";
import Layout from "@/components/layout";
export default function Settings() {
const router = useRouter();
const parse = useContext(ParseContext);
const [description, setDescription] = useState("");
const [avatarUrl, setAvatarUrl] = useState("");
useEffect(() => {
(async () => {
const user = parse.User.current();
// redirect the user if not logged in
if (user === null) {
await router.push("/");
return;
}
// load data from the database
setDescription(await user.get("description"));
setAvatarUrl(await user.get("avatarUrl"));
})();
}, [router, parse.User]);
const onSave = async () => {
const user = parse.User.current();
user.set("description", description);
user.set("avatarUrl", avatarUrl);
await user.save();
console.log("Successfully saved settings.");
};
const onLogout = async () => {
await parse.User.logOut();
await router.push("/");
console.log("Successfully logged out.");
};
return (
<Layout>
<Card>
<CardHeader>
<HStack>
<FaCog/>
<Heading as="h2" size="md"> Settings</Heading>
</HStack>
</CardHeader>
<CardBody py={0}>
<VStack spacing="1em">
<FormControl>
<FormLabel>Description</FormLabel>
<Input
placeholder="Description"
value={description}
onChange={e => setDescription(e.target.value)}
/>
</FormControl>
<FormControl>
<FormLabel>Avatar URL</FormLabel>
<Input
placeholder="Avatar URL"
value={avatarUrl}
onChange={e => setAvatarUrl(e.target.value)}
/>
</FormControl>
</VStack>
</CardBody>
<CardFooter display="flex" justifyContent="right">
<HStack>
<Button colorScheme="red" onClick={onLogout}>Log out</Button>
<Button colorScheme="teal" onClick={onSave}>Save</Button>
</HStack>
</CardFooter>
</Card>
</Layout>
);
}
- เราใช้ React
useEffect()
เพื่อเช็กว่าผู้ใช้ล็อกอินหรือยัง ถ้ายัง ก็ redirect ไปหน้าแรก นอกจากนี้ยังโหลดข้อมูลdescription
และavatarUrl
ของผู้ใช้มาใส่ใน state - เราสร้างฟังก์ชัน
onSave()
เพื่ออัปเดตข้อมูลผู้ใช้ในฐานข้อมูลให้ตรงกับ state - เราสร้างฟังก์ชัน
onLogout()
เพื่อล็อกเอาต์โดยเรียกparse.User.logOut()
ซึ่งจะลบเซสชันออกจากฐานข้อมูลและลบคุกกี้จากเบราว์เซอร์
โพสต์
ส่วนสุดท้ายที่ต้องทำเพื่อให้แอปโซเชียลเน็ตเวิร์กง่าย ๆ ของเราสมบูรณ์ก็คือการเพิ่มฟีเจอร์โพสต์ เราได้สร้างคลาสในฐานข้อมูลเรียบร้อยแล้ว ตอนนี้แค่ทำหน้าฟอร์มสร้างโพสต์และดึงข้อมูลโพสต์มาแสดง
ก่อนอื่น สร้างคอมโพเนนต์ใหม่ชื่อ post.js:
// components/post.js
import {Avatar, Box, Card, CardBody, CardHeader, Heading, HStack, Text} from "@chakra-ui/react";
export default function Post(props) {
return (
<Card mt={2}>
<CardHeader pb={0}>
<HStack spacing="1em">
<Avatar name={props.author.username} src={props.author.avatarUrl}/>
<Box>
<Heading size="sm">{props.author.username}</Heading>
<Text>{props.author.description}</Text>
</Box>
</HStack>
</CardHeader>
<CardBody>
<Text>{props.content}</Text>
</CardBody>
</Card>
);
}
จากนั้นแก้ไข index.js เพื่อแสดงฟอร์มสร้างโพสต์และรายชื่อโพสต์:
// pages/index.js
import {useContext, useEffect, useState} from "react";
import {Alert, AlertIcon, Button, Card, CardBody, CardFooter,
CardHeader, Heading, HStack, Textarea} from "@chakra-ui/react";
import {FaPlus} from "react-icons/fa";
import ParseContext from "@/context/parseContext";
import Layout from "@/components/layout";
import Post from "@/components/post";
export default function Home() {
const parse = useContext(ParseContext);
const [user, setUser] = useState(null);
const [postContent, setPostContent] = useState("");
const [posts, setPosts] = useState([]);
const onCreatePost = async () => {
// implement logic
};
return (
<Layout>
{user ? (
<Card mb={2}>
<CardHeader>
<HStack>
<FaPlus/>
<Heading as="h2" size="md"> Create post</Heading>
</HStack>
</CardHeader>
<CardBody py={0}>
<Textarea
placeholder="What's on your mind?"
value={postContent}
onChange={(event) => setPostContent(event.target.value)}
/>
</CardBody>
<CardFooter display="flex" justifyContent="right">
<Button colorScheme="teal" onClick={onCreatePost}>Post</Button>
</CardFooter>
</Card>
) : (
<Alert status="warning" mb={2}>
<AlertIcon/>
You need to log in to create posts.
</Alert>
)}
{posts.map(post => (
<Post
key={post.id}
content={post.attributes.content}
author={{...post.attributes.author.attributes}}
/>
))}
</Layout>
);
}
เพิ่มลอจิกในฟังก์ชัน onCreatePost()
ดังนี้:
const onCreatePost = async () => {
if (!user == null) return;
const post = new parse.Object("Post");
post.set("content", postContent);
post.set("author", user);
await post.save();
setPostContent("");
setPosts([post, ...posts]);
};
สุดท้าย เพิ่ม useEffect()
เพื่อดึงข้อมูลโพสต์:
useEffect(() => {
setUser(parse.User.current());
(async () => {
const posts = await new parse.Query("Post")
.include("author").descending("createdAt").find();
setPosts(posts);
})();
}, []);
หากต้องการเรียนรู้เพิ่มเติมเกี่ยวกับ Parse Objects และ Queries สามารถดูได้ที่ Parse Documentation
จากนั้นสั่งรันเซิร์ฟเวอร์ Next อีกครั้ง:
$ next start
ลองสร้างโพสต์ตัวอย่างสักสองสามโพสต์ จากนั้นรีเฟรชหน้า หากทุกอย่างทำงานถูกต้อง โพสต์จะถูกเก็บไว้ในฐานข้อมูล และดึงกลับมาแสดงเมื่อคุณเปิดหน้าอีกครั้ง
สรุป
ในบทความนี้ เราได้สร้างแอปโซเชียลมีเดียง่าย ๆ ซึ่งให้ผู้ใช้สมัครบัญชี ล็อกอิน ตั้งค่าโปรไฟล์ และโพสต์เนื้อหาได้
เมื่อถึงตอนนี้ คุณควรเข้าใจวิธีการทำงานของ Back4app และรู้วิธีเริ่มต้นสร้างโซเชียลเน็ตเวิร์กแล้ว
โปรเจกต์ตัวอย่างในบทความนี้สามารถใช้เป็นโครงสร้างพื้นฐานสำหรับการต่อยอด เพิ่มฟีเจอร์ใหม่ เช่น ระบบไลก์/ดิสไลก์ ระบบแชร์ หรือระบบคอมเมนต์ เพื่อฝึกฝนเพิ่มเติม
โค้ดตัวอย่างทั้งหมดสามารถดูได้ที่ back4app-social-network ใน GitHub
ก้าวต่อไป
- ทำตาม บทความนี้ เพื่อดีพลอย Next.js ฟรอนต์เอนด์ของคุณไปยัง Back4app Containers
- ศึกษาการใช้ Cloud Code Functions เพื่อเพิ่มความสามารถขั้นสูงด้านแบ็กเอนด์
- เปิดใช้งานการ ยืนยันอีเมลผู้ใช้ เพื่อป้องกันบอต