useRef এর আদ্যোপান্ত

useRef এর আদ্যোপান্ত

কিছুদিন আগে আমি useEffect সম্পর্কে ভাল একটা ধারণা দেয়ার চেষ্টা করেছিলাম। আজ আপনাদের সামনে আমি নিয়ে আসছি রিয়্যাক্টের অন্যতম একটি গুরুত্বপূর্ণ হুক যার নাম useRef। এই আর্টিকেলে আমি useRef সম্পর্কে যা যা দরকার সব নিয়ে ধারণা দেয়ার চেষ্টা করবো।

useRef কি?

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

useRef হলো সেই খাতার মতো যেখানে আপনি আপনার ডাটা স্টোর করে রাখতে পারবেন এবং যখন খুশি এক্সেস করতে পারবেন। এখন প্রশ্ন হলো useState ও তো একই কাজ করে, তাহলে আলাদাভাবে useRef এর কাজ কি? সেটা বোঝার জন্য চলুন আমরা নিচের উদাহরণটি দেখি।

import { useRef, useState } from 'react';

const Counter = () => {
    const [count, setCount] = useState(0);
    const countRef = useRef(0);

    const handleClick = () => {
        setCount(count + 1);
        countRef.current++;

        console.log('State: ', count);
        console.log('Ref: ', countRef.current);
    };

    return (
        <div>
            <h1>Counter: {count}</h1>
            <button onClick={handleClick}>Increment</button>
        </div>
    );
};

export default Counter;

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

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

যদি আমরা আগের উদাহরণ থেকে স্টেট রিলেটেড সবকিছু বাদ দিয়ে দিই তাহলে কি দাঁড়ায় দেখি।

import { useRef } from 'react';

const Counter = () => {
    const countRef = useRef(0);

    const handleClick = () => {
        countRef.current++;

        console.log('Ref: ', countRef.current);
    };

    return (
        <div>
            <h1>Counter: {countRef.current}</h1>
            <button onClick={handleClick}>Increment</button>
        </div>
    );
};

export default Counter;

দেখুন ভ্যালু আপডেট হচ্ছে ঠিকই, কিন্তু তা UI এ শো করছে না। যেহেতু useRef এর ভ্যালু কোনো রিরেন্ডার ছাড়া আপডেট হয়, সুতরাং UI এ কোনো চেইঞ্জ দেখা যাবে না। যদি আপনারা চান যে ডাটা আপডেটের সাথে সাথে তা UI তে শো করবে তাহলে useState ইউজ করবেন।

Examples

Focusing Input

আমরা অনেক সময় চাই যে কোনো ফর্মের প্রথম ইনপুট অটোমেটিক্যালি ফোকাস হয়ে থাকুক। এই কাজটা আমরা useRef এর মাধ্যমে সহজে করে ফেলতে পারি।

import { useEffect, useRef } from 'react';

const InputComponent = () => {
    const inputRef = useRef(null);

    useEffect(() => {
        inputRef.current.focus();
    }, []);

    return (
        <div>
            <input ref={inputRef} type="text" placeholder="email" />
            <input type="text" placeholder="password" />
            <input type="text" placeholder="confirm password" />
        </div>
    );
};

export default InputComponent;

দেখুন প্রথম ইনপুট অটোমেটিক্যালি ফোকাস হয়ে আছে।

Notification Handle

এই কাজটা সাধারণত আমরা ইকমার্স সাইটে কার্ট হ্যান্ডেলিং এর সময় বেশি করে থাকি। যখন Add to Cart এ ক্লিক করবো তখন একটা ছোট নোটিফিকেশন দেখাবে। যটবার অ্যাড করবো ততবারই তা দেখাবে। আমরা যদি সেটা useState ব্যবহার করে হ্যান্ডেল করি তাহলে কি হয় দেখি।

import { useState } from 'react';

const App = () => {
    const [notification, setNotification] = useState('');

    const showNotification = (message, duration) => {
        setNotification(message);

        setTimeout(() => {
            setNotification('');
        }, duration);
    };

    return (
        <div>
            <button onClick={() => showNotification('Item added to cart', 2000)}>
                Add to Cart
            </button>
            {notification && (
                <div
                    style={{
                        position: 'fixed',
                        top: '20px',
                        left: '50%',
                        transform: 'translateX(-50%)',
                        padding: '10px',
                        backgroundColor: 'rgba(0, 0, 0, 0.7)',
                        color: '#fff',
                        borderRadius: '5px',
                        zIndex: '9999',
                    }}
                >
                    {notification}
                </div>
            )}
        </div>
    );
};

export default App;

খুবই সিম্পল একটা অপারেশন। এখন আপনি যদি বাটনে ক্লিক করেন একটা নোটিফিকেশন আসবে এবং ২ সেকেন্ড পর চলে যাবে। ২ সেকেন্ড শেষ হওয়ার আগে যদি আপনি আবার বাটনে ক্লিক করেন আপনার আশা থাকবে যে নোটিফিকেশন আবার ২ সেকেন্ডের জন্য শো হবে। কিন্তু দেখলেন ওমা! এতো সাথে সাথে চলে যাচ্ছে। অর্থাৎ সে শুধু প্রথম নোটিফিকেশনের টাইমিং নিয়েই আছে। পরেরটা আর পায়নি। এটা থেকে মুক্তির উপায় হলো useRef

import { useRef, useState } from 'react';

const App = () => {
    const [notification, setNotification] = useState('');
    const notificationRef = useRef(null);

    const showNotification = (message, duration) => {
        setNotification(message);
        clearTimeout(notificationRef.current);

        notificationRef.current = setTimeout(() => {
            setNotification('');
        }, duration);
    };

    return (
        <div>
            <button onClick={() => showNotification('Item added to cart', 2000)}>
                Add to Cart
            </button>
            {notification && (
                <div
                    style={{
                        position: 'fixed',
                        top: '20px',
                        left: '50%',
                        transform: 'translateX(-50%)',
                        padding: '10px',
                        backgroundColor: 'rgba(0, 0, 0, 0.7)',
                        color: '#fff',
                        borderRadius: '5px',
                        zIndex: '9999',
                    }}
                >
                    {notification}
                </div>
            )}
        </div>
    );
};

export default App;

এবার আপনি যখনই বাটনে ক্লিক করবেন সে তখন থেকে ২ সেকেন্ড পর্যন্ত নোটিফিকেশন শো করবে। এটাই useRef এর পাওয়ার।

Video Play and Pause

ভিডিও প্লেয়ার নিয়ে কাজ করতে গেলে আপনাকে প্লে এবং পজ ফাংশনালিটিজ নিয়ে কাজ করতেই হয়। সেক্ষেত্রে আপনার কাজ সহজ করার জন্য আছে useRef

import { useRef, useState } from 'react';

const App = () => {
    const [isPlaying, setIsPlaying] = useState(false);
    const ref = useRef(null);

    function handleClick() {
        const nextIsPlaying = !isPlaying;
        setIsPlaying(nextIsPlaying);

        if (nextIsPlaying) {
            ref.current.play();
        } else {
            ref.current.pause();
        }
    }

    return (
        <>
            <button onClick={handleClick}>{isPlaying ? 'Pause' : 'Play'}</button>
            <video
                width="250"
                ref={ref}
                onPlay={() => setIsPlaying(true)}
                onPause={() => setIsPlaying(false)}
            >
                <source
                    src="https://interactive-examples.mdn.mozilla.net/media/cc0-videos/flower.mp4"
                    type="video/mp4"
                />
            </video>
        </>
    );
};

export default App;

এসব ছাড়াও টাইমার অ্যাপ্লিকেশন, ম্যাসেজ আনডু ইত্যাদি কাজে useRef প্রচুর ব্যবহৃত হয়।

আশা করি আপনারা useRef সম্পর্কে ভাল একটা ধারণা পেয়েছেন। আপনাদের মতামত আমাকে কমেন্টে জানাবেন।