🌟 Bonus පාඩම: Real-time ක්‍රියාකාරීත්වය (Socket.IO)

අපේ React App එක, බහු-පරිශීලක (multi-user) අත්දැකීමක් බවට පත් කරමු. එක් අයෙක් කරන වෙනසක්, සැමටම සජීවීව පෙනෙන ලෙස සකසමු!

"Real-time" යන්නෙහි සැබෑ අරුත කුමක්ද? ⏱️

මේ වන විටත්, අපේ React app එක "real-time" ලෙස දැනෙනවා. ඒ, බොත්තමක් click කළ සැනින් කිසිදු page refresh වීමකින් තොරව UI එක update වන නිසයි. මෙය React හි state කළමනාකරණයේ ප්‍රතිඵලයකි. නමුත් මෙය සිදුවන්නේ **එක් පරිශීලකයෙකුගේ browser එක තුල පමණි**.

සැබෑ "Real-time" යෙදුමකදී (True real-time application), සිදුවන්නේ ඊට වඩා දෙයකි. එහිදී, එක් පරිශීලකයෙක් (Client A) යම් වෙනසක් කළ විට, එම වෙනස ඒ මොහොතේදීම මධ්‍යම server එකක් හරහා ගොස්, එම යෙදුම භාවිත කරන අනෙක් සියලුම පරිශීලකයින්ට (Client B, Client C, ...) ස්වයංක්‍රීයව ලැබී ඔවුන්ගේ තිරයන් ද update වීමයි.

ප්‍රායෝගික උදාහරණ:

  • Chat Applications (WhatsApp, Messenger): ඔබ පණිවිඩයක් යැවූ සැනින්, අනෙක් අයට එය ලැබීම.
  • Online Gaming: එක් ක්‍රීඩකයෙක් චලනය වන විට, අනෙක් සියලුම ක්‍රීඩකයින්ට එය පෙනීම.
  • Collaborative Editing (Google Docs): කිහිප දෙනෙක් එකම document එකේ type කරන විට, කරන වෙනස්කම් සැමටම සජීවීව පෙනීම.

මෙය සිදුකිරීමට, client (browser) සහ server අතර නිරන්තර, දෙපැත්තටම ක්‍රියාත්මක වන සන්නිවේදන මාර්ගයක් (persistent, bidirectional connection) අවශ්‍ය වේ. මේ සඳහා WebSockets නම් තාක්ෂණය බහුලව භාවිත වන අතර, Socket.IO යනු එය ඉතා පහසුවෙන් ක්‍රියාවට නැංවීමට අපට උපකාර වන library එකකි.

පියවර 1: Node.js Server එක නිර්මාණය කිරීම 🖥️

කවුන්ටරයේ වත්මන් අගය තවදුරටත් එක් එක් browser එකේ වෙන් වෙන්ව තබා නොගෙන, සියලු දෙනාටම පොදු මධ්‍යම ස්ථානයක තබා ගනිමු. මෙම මධ්‍යම ස්ථානය තමයි අපේ **Server** එක. කවුරුන් හෝ කවුන්ටරය වෙනස් කළ විට, ඔවුන් දැනුම් දෙන්නේ server එකටයි. ඉන්පසු server එක විසින් එම නව අගය අනෙක් සැමටම දැනුම් දෙනු ලබයි.

2.1: Server Project එක සකස් කිරීම

ඔබේ `react-counter` project folder එකෙන් පිටතට පැමිණ, ඒ අසලින් `server` නමින් අලුත් folder එකක් සාදන්න. ඉන්පසු terminal එකක් open කර, එම `server` folder එකට ඇතුල් වන්න.

cd path/to/your/projects/server

දැන්, මෙම folder එක Node.js project එකක් බවට පත් කිරීමට `npm init -y` command එක run කරන්න. මෙය `package.json` ගොනුවක් සාදනු ඇත.

npm init -y

අපේ server එකට අවශ්‍ය libraries දෙක වන `Express` සහ `Socket.IO` දැන් install කරගනිමු.

npm install express socket.io

2.2: Server කේතය ලිවීම (`index.js`)

`server` folder එක තුල `index.js` නමින් අලුත් ගොනුවක් සාදා, පහත සම්පූර්ණ කේතය അതിൽ copy-paste කරන්න. එක් එක් පේළියෙන් සිදුවන්නේ කුමක්දැයි කේතය පහලින් විස්තර කර ඇත.

// server/index.js const express = require('express'); const http = require('http'); const { Server } = require("socket.io"); const app = express(); const server = http.createServer(app); // CORS දෝෂ මගහැරවීමට, ඕනෑම origin එකකින් එන සම්බන්ධතා වලට ඉඩ දීම const io = new Server(server, { cors: { origin: "*", methods: ["GET", "POST"] } }); // කවුන්ටරයේ අගය server එකේ මතක තබා ගැනීම (Single Source of Truth) let count = 0; // Client කෙනෙක් connect වූ විට කුමක් කල යුතුද යන්න මෙහි định nghĩa කරයි io.on('connection', (socket) => { console.log('✅ a user connected:', socket.id); // 1. අලුතින් connect වූ client ට පමණක් වත්මන් 'count' අගය යැවීම socket.emit('count', count); // 2. client කෙනෙක් 'increment' event එකක් එව්වොත් සවන් දීම socket.on('increment', (step = 1) => { count += Number(step); // 3. සියලුම clients ලාටම අලුත් 'count' අගය broadcast කිරීම io.emit('count', count); }); // 4. client කෙනෙක් 'reset' event එකක් එව්වොත් සවන් දීම socket.on('reset', () => { count = 0; // 5. සියලුම clients ලාටම අලුත් 'count' අගය (0) broadcast කිරීම io.emit('count', count); }); socket.on('disconnect', () => { console.log('❌ user disconnected:', socket.id); }); }); const PORT = 3001; server.listen(PORT, () => { console.log(`🚀 Socket.IO server running on http://localhost:${PORT}`); });
කේතය පැහැදිලි කිරීම:
  • `io.on('connection', ...)`: Client කෙනෙක් අපේ server එකට connect වූ සැණින් මෙම function එක ක්‍රියාත්මක වේ.
  • `socket.emit(...)`: යම් event එකක්, එම මොහොතේ connect වූ **එක් client කෙනෙකුට පමණක්** යැවීමට භාවිත කරයි. (උදා: අලුතින් ආ කෙනාට count එක යැවීම).
  • `socket.on(...)`: Client කෙනෙක් එවනු ලබන event එකකට **සවන් දීමට** (listen කිරීමට) server එකේදී භාවිත කරයි.
  • `io.emit(...)`: යම් event එකක්, server එකට connect වී සිටින **සියලුම clients ලාට** එකවර යැවීමට (broadcast) භාවිත කරයි. (උදා: count එක update වූ පසු සැමටම දැනුම් දීම).
2.3: Server එක Run කිරීම

දැන්, server එකේ terminal එක තුල පහත command එක run කර server එක ආරම්භ කරන්න.

node index.js

ඔබට `🚀 Socket.IO server running on http://localhost:3001` ලෙස පණිවිඩයක් දිස්විය යුතුය. Server එක දැන් සූදානම්!

පියවර 2: React Client එක Server එකට සම්බන්ධ කිරීම 🔗

දැන් අපේ React app එක (Client), අලුතින් සෑදූ server එක සමග සන්නිවේදනය කරන ලෙස සකස් කරමු.

3.1: Client Library එක Install කිරීම

දැන්, `react-counter` project එකේ terminal එක වෙත ගොස් (අවශ්‍ය නම් අලුත් terminal tab එකක් open කරන්න), Socket.IO client library එක install කරන්න.

npm install socket.io-client

3.2: `Counter.jsx` ගොනුව යාවත්කාලීන කිරීම

දැන් `localStorage` සහ අනෙකුත් දේවල් අනවශ්‍යයි, මන්ද, කවුන්ටරයේ "සත්‍ය අගය" (source of truth) දැන් තිබෙන්නේ server එකේය. `src/Counter.jsx` ගොනුව open කර, එහි සම්පූර්ණ කේතය පහත කේතයෙන් replace කරන්න.

// src/Counter.jsx import React, { useState, useEffect } from 'react'; import { io } from "socket.io-client"; // 1. Client library එක import කිරීම // 2. අපේ server එකට සම්බන්ධතාවය ගොඩනැගීම const socket = io("http://localhost:3001"); export default function Counter() { // වත්මන් count අගය තබා ගැනීමට state එකක්. ආරම්භක අගය server එකෙන් ලැබේ. const [count, setCount] = useState('...'); const [step, setStep] = useState(1); // Component එක mount වූ විට socket listeners සකස් කිරීම useEffect(() => { // 3. Server එකෙන් එවන 'count' event එකට සවන් දීම socket.on('count', (newCount) => { setCount(newCount); // Server එකෙන් එවන නව අගයෙන් state එක update කිරීම }); // 4. Cleanup: Component එක unmount වන විට listener එක ඉවත් කිරීම // මෙය memory leaks වළක්වා ගැනීමට ඉතා වැදගත්! return () => { socket.off('count'); }; }, []); // [] හිස් නිසා, මෙය component එක mount වන විට එක් වරක් පමණක් run වේ // 5. බොත්තම් click කළ විට, state එක update කරනවා වෙනුවට, server එකට event යැවීම const increment = () => socket.emit('increment', step); const decrement = () => socket.emit('increment', -step); // අඩු කිරීමට, ঋণাত্মক step එකක් යැවීම const reset = () => socket.emit('reset'); return ( <div className="counter"> <div className="display"> Count: <strong>{count}</strong> </div> <div className="controls"> <button onClick={decrement} aria-label="decrement">-</button> <button onClick={increment} aria-label="increment">+</button> <button onClick={reset}>Reset</button> </div> <div className="step"> <label> Step: <input type="number" min="1" value={step} onChange={e => setStep(e.target.value)} /> </label> </div> </div> ); }

නව ක්‍රියාවලිය (New Flow):

User Click ➡️ React `socket.emit()` ➡️ Node.js Server ➡️ Server `io.emit()` ➡️ All Connected React Clients ➡️ `socket.on()` updates state ➡️ UI Re-renders

පියවර 3: The Grand Finale! - අවසන් පරීක්ෂාව 🥳

දැන් සියල්ල සූදානම්. අපි අපේ නිර්මාණය ක්‍රියාත්මක කර බලමු!

  1. ඔබේ **server එකේ terminal** එකේ `node index.js` ක්‍රියාත්මක වන බවට වග බලා ගන්න.
  2. ඔබේ **React app එකේ terminal** එකේ `npm run dev` ක්‍රියාත්මක වන බවට වග බලා ගන්න.
  3. දැන්, ඔබේ web browser එකේ අලුත් **windows දෙකක්** (හෝ එකක් normal සහ එකක් incognito) open කර, දෙකේදීම `http://localhost:5173` (හෝ ඔබේ React app URL එක) වෙත පිවිසෙන්න.
  4. එක් window එකක ඇති `+` බොත්තම click කරන්න.
ප්‍රතිඵලය: ඔබ එක් window එකක අගය වෙනස් කළ සැනින්, අනෙක් window එකේ ඇති කවුන්ටරයේ අගය ද ඒ මොහොතේදීම update වන ආකාරය ඔබට දැකගත හැකි වනු ඇත! ඔබ සාර්ථකව සම්පූර්ණ Real-time web application එකක් නිර්මාණය කර ඇත!