Redux অ্যাপ্লিকেশন ব্যবহারের সময়, performance optimization এবং immutable data handling দুইটি খুবই গুরুত্বপূর্ণ বিষয়। যেহেতু Redux-এর মাধ্যমে স্টেট ম্যানেজমেন্ট করা হয়, তাই সঠিকভাবে স্টেট হ্যান্ডলিং এবং রেন্ডারিং অপ্টিমাইজেশন না করলে অ্যাপ্লিকেশন স্লো হয়ে যেতে পারে। Redux স্টেটে পরিবর্তন করার সময় ডেটা যদি অপরিবর্তনীয় (immutable) না হয়, তবে এটি সঠিকভাবে কাজ করবে না এবং অ্যাপ্লিকেশনটি অপ্রত্যাশিতভাবে রেন্ডার হতে পারে।
এখানে আলোচনা করা হবে কীভাবে আপনি Redux-এ performance optimization এবং immutable data handling করতে পারেন।
Immutable Data Handling in Redux
Immutable data এমন ডেটা যা একবার তৈরি হলে সেটি কখনই পরিবর্তন হয় না। Redux-এর স্টেট অবশ্যই অপরিবর্তনীয় (immutable) থাকতে হবে, কারণ এই স্টেট পরিবর্তন করতে গিয়ে স্টেটের নতুন কপি তৈরি করা হয়, যাতে পুরোনো স্টেট অক্ষত থাকে।
Redux-এ স্টেট যদি পরিবর্তনশীল (mutable) হয়, তাহলে কিছু সমস্যা তৈরি হতে পারে:
- Unpredictable Behavior: যদি স্টেট পরিবর্তন হয় তবে আপনি কখনো জানবেন না যে, কবে কোথায় বা কীভাবে পরিবর্তন হচ্ছে।
- Inefficient Re-renders: স্টেট পরিবর্তন হলে কম্পোনেন্টগুলো পুনরায় রেন্ডার হতে পারে, যা পারফরম্যান্স কমাতে পারে।
- Difficult Debugging: স্টেট পরিবর্তনশীল হলে ডিবাগিং অনেক কঠিন হয়ে যায়।
তাহলে, Immutable ডেটা ম্যানেজমেন্টের জন্য কিছু কৌশল অবলম্বন করা হয়।
Immutable Data Handling এর পদ্ধতি
১. স্প্রেড অপারেটর (Spread Operator) ব্যবহার করা
Redux-এ স্টেট পরিবর্তন করতে হলে, আপনাকে পুরনো স্টেটের একটি কপি তৈরি করতে হবে। এর জন্য স্প্রেড অপারেটর (...) ব্যবহার করা যেতে পারে, যা অক্ষত রেখে একটি নতুন অবজেক্ট বা অ্যারে তৈরি করে।
function todosReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload]; // নতুন টুডো যোগ করা
case 'REMOVE_TODO':
return state.filter(todo => todo.id !== action.payload.id); // একটি টুডো বাদ দেওয়া
default:
return state;
}
}
এখানে, state এর পরিবর্তে নতুন অ্যারে তৈরি করা হচ্ছে, যা Immutable নিশ্চিত করে।
২. Object.assign() ব্যবহার করা
Object.assign() একটি অবজেক্টের নতুন কপি তৈরি করতে সাহায্য করে। এটি একটি নতুন অবজেক্ট রিটার্ন করে এবং এর মধ্যে পুরনো অবজেক্টের প্রপার্টি কপি করে।
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT':
return Object.assign({}, state, { count: state.count + 1 }); // স্টেটের নতুন কপি তৈরি করা
case 'DECREMENT':
return Object.assign({}, state, { count: state.count - 1 });
default:
return state;
}
}
এখানে Object.assign({}, state, { count: state.count + 1 }) ব্যবহার করে একটি নতুন অবজেক্ট তৈরি করা হচ্ছে এবং এটি Immutable রাখছে।
৩. Immutable.js ব্যবহার করা
Immutable.js একটি লাইব্রেরি যা JavaScript-এ Immutable ডেটা স্ট্রাকচার সরবরাহ করে। এটি অ্যারে, অবজেক্ট, মেপ, সেট ইত্যাদি পরিবর্তনশীল ডেটা স্ট্রাকচারকে Immutable করে তোলে।
import { Map } from 'immutable';
function counterReducer(state = Map({ count: 0 }), action) {
switch (action.type) {
case 'INCREMENT':
return state.update('count', count => count + 1); // Immutableভাবে count আপডেট
case 'DECREMENT':
return state.update('count', count => count - 1);
default:
return state;
}
}
এখানে Map ব্যবহার করে Immutable অবজেক্ট তৈরি করা হয়েছে এবং .update() ব্যবহার করে count আপডেট করা হয়েছে।
Performance Optimization in Redux
Redux-এ পারফরম্যান্স অপ্টিমাইজেশনের জন্য, কিছু কৌশল গ্রহণ করতে হয়, যাতে unnecessary re-renders বা স্টেটের পরিবর্তনের কারণে অ্যাপ্লিকেশন ধীর না হয়ে যায়।
১. React.memo() ব্যবহার করা
React-এর React.memo() একটি হাইয়ার অর্ডার কম্পোনেন্ট (HOC) যা কম্পোনেন্টের পুনরায় রেন্ডারিং সীমিত করে। এটি শুধুমাত্র তখনই কম্পোনেন্ট রেন্ডার করে যখন তার প্রপস পরিবর্তিত হয়।
const TodoItem = React.memo(({ todo }) => {
console.log('Rendering TodoItem');
return <li>{todo.title}</li>;
});
এখানে, TodoItem কম্পোনেন্ট শুধুমাত্র তখনই রেন্ডার হবে যদি todo প্রপসের মান পরিবর্তিত হয়। এটি unnecessary রেন্ডারিং কমিয়ে অ্যাপ্লিকেশনের পারফরম্যান্স বাড়াতে সাহায্য করবে।
২. Reselect লাইব্রেরি ব্যবহার করা
Redux স্টোর থেকে সিলেক্টর (selectors) ব্যবহার করার সময় অনেক বার অ্যাক্সেস করা হয় একই ডেটাকে। যখনই Redux স্টেটে কোনো পরিবর্তন হয়, সব সিলেক্টরের মাধ্যমে সেই স্টেটের ডেটা আবার রেন্ডার হয়। এতে পারফরম্যান্স হ্রাস পেতে পারে।
Reselect হলো একটি লাইব্রেরি যা মেমোইজড সিলেক্টর তৈরি করতে সাহায্য করে, যাতে কোনো সিলেক্টর একই ইনপুটে বারবার কল হলে, সেটি পুনরায় ক্যালকুলেট না হয়ে আগের রিটার্ন করা ভ্যালু রিটার্ন করে।
import { createSelector } from 'reselect';
const getTodos = state => state.todos;
const getCompletedTodos = createSelector(
[getTodos],
(todos) => todos.filter(todo => todo.completed)
);
এখানে, getCompletedTodos সিলেক্টর মেমোইজড, তাই এটি শুধুমাত্র তখনই রিটার্ন করবে যখন todos স্টেট পরিবর্তিত হবে, ফলে unnecessary recalculations বা রেন্ডারিং এড়ানো যায়।
৩. Use of useMemo and useCallback in React
React-এর useMemo এবং useCallback হুক দুটি পারফরম্যান্স অপ্টিমাইজেশনে সহায়তা করে। useMemo ব্যবহার করা হয় expensive calculations মেমোইজড করার জন্য, যাতে সেগুলো প্রয়োজন না হলে পুনরায় ক্যালকুলেট না হয়।
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
এখানে, computeExpensiveValue(a, b) কেবলমাত্র a বা b পরিবর্তিত হলে পুনরায় ক্যালকুলেট হবে।
useCallback হুক ব্যবহার করা হয় ফাংশনের মেমোইজেশন করতে, যাতে unnecessary রি-রেন্ডারিং এড়ানো যায়।
const memoizedCallback = useCallback(() => { doSomething(a, b); }, [a, b]);
৪. Batched Updates
Redux 4.1.0 এবং React 18 এর পরে, ব্যাচড আপডেট সমর্থন যুক্ত করা হয়েছে, যার মাধ্যমে একাধিক ডিসপ্যাচ একসাথে সম্পাদিত হতে পারে। এতে পুনরায় রেন্ডারিং কম হয় এবং পারফরম্যান্স উন্নত হয়।
সারাংশ
- Immutable data handling: Redux-এ স্টেট পরিবর্তন করতে হলে তার একটি নতুন কপি তৈরি করতে হয়, যা স্টেটকে Immutable রাখে। এর জন্য স্প্রেড অপারেটর,
Object.assign()অথবা Immutable.js ব্যবহার করা যেতে পারে। - Performance optimization: স্টেট পরিবর্তন বা unnecessary re-renders কমাতে
React.memo(), Reselect লাইব্রেরি, এবংuseMemo/useCallbackহুক ব্যবহার করা যেতে পারে।
এগুলো অ্যাপ্লিকেশনের পারফরম্যান্স বাড়াতে এবং ডেটা স্টেটকে সঠিকভাবে পরিচালনা করতে সহায়তা করে, যা Redux ব্যবহারের সময় গুরুত্বপূর্ণ।
Read more