Synchronizing with Effects
যখন আমাদের কোন এক্সটার্নাল API নিয়ে কাজ করা লাগবে বা কোন সাইড ইফেক্ট (যেমনঃ API কল করা, এলার্ট দেখানো, ডাটাবেজ এক্সেস করা) হ্যান্ডেল করা লাগবে তখন আমরা useEffect
ব্যাবহার করবো।
মনে রাখতে হবে যে যেসব একশন অটোমেটিক ট্রিগার হতে হবে সেগুলাই useEffect
এর মাধ্যমে হেন্ডেল করা লাগবে আর যেগুলো ইউজারের কোন একশনের ভিত্তিতে ট্রিগার হবে সেগুলো event handler
এর মাধ্যমে হেন্ডেল করা লাগবে।
যেমন ধরুন আমাদের কম্পোনেন্ট লোড হয়ে যাওয়ার সাথে সাথেই আমদের স্ক্রিনে সকল প্রডাক্ট এর লিস্ট দেখাতে হবে, এই প্রডাক্ট এর লিস্ট আসছে API থেকে। তাহলে এক্ষেত্রে আমাদের এমন কিছু করতে হবে যে আমাদের কোন event handler
ছাড়াই কম্পোনেন্ট লোড হয়ে যাওয়ার সাথে সাথেই অটোমেটিক ভাবে API কল করে দিতে হবে। এই অটোমেটিক কাজটাই আমরা useEffect
দিয়ে করতে পারি।
আবার ধরুন কোন একটা প্রডাক্টের কার্ডে Show Details
নামে একটা বাটন আছে,যেখানে ক্লিক করলে প্রডাক্টের ডিটেইলস দেখাবে, এইযে ক্লিক করলে কিছু হবে, এটা আমরা event handler
দিয়ে করবো
useEffect
শুধুমাত্র কম্পোনেন্ট রেন্ডার হয়ে কমিট হয়ে যাওয়ার পর এক্সিকিউট হয়। মানে হলো আমরা ইফেক্টের ভিতর যা লিখবো তা শুধুমাত্র আমাদের কম্পোনেন্ট লোড হয়ে স্ক্রিনে চলে আসার পর এক্সিকিউট হবে।
How to write an Effect (কিভাবে ইফেক্ট লিখতে হয়)
ইফেক্ট লিখতে হলে আমাদেরকে তিনটি স্টেপ ফলো করতে হয়, চলুন বিস্তারিত জেনে নেই।
- Declare an Effect. (ইফেক্ট ডিক্লেয়ার করা)
- Specify the Effect dependencies.(ইফেক্ট রান হউয়ার ডিপেন্ডেসিগুলো বলে দেয়া)
- Add cleanup if needed.(ইফেক্ট ক্লিন-আপ করা যদি প্রয়োজন হয়)
Declare an Effect. (ইফেক্ট ডিক্লেয়ার করা)
ইফেক্ট ডিক্লেয়ার করার জন্য সর্বপ্রথম আমাদের কম্পোনেন্টের ভিতর useEffect
হুক কে ইম্পোর্ট করতে হবে। এবং তারপর useEffect
কে কম্পোনেন্টের টপ লেবেলে কল করতে হবে।
import React from 'react'
const App = () => {
useEffect(()=>{
// effect code will go here
})
return (
<div>
<h1>Hello World! </h1>
</div>
)
}
export default App
ইফেক্টের কোড শুধুমাত্র কম্পোনেন্ট রি-রেন্ডার হয়ে যাওয়ার পর স্ক্রিনে যখন ভিজিবল হয় শুধুমাত্র তখন এক্সিকিউট হয়। এই অবস্থায় ইফেক্টের ভিতরে আমরা যা লিখবো তা প্রতিবার আমাদের কম্পোনেন্ট রি-রেন্ডার হউয়ার সাথে সাথে রান হবে।
কিন্তু এইটা তো একটা সমস্যা, কেননা আমরা যদি এফেক্ট এর ভিতরে এমন কিছু লিখি যা আমাদের শুধুমাত্র একবার কম্পোনেন্ট লোড হউয়ার সময় রান করা দরকার, পরে আর কম্পোনেন্ট রি-রেন্ডার হলেও আমারা ইফেক্টের ওই কোড রান করাতে চাইনা। যেমন ধরুনঃ আমরা কোন কম্পোনেন্টে কোন সার্ভারের সাথে কানেক্ট করালাম, এখন সেই কম্পোনেন্টে একটা ইনপুট ফর্ম আছে, তাহলেতো প্রতিবার টাইপিং এ আমাদের কম্পোনেন্ট রি-রেন্ডার হবে এবং প্রতিবার আমাদের ইফেক্ট রান হবে এবং সার্ভারের সাথে কানেকশন করাবে। কিন্তু এই কানেকশন করানো কি আমাদের প্রতিটা কি-প্রেসে দরকার আছে ? আমরা শুধু চাই আমাদের কম্পোনেন্ট যদি প্রথমবার লোড হয় তাহলে শুধুমাত্র যেন সার্ভারের সাথে কানেকশনটা হয়।
তাহলে আমাদের এমন কিছু দরকার যা দিয়ে আমরা এই বিহেবিয়ার টা কনট্রোল করতে পারি। এই জন্যই আমরা এফেক্টে ডিপেন্ডেন্সি এড করবো।
Specify the Effect dependencies.(ইফেক্ট রান হউয়ার ডিপেন্ডেসিগুলো বলে দেয়া)
রিয়াক্টের ইফেক্টের উপর আমাদের কনট্রোল আনার জন্য আমরা ডিপেন্ডেসি এড করবো। কেননা আমরা বলে দিতে চাই যে আমাদের কম্পোনেন্ট কখন কখন রান করা উচিত, এটা কি প্রতিটা রি-রেন্ডারে কল হবে নাকি শুধুমাত্র একবার কল হবে নাকি কোন নির্দিষ্ট বিষয়ের উপর ডিপেন্ড করে কল হবে।
ডিপেন্ডেসি এড করার জন্য আমাদের ইফেক্ট এর সেকন্ড প্যারামিটারে কিছু ভ্যালু ( [] অথবা অন্যান্য ডিপেন্ডেন্সি) দিতে হয় ।
যদি আমরা চাই যে প্রতিবার রি-রেন্ডারে ইফেক্ট কল হবে তাহলে এভাবে লিখতে হয়
useEffect(() => {
//code will go here
});
এক্ষেত্র কোন ডিপেন্ডেসি বলে দিতে হয়না ।
যদি আমরা চাই যে শুধু প্রথম রেন্ডারে ইফেক্ট কল হবে এবং পরবর্তিতে কম্পোনেন্ট রি-রেন্ডার হলেও আর ইফেক্ট কল হবেনা, তাহলে এভাবে লিখতে হয়
useEffect(() => {
// code will go here
}, []);
এক্ষেত্র সেকন্ড প্যারামিটারে শুধুমাত্র একটা [] দিতে হয়
যদি আমরা চাই যে কম্পোনেন্ট লোড হউয়ার সাথে সাথে একবার রান হবে এবং কোন স্পেসিফিক কিছু চেঞ্জ হলে আবার রান হবে,সেক্ষেত্রে আমাদের সেকেন্ড প্যারামিটারে [] এর ভিতরে ডীপেন্ডেন্সিগুলো বলে দিতে হবে
useEffect(() => {
//code will go here
}, [a, b]);
এক্ষেত্রে আমরা ডিপেন্ডেন্সিতে a
এবং b
এড করেছি, এটা যে কোন কিছু হতে পারে,যেগুলো আমরা আমাদের ইফেক্টের ভিতর ব্যাবহার করেছি, সেগুলো ডিপেন্ডেন্সিতে এড করা লাগবে, আমরা মাল্টিপল ডিপেন্ডেন্সি এড করতে পারি। আমাদের কি কি ডিপেন্ডেন্সি এড করা লাগবে তা eslint
আমাদের অটোমেটিক সাজেশন দিবে। আমরা সেগুলো ফলো করেও ডিপেন্ডেন্সি এড করতে পারি।
তবে আমাদের বুঝতে হবে যে কোন কোন ভ্যালূ চেঞ্জ হলে আমরা এফেক্ট আবার রান করাতে চাই,সেগুলোই আমরা ইফেক্টের ডিপেন্ডেন্সি হিসেবে ব্যাবহার করবো।
আমরা ডিপেন্ডেন্সি তে যেসব ভ্যালু এড করবো রিয়াক্ট প্রতিবার কম্পোনেন্ট রেন্ডার হয়ে যাওয়ার পর চেক করে দেখবে যে সেই ভ্যালুগুলো আগের রেন্ডারে যা ছিল পরের রেন্ডারে কি তাই আছে নাকি চেঞ্জ হয়েছে, আর এটা করবে রিয়াক্ট জাভাস্ক্রিপ্টের Object.is()
মেথডের মাধ্যমে। যদি কোন একটার ভ্যালু চেঞ্জ হয় তাহলেই রিয়াক্ট এফেক্টকে আরেকবার কল করবে।
Add cleanup if needed.(ইফেক্ট ক্লিন-আপ করা যদি প্রয়োজন হয়)
চলুন একটা উদাহরণের কথা ভাবা যাক,যাতে আমরা বুঝতে পারি যে কখন আমাদের ক্লিন-আপ করা প্রয়োজন এবং ক্লিন-আপ কেন করতে হবে।
ধরুন আমাদের একটা চ্যাট এপ্লিকেশন আছে। এখন যখনি কোন ইউজার চ্যাট করার জন্য এপ্লিকেশনটা অন করে চ্যাট কম্পোনেন্টে ক্লিক করবে সাথে সাথে ইফেক্টের মাধ্যমে একটা চ্যাট সার্ভারের সাথে কানেকশন ঘটাবে।
import { useEffect } from 'react';
import { createConnection } from './chat.js';
export default function ChatRoom() {
useEffect(() => {
const connection = createConnection();
connection.connect();
}, []);
return <h1>Welcome to the chat!</h1>;
}
এখন ইউজার আবার বেক করে অন্য কম্পোনেন্টে চলে গেল এবং পুনরায় আবার এসে চ্যাট কম্পোনেন্টে ক্লিক করলো, এখন আবার একটা কানেকশন ঘটলো।
খেয়াল করলে বুঝবেন যে, প্রথমবার যখন ইউজার চ্যাট আইকনে ক্লিক করার পর যেই কানেকশনটি হয়ছিল,ইউজার বেক করে অন্য পেজে চলে যাওয়ার পর কিন্তু সেই কানেকশনটি বন্ধ করা হয়নি এবং এবং ইউজার যখন আবার পুনরায় এসে আবার চ্যাট আইকনে ক্লিক করলো তখন আরও একটা কানেকশন ঘটলো, এভাবে যদি ইউজার বার বার বেক এন্ড ফোর্থ করতে থাকে তাহলে অসংখ্য কানেকশন রানিং হয়ে যাবে এবং এতে মেমরি লিক হবে। তাই সবসময় কম্পোনেন্ট যখন আনমাউন্ট হবে তখন প্রতিবার আমাদের ইফেক্টকে ক্লিন-আপ করে নিতে হবে।
ক্লিন-আপ করার জন্য আমাদের ইফেক্ট এর কলব্যাক ফাংশনের ভিতর থেকে রিটার্ন করতে হবে একটা ফাংশন কল, তার ভিতর আমরা ক্লিন-আপ লিখে দিবো।
useEffect(() => {
const connection = createConnection();
connection.connect();
return () => {
connection.disconnect();
};
}, []);