Reactive Accelerator
React Js
React Escape Hatches
4.14 - Reusing Logic with Custom Hook

রিয়াক্টে বিভিন্ন কাজ করার জন্য বিভিন্ন বিল্ট-ইন হুক রয়েছে যেমনঃ useState, useEffect,useContext. কিন্তু কাজ করতে গিয়ে আপনার মাঝে মধ্যে মনে হতে পারে যে, আমার এই কাজটার জন্য যদি রিয়াক্টের কোন হুক থাকতো ! আপনি এমন সিচুয়েশনে আপনার নিজের একটা কাস্টম হুক বানাতে পারেন।

আমরা এই লিসনে সেটাই জানবো যে, কাস্টম হুক কি ? কিভাবে বানাতে হয় ইত্যাদি বিস্তারিত।

Custom Hooks: Sharing logic between components

ধরুন আপনি এমন একটা এপ্লিকেশন বানাচ্ছেন যেখানে আপনাকে বার বার চেক করতে হয় যে ইউজার online নাকি offline। যদি ইউজার অনলাইনে থাকে তাহলে আপনি অনলাইন নামে একটা স্ট্যাটাস দেখাতে চান আর অফলাইন হয়ে গেলে অফলাইন দেখাতে চান।

তাহলে আপনাকে দুইটা কাজ করা লাগবে,

  1. একটা স্টেট লাগবে যেটা ট্র্যাক করবে ইউজার অনলাইন নাকি অফলাইন আর সেটা JSX এর মাধ্যমে UI তে দেখাবে
  2. ব্রাউজারের অনলাইন এবং অফলাইন ইভেন্টকে এক্সেস করার জন্য একটা ইফেক্ট লাগবে যেটা স্টেট কে আপডেট করবে।

এক্ষেত্রে আপনার কোড হবে এমনঃ

import { useEffect, useState } from "react";
 
const StatusBar = () => {
    const [isOnline, setIsOnline] = useState(true);
 
    useEffect(() => {
        function handleOnline() {
            setIsOnline(true);
        }
        function handleOffline() {
            setIsOnline(false);
        }
 
        window.addEventListener("online", handleOnline);
        window.addEventListener("offline", handleOffline);
        return () => {
            window.removeEventListener("online", handleOnline);
            window.removeEventListener("offline", handleOffline);
        };
    }, []);
 
    return <div>{isOnline ? "✅ Online" : "❌ Disconnected"} </div>;
};
 
export default StatusBar;

এবং এতে আপনার কাজ হয়ে যাবে, কিন্তু ধরুন আপনি এমন আরও একটা কম্পোনেন্ট বানালেন যেখানে আপনাকে ইউজার অনলাইনে থাকলে একটা কিছু দেখাতে হবে আর যদি অফলাইন হয়ে যায় সেক্ষেত্রে আরেকটা কিছু দেখাতে হবে।

ধরুন আরেকটা কম্পোনেন্টে একটা Play Now বাটন আছে, সেই বাটনটা ডিজেবল থাকবে যদি ইউজার এর নেটওয়ার্ক অফলাইন হয়ে যায় এবং সেক্ষেত্রে বাটনের টেক্সট দেখাবে Reconnecting...। এক্ষেত্রেও কিন্তু আপনাকে ইউজারের নেটওয়ার্ক স্ট্যাটাস টাই জানা লাগছে, এখন আপনি চাইলে সেই আগের কম্পোনেন্ট থেকে কোডটা কপি করে এই কম্পোনেন্টে পেস্ট করেও কাজ করে ফেলতে পারেন। কিন্তু এটা কোনভাবেই কোন এফিসিয়েন্ট উপায় হলোনা।

কিন্তু তার চাইতে যদি এমন করা যেত যে, ইউজার অনলাইন নাকি অফলাইন এই স্টেটসহ লজিকটাকে একটা আলাদা রি-ইউজেবল কাস্টম হুক বানিয়ে নেয়া যেত ? তাহলে আমরা যত খুশি,যেখানে খুশি সেটাকে রি-ইউজ করতে পারতাম।

এই স্টেটফুল লজিকগুলোকে একটা আলাদা হুক বানিয়ে নেয়টাই হলো একটা কাস্টম হুক বানানো। চলুন আগের লজিকটাকে একটা কাস্টম হুকে কনভার্ট করি।

Extracting your own custom Hook from a component

প্রথমে হুকের জন্য একটা আলাদা ফাইল বানাবো এবং এবং তাতে কাস্টম হুক বানানোর জন্য একটা ফাংশন ডিক্লেয়ার করবো।

আমাদেরকে একটা আলাদা ফাইল বানাতে হবে, ফাইলের নাম আমরা যেকোন কিছু দিতে পারি, কিন্তু কনভেনশন হলো যেই হুক বানাচ্ছি সেই হুকের সাথে মিলিয়ে ফাইলের নামটা দেওয়া । এবং হুকের জন্য যেই ফাংশনটা লিখবো সেটাও যেন যেই কাজ করতে চাচ্ছি, একদম সেই কাজ স্পেসিফিক হয়। আর অবশ্যই ফাংশনের নামের শুরুতে use দিয়ে শুরু করতে হবে এবং তার পরের প্রথম অক্ষর বড় হাতের দিয়ে শুরু করতে হবেনা।

এই উদাহরণে আমরা ইউজারের online স্ট্যাটাস চেক করবো,আর তাই আমরা হুকের নাম দিচ্ছি useOnlineStatus

useOnlineStatus.js
export default function useOnlineStatus(){
 
}
 

তারপর কম্পোনেন্টের ভিতর আমরা যেই লজিক লিখেছিলাম সেটা কম্পোনেন্ট থেকে cut করে এনে হুকের ভিতরে paste করতে হবে।

import { useEffect, useState } from "react";
 
export default function useOnlineStatus() {
    const [isOnline, setIsOnline] = useState(true);
 
    useEffect(() => {
        function handleOnline() {
            setIsOnline(true);
        }
        function handleOffline() {
            setIsOnline(false);
        }
 
        //syncronization
        window.addEventListener("online", handleOnline);
        window.addEventListener("offline", handleOffline);
        //cleanup
        return () => {
            window.removeEventListener("online", handleOnline);
            window.removeEventListener("offline", handleOffline);
        };
    }, []);
}

তারপর আমদের যেই ভ্যালুটা বা ভ্যারিয়েবলটা আমাদের কম্পোনেন্টে দরকার হবে সেটা হুকের ফাংশন থেকে রিটার্ন করে দিতে হবে।

এক্ষেত্র যদি একাধিক ভ্যারিয়েবল প্রয়োজন হয় তাহলে অবজেক্ট আকারে রিটার্ন করা যেতে পারে। যেহেতু আমাদের কম্পোনেন্টর শুধু অনলাইন স্ট্যাটাস টা দরকার তাই আমরা এখান থেকে শুধু অনলাইন isOnline রিটার্ন করে দিচ্ছি।

import { useEffect, useState } from "react";
 
export default function useOnlineStatus() {
    const [isOnline, setIsOnline] = useState(true);
 
    useEffect(() => {
        function handleOnline() {
            setIsOnline(true);
        }
        function handleOffline() {
            setIsOnline(false);
        }
 
        //syncronization
        window.addEventListener("online", handleOnline);
        window.addEventListener("offline", handleOffline);
        //cleanup
        return () => {
            window.removeEventListener("online", handleOnline);
            window.removeEventListener("offline", handleOffline);
        };
    }, []);
    return isOnline;
}

তারপর কম্পোনেন্টের ভিতরে টপ লেভেলে হুকটাকে কল করে isOnline টা বের করে কন্ডিশনালি কাজ করতে পারি।

import useOnlineStatus from "../../hooks/useOnlineStatus";
 
const StatusBar = () => {
    const isOnline = useOnlineStatus();
    return <div>{isOnline ? "✅ Online" : "❌ Disconnected"} </div>;
};
 
export default StatusBar;

এই কয়টা স্টেপেই হয়ে গেলও আমাদের কাস্টম হুক। এখন এই হুক কে আমাদের যতবার খুশি,আর যেখানে খুশি ব্যাবহার করতে পারবো।

Hook names always start with use

রিয়াক্ট এপ্লিকেশনে কম্পোনেন্ট এবং হুকের জন্যে নিচের নেমিং কনভেনশন ফলো করতে হয়,

  1. React component names must start with a capital letter রিয়াক্টের কম্পোনেন্টের নামের প্রথম অক্ষর বড় হাতের দিয়ে শুরু করতে হয়।
  2. Hook names must start with use followed by a capital letter হুকের নামের শুরুতে use দিয়ে শুরু করতে হবে এবং তারপরের প্রথম অক্ষর অবশ্যই বড় হাতের দিতে হবে।

Should all functions called during rendering start with the use prefix?

না, নরমাল ফাংশনগুলোর নাম কখনও use দিয়ে শুরু করতে হয়না। use প্রিফিক্স একমাত্র হুকের (বিল্ট-ইন অথবা কাস্টম হুক) নামের শুরুতে ব্যাবহার করতে হবে।

যদি কোন ফাংশন তার ভিতরে রিয়াক্টের কোন হুক কে ব্যাবহার না করে, তাহলে তাকে হুক না বানিয়ে নরমাল ফাংশন হিসেবে ব্যাবহার করতে হবে। কেননা রেগুলার ফাংশন হিসেবে লিখলে আপনি এটাকে কম্পোনেন্ট এর যেকোন জায়গায় ব্যাবহার করতে পারবেন অন্যদিকে হুক হিসেবে ব্যাবহার করলে এটাকে শুধু কম্পোনেন্ট এর টপ লেবেলে ব্যাবহার করতে হবে।

When to use custom Hooks

আপনাকে আপনার কোডের প্রতিটা ছোট ছোট ডুপ্লিকেট কমানোর জন্য কাস্টম হুক বানানোর দরকার নেই, আপনি কিছু কিছু যৌক্তিক ডুপ্লিকেট করতে পারবেন, আর এটা করা ভালো।

আপনি যখন কোন ইফেক্ট ব্যাবহার করবেন, তখন আপনি রিয়াক্টের বাহিরের কোন কিছুকে এক্সেস করতে চাইছেন, এপ্নি হয়তো একবার একটা ইফেক্ট লিখছেন এবং এই এফেক্ট টা আপনাকে অনেক অনেক কম্পোনেন্টে ব্যাবহার করতে হবে, এই ক্ষেত্রে আপনি ইফেক্টকে কাস্টম হুক বানিয়ে নিতে পারেন

Custom Hooks help you migrate to better patterns

ইফেক্টগুলো হলো Escape Hatch। আপনি যখন কোন ইফেক্ট ব্যাবহার করছেন তখন আপনি রিয়াক্টের বাহিরের কোন API কে এক্সেস করছেন। রিয়াক্ট টিম এটা নিয়ে প্রতিনিয়ত কাজ করে যাচ্ছে যাতে আপনাকে খুব বেশি ইফেক্ট ব্যবহার না করতে হয়। তার ইফেক্টগুলোর জন্য কিছু বিল্ট-ইন হুক দিয়ে দিবে, তাই আপনি যদি আপনার বর্তমান কোডবেজের ইফেক্টগুলোকে কাস্টম হুক বানিয়ে ব্যাবহার করেন তাহলে আগামী ভার্সনে রিয়াক্ট যখন এসবের জন্য বিল্ট ইন হুক রিলিজ করবে তখন খুব সহজেই আপনি সেগুলো ব্যবহার করে খুব কম চেঞ্জ করার মাধ্যমে আপনি আপনার হুকগুলোকে সেগুলোতে মাইগ্রেট করতে পারবেন।