Redux একটি কেন্দ্রীয় স্টেট ম্যানেজমেন্ট লাইব্রেরি যা অ্যাপ্লিকেশনগুলির ডেটা স্টেটের সঠিক এবং কার্যকর পরিচালনার জন্য ব্যবহৃত হয়। Redux এর মূল কাঠামো অন্তর্ভুক্ত তিনটি গুরুত্বপূর্ণ অংশ: স্টোর (Store), একশন (Action), এবং রিডিউসার (Reducer)। এর মধ্যে, রিডিউসার স্টেট পরিচালনার জন্য একটি অত্যন্ত গুরুত্বপূর্ণ ভূমিকা পালন করে।
Reducer কী?
Reducer একটি ফাংশন, যা স্টেট এবং একশন (Action) নিয়ে কাজ করে এবং একটি নতুন স্টেট রিটার্ন করে। রিডিউসারকে বলা হয় "Pure Function", কারণ এটি পূর্ববর্তী স্টেট এবং অ্যাকশন দিয়ে একটি নতুন স্টেট তৈরি করে, কিন্তু নিজে কোনো পরিবর্তন বা পার্শ্বপ্রতিক্রিয়া তৈরি করে না।
রিডিউসার মূলত স্টেটের পূর্ববর্তী কপি নিয়ে নতুন কপি তৈরি করে, যা অপরিবর্তনীয় (Immutable) স্টেটের ধারণাকে বজায় রাখে। এটি স্টেট পরিবর্তন করার জন্য একমাত্র নির্ভরযোগ্য পদ্ধতি, কারণ শুধু রিডিউসারেই স্টেট পরিবর্তন করা সম্ভব।
Reducer কিভাবে কাজ করে?
রিডিউসার একটি সাধারণ ফাংশন যা নিচের মতো কাঠামোয় কাজ করে:
function reducer(state, action) {
switch (action.type) {
case 'ACTION_TYPE':
return {
...state, // পূর্ববর্তী স্টেটের কপি
newStateProperty: action.payload // নতুন স্টেটের প্রপার্টি
};
default:
return state; // যদি একশনটি জানে না, তবে পূর্ববর্তী স্টেটই ফেরত দেবে
}
}
এখানে:
- State: এটি হল স্টোরের বর্তমান স্টেট।
- Action: এটি এমন একটি অবজেক্ট যার মধ্যে
typeএবং (অপশনাল)payloadথাকে, যা স্টেট পরিবর্তন করার জন্য নির্দেশ দেয়। - Return: রিডিউসার নতুন স্টেট ফেরত দেয়, যা পূর্ববর্তী স্টেটের কপি এবং প্রয়োজনীয় পরিবর্তন নিয়ে।
Reducer এর উদাহরণ
ধরা যাক, আমরা একটি টুডু অ্যাপ্লিকেশন তৈরি করছি এবং আমাদের টুডু তালিকা (todos) সংরক্ষণ করতে হবে।
// Reducer
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;
}
}
এখানে:
- ADD_TODO: যখন এই একশনটি ডিসপ্যাচ করা হয়, রিডিউসার বর্তমান টুডু তালিকায় নতুন টুডু আইটেম যোগ করে।
- REMOVE_TODO: যখন এই একশনটি ডিসপ্যাচ করা হয়, রিডিউসার টুডু আইটেমটির
idদেখে সঠিক আইটেমটি সরিয়ে দেয়।
Reducer এর মূল বৈশিষ্ট্য
- স্টেট অপরিবর্তনীয়তা (Immutable State): রিডিউসার পূর্ববর্তী স্টেটকে সরাসরি পরিবর্তন না করে, তার একটি নতুন কপি তৈরি করে। এটি স্টেট অপরিবর্তনীয় (immutable) রাখে।
- Pure Function: রিডিউসার একটি Pure Function হওয়া উচিত, অর্থাৎ এটি শুধুমাত্র তার ইনপুট (স্টেট এবং অ্যাকশন) এর উপর নির্ভরশীল, এবং কখনোই বাইরের কিছু পরিবর্তন করে না বা পার্শ্বপ্রতিক্রিয়া তৈরি করে না।
- স্টেটের কপি তৈরি: রিডিউসার বর্তমান স্টেটের পরিবর্তে একটি নতুন স্টেট রিটার্ন করে, যাতে আগের স্টেট অপরিবর্তিত থাকে এবং কোন ধরণের সাইড ইফেক্টস না হয়।
রিডিউসার কম্বিনেশন (Combining Reducers)
Redux অ্যাপ্লিকেশনগুলিতে সাধারণত একাধিক রিডিউসার থাকে, বিশেষ করে বড় অ্যাপ্লিকেশনগুলিতে। combineReducers ফাংশন ব্যবহার করে একাধিক রিডিউসারকে একত্রিত করা যায়। এই পদ্ধতিতে প্রতিটি রিডিউসার আলাদা আলাদা স্টেট ফিচার বা ডোমেনের জন্য দায়িত্ব পালন করে।
উদাহরণ:
import { combineReducers } from 'redux';
function todosReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload];
default:
return state;
}
}
function visibilityFilter(state = 'SHOW_ALL', action) {
switch (action.type) {
case 'SET_VISIBILITY_FILTER':
return action.payload;
default:
return state;
}
}
// Combine reducers
const rootReducer = combineReducers({
todos: todosReducer,
visibilityFilter: visibilityFilter
});
এখানে, combineReducers ব্যবহার করে দুটি রিডিউসারকে একত্রিত করা হয়েছে, যার মধ্যে:
todosReducerটুডু আইটেম সংরক্ষণ করছে।visibilityFilterব্যবহারকারীর দৃশ্যমানতার ফিল্টার স্টেট সংরক্ষণ করছে।
State Management এর ভূমিকা
Redux স্টেট ম্যানেজমেন্টে রিডিউসার খুব গুরুত্বপূর্ণ ভূমিকা পালন করে। স্টোরের মধ্যে সমস্ত স্টেট একটি একক জায়গায় থাকে এবং রিডিউসারের মাধ্যমে তা পরিবর্তিত হয়। স্টেট ম্যানেজমেন্টের মধ্যে:
- স্টেট একটি কেন্দ্রীয় অবস্থানে সংরক্ষিত থাকে যা অ্যাপ্লিকেশনের মধ্যে যে কোনো জায়গা থেকে অ্যাক্সেস করা যায়।
- স্টেট পরিবর্তন শুধুমাত্র রিডিউসারের মাধ্যমে হয়, যা অ্যাপ্লিকেশনটিকে পূর্বানুমানযোগ্য এবং সহজে ডিবাগযোগ্য করে তোলে।
সারাংশ
Reducer হলো Redux অ্যাপ্লিকেশনের একটি গুরুত্বপূর্ণ অংশ যা স্টেট পরিচালনা করে। এটি একমাত্র ফাংশন যা স্টেট পরিবর্তন করে, এবং এটি Pure Function হওয়া উচিত, যার মানে এটি পূর্ববর্তী স্টেট এবং অ্যাকশন গ্রহণ করে একটি নতুন স্টেট রিটার্ন করে, তবে পূর্ববর্তী স্টেট পরিবর্তন করে না। রিডিউসার কম্বিনেশন দ্বারা বড় অ্যাপ্লিকেশনগুলোতে একাধিক রিডিউসারকে একত্রিত করা যায়, যা স্টেট ম্যানেজমেন্টকে আরও সংগঠিত এবং স্কেলেবল করে তোলে।
Reducer হল Redux-এর একটি গুরুত্বপূর্ণ উপাদান, যা স্টেট পরিবর্তনের জন্য দায়িত্বশীল। এটি একটি পিউর ফাংশন যা অ্যাকশন (Action) এবং বর্তমান স্টেট (State) গ্রহণ করে এবং একটি নতুন স্টেট রিটার্ন করে। Redux-এ স্টেট কখনো সরাসরি পরিবর্তন হয় না; পরিবর্তনের জন্য Reducer ব্যবহৃত হয়।
Reducer কী?
Reducer একটি ফাংশন যা দুইটি প্যারামিটার গ্রহণ করে:
- State (স্টেট): এটি বর্তমান স্টেট, যা আগে থেকে স্টোরে সংরক্ষিত থাকে। প্রথমবার রিডিউসার চলার সময়, এটি সাধারণত একটি ডিফল্ট স্টেট হতে পারে।
- Action (একশন): এটি একটি অবজেক্ট যা স্টেট পরিবর্তনের সংকেত দেয় এবং এর মধ্যে একটি
typeথাকে যা জানায় কোন ধরনের পরিবর্তন ঘটাতে হবে। একশনটি সাধারণত একটিpayloadধারণ করে, যা নতুন ডেটা বা অতিরিক্ত তথ্য থাকতে পারে।
Reducer ফাংশনের কাজ হল, একশনটি পেয়ে বর্তমান স্টেটের উপর ভিত্তি করে নতুন স্টেট তৈরি করা। এটি কোনো অবস্থাতেই সরাসরি স্টেট পরিবর্তন করে না, বরং একটি নতুন স্টেট রিটার্ন করে, যাতে পুরনো স্টেট অপরিবর্তিত থাকে।
Reducer এর কাজ
- স্টেট পরিবর্তন করা: Reducer অ্যাকশন অনুসারে স্টেটের পরিবর্তন ঘটায়।
- নতুন স্টেট রিটার্ন করা: Reducer কখনোই সরাসরি স্টেট পরিবর্তন করে না, বরং একটি নতুন স্টেট অবজেক্ট রিটার্ন করে।
- পিউর ফাংশন: Reducer একটি পিউর ফাংশন, অর্থাৎ এটি একই ইনপুটের জন্য সর্বদা একই আউটপুট প্রদান করে এবং কোনো পার্শ্বপ্রতিক্রিয়া (side effect) সৃষ্টি করে না।
Reducer এর উদাহরণ
ধরা যাক, একটি অ্যাপ্লিকেশন যেখানে আমরা টুডু আইটেম যোগ, মুছে ফেলা এবং টুডু স্ট্যাটাস পরিবর্তন করতে চাই। এর জন্য একটি সিম্পল রিডিউসার তৈরি করা যাক।
// Initial state
const initialState = {
todos: [],
};
// Reducer function
function todosReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
case 'REMOVE_TODO':
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload.id)
};
case 'TOGGLE_TODO':
return {
...state,
todos: state.todos.map(todo =>
todo.id === action.payload.id
? { ...todo, completed: !todo.completed }
: todo
)
};
default:
return state;
}
}
এখানে:
ADD_TODO: টুডু আইটেম যোগ করতে ব্যবহৃত হয়। নতুন টুডু আইটেমaction.payloadথেকে আসে এবং এটি স্টেটেরtodosঅ্যারের মধ্যে যোগ করা হয়।REMOVE_TODO: টুডু আইটেম মুছে ফেলা হয়।action.payload.idঅনুযায়ী আইটেমটি ফিল্টার করা হয়।TOGGLE_TODO: টুডু আইটেমের স্ট্যাটাস পরিবর্তন হয়, অর্থাৎ, একটি টুডু আইটেমটি সম্পন্ন (completed) বা অসম্পন্ন (incomplete) হবে।
এছাড়া, যদি কোনো একশন না মেলে (অর্থাৎ ডিফল্ট), তবে পুরনো স্টেট রিটার্ন হয়।
Reducer এর মূল বৈশিষ্ট্য
- পিউর ফাংশন: Reducer কখনোই স্টেট পরিবর্তন করে না; এটি নতুন স্টেট অবজেক্ট তৈরি করে এবং রিটার্ন করে। এটি কোনো পার্শ্বপ্রতিক্রিয়া সৃষ্টি করে না।
- স্টেট অপরিবর্তনীয়তা (Immutable State): Reducer স্টেটকে অপরিবর্তনীয় (immutable) রাখে, অর্থাৎ পুরনো স্টেট কখনো সরাসরি পরিবর্তিত হয় না। নতুন স্টেট তৈরি করে ফেরত দেওয়া হয়।
- স্টেটের মূল অবস্থা (Initial State): Reducer প্রথমবার চলার সময় একটি ডিফল্ট বা ইনিশিয়াল স্টেট গ্রহণ করে।
- একশন টাইপ (Action Type): Reducer স্টেট পরিবর্তনের জন্য একশনের
typeএর মাধ্যমে সিদ্ধান্ত নেয় কোন পরিবর্তনটি ঘটবে।
Reducer ফাংশনের কাঠামো
Redux এ, একটি অ্যাপ্লিকেশনে সাধারণত একাধিক রিডিউসার থাকতে পারে। এই রিডিউসারগুলো combineReducers এর মাধ্যমে একত্রিত করা হয়। এর মাধ্যমে, একাধিক রিডিউসার একসাথে কাজ করতে পারে এবং একক স্টোরে সংগঠিত স্টেট সঞ্চিত থাকে।
import { combineReducers } from 'redux';
// Individual reducers
function todosReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload];
default:
return state;
}
}
function userReducer(state = { name: '' }, action) {
switch (action.type) {
case 'SET_USER':
return { name: action.payload.name };
default:
return state;
}
}
// Combine reducers
const rootReducer = combineReducers({
todos: todosReducer,
user: userReducer
});
এখানে:
- todosReducer: টুডু আইটেমের স্টেট পরিচালনা করে।
- userReducer: ব্যবহারকারীর তথ্যের স্টেট পরিচালনা করে।
এখন, rootReducer দুটি রিডিউসারকে একত্রিত করেছে এবং একটি একক স্টোর তৈরি করেছে।
Reducer এর গুরুত্বপূর্ণ নিয়মাবলী
- স্টেট অপরিবর্তনীয়তা (State Immutability): Reducer কখনোই স্টেটকে সরাসরি পরিবর্তন করবে না। পুরনো স্টেটের একটি নতুন কপি তৈরি করবে এবং সেটি রিটার্ন করবে।
- একশন টাইপ (Action Type): Reducer একশন টাইপ দেখে সিদ্ধান্ত নেবে কোন পরিবর্তন ঘটাতে হবে।
- ফাংশনাল রিডিউসার (Functional Reducers): Reducer একটি পিউর ফাংশন হবে, যেটি একই ইনপুটের জন্য একই আউটপুট দেবে এবং কোনো পার্শ্বপ্রতিক্রিয়া তৈরি করবে না।
সারাংশ
Reducer হলো একটি ফাংশন যা অ্যাকশন এবং বর্তমান স্টেট নিয়ে নতুন স্টেট তৈরি করে। এটি কখনোই সরাসরি স্টেট পরিবর্তন করে না, বরং একটি নতুন স্টেট রিটার্ন করে। Reducer হল Redux-এর একটি পিউর ফাংশন যা স্টেটের অপরিবর্তনীয়তা বজায় রাখে। এতে একাধিক রিডিউসার থাকতে পারে, যেগুলো একত্রিত হয়ে একটি কেন্দ্রীয় স্টোরে স্টেট পরিচালনা করে।
Redux একটি স্টেট ম্যানেজমেন্ট লাইব্রেরি যা Pure Functions এবং Reducers ব্যবহার করে অ্যাপ্লিকেশনের স্টেট পরিচালনা করতে সহায়তা করে। এর মধ্যে Pure Functions এর গুরুত্ব এবং Reducers কীভাবে কাজ করে, তা বুঝতে পারা খুবই গুরুত্বপূর্ণ।
Redux অ্যাপ্লিকেশনগুলিতে Reducers এমন Pure Functions হিসেবে কাজ করে, যা অ্যাপ্লিকেশনের স্টেট পরিবর্তন করতে ব্যবহৃত হয়। এই ধারণাগুলি স্টেট পরিবর্তনের প্রক্রিয়াকে সহজ, পূর্বানুমানযোগ্য এবং ডিবাগযোগ্য করে তোলে।
Pure Functions কী?
Pure Function হলো এমন একটি ফাংশন যা কোনো ধরনের পার্শ্বপ্রতিক্রিয়া (side effects) সৃষ্টি না করে এবং একটি নির্দিষ্ট ইনপুটের জন্য একই আউটপুট প্রদান করে। এর মানে, যদি আপনি একটি পিউর ফাংশনকে একসাথে একই ইনপুট দেন, তবে এটি সবসময় একই রেজাল্ট দিবে।
Pure Functions এর প্রধান বৈশিষ্ট্য:
- একই ইনপুটে একই আউটপুট: একই ইনপুট দিলে সবসময় একই আউটপুট পাওয়া যায়।
- কোন পার্শ্বপ্রতিক্রিয়া নেই (No Side Effects): পিউর ফাংশন কোনও বাহ্যিক ডেটা পরিবর্তন করে না, যেমন গ্লোবাল ভ্যারিয়েবল বা বাইরের স্টেট।
- স্টেট অপরিবর্তনীয়তা (Immutability): পিউর ফাংশন কখনোই তার ইনপুট বা বাহ্যিক ডেটা পরিবর্তন করে না। এটি নতুন ডেটা তৈরি করে এবং পুরানো ডেটা অপরিবর্তনীয় রাখে।
Redux-এ, রিডিউসার ফাংশনগুলো Pure Functions হিসেবে কাজ করে, যা নিশ্চিত করে স্টেট পরিবর্তনের প্রক্রিয়া নিরাপদ এবং পূর্বানুমানযোগ্য।
Reducers কী?
Reducers হল পিউর ফাংশন, যা স্টেট এবং অ্যাকশন ইনপুট হিসেবে নিয়ে নতুন স্টেট রিটার্ন করে। Redux-এ, স্টেট কখনোই সরাসরি পরিবর্তিত হয় না। পরিবর্তন করতে হলে, Reducer ফাংশন একটি নতুন স্টেট অবজেক্ট তৈরি করে, যা আগের স্টেটের সাথে মিলে না।
Redux-এ Reducer এর কাজ হচ্ছে:
- অ্যাকশন অনুযায়ী স্টেট পরিবর্তন করা।
- স্টেটের একটি নতুন কপি তৈরি করা (immutable স্টেট)।
Reducer এর কার্যপদ্ধতি:
- স্টেট এবং অ্যাকশন গ্রহণ: Reducer দুটি প্যারামিটার গ্রহণ করে: বর্তমান স্টেট (যা প্রথমবার
undefinedহতে পারে) এবং একশন। - স্টেট পরিবর্তন: Reducer শুধুমাত্র একশন অনুযায়ী স্টেট পরিবর্তন করে, কিন্তু পুরানো স্টেটকে সরাসরি পরিবর্তন করে না।
- নতুন স্টেট রিটার্ন: Reducer পুরানো স্টেটের কপি তৈরি করে এবং নতুন স্টেট রিটার্ন করে।
Reducer এর উদাহরণ:
// Reducer function
function counterReducer(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1; // Return new state, don't modify old state
case 'DECREMENT':
return state - 1;
default:
return state;
}
}
এখানে:
- state = 0: প্রথমবারের মতো স্টেট যদি না থাকে, তাহলে সেটি 0 দিয়ে শুরু হবে।
- action: অ্যাকশন অবজেক্ট যা
typeধারণ করে (যেমন,INCREMENTবাDECREMENT)। - new state return: রিডিউসার একটি নতুন স্টেট রিটার্ন করে, পুরোনো স্টেট পরিবর্তন না করে।
Reducer এর বিশেষ বৈশিষ্ট্য:
- পিউর ফাংশন: রিডিউসার কখনোই বাহ্যিক স্টেট পরিবর্তন বা পার্শ্বপ্রতিক্রিয়া সৃষ্টি করে না।
- স্টেট অপরিবর্তনীয়তা (Immutability): রিডিউসার কখনো পুরোনো স্টেট পরিবর্তন করে না; বরং একটি নতুন কপি তৈরি করে।
- নির্ধারিত একশন: রিডিউসার শুধুমাত্র প্রদত্ত অ্যাকশন অনুযায়ী স্টেট পরিবর্তন করে।
Reducer এর মধ্যে Pure Function এর ভূমিকা
Redux-এ, Reducers হল পিউর ফাংশন হিসেবে কাজ করে, যা স্টেটের অপরিবর্তনীয়তা এবং পূর্বানুমানযোগ্যতা বজায় রাখে। যখন কোনো অ্যাকশন ডিসপ্যাচ করা হয়, রিডিউসার ঐ অ্যাকশন অনুযায়ী নতুন স্টেট তৈরি করে এবং কোনভাবেই পুরানো স্টেট পরিবর্তন করে না। এর ফলে অ্যাপ্লিকেশনের স্টেট ম্যানেজমেন্ট আরো সহজ এবং ডিবাগযোগ্য হয়।
উদাহরণ:
// Reducer with pure function
function todoReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload]; // return new state
case 'REMOVE_TODO':
return state.filter(todo => todo.id !== action.payload.id);
default:
return state;
}
}
এখানে:
ADD_TODOএকশনে, রিডিউসার নতুন টুডু আইটেম অ্যাড করে একটি নতুন অ্যারে রিটার্ন করে। পূর্বেরstateঅপরিবর্তিত থাকে।REMOVE_TODOএকশনে, রিডিউসার শুধুমাত্র মুছে ফেলা আইটেমটি বাদ দিয়ে একটি নতুন অ্যারে রিটার্ন করে।
Pure Functions এবং Reducers এর সুবিধা
- ডিবাগিং সহজ: পিউর ফাংশন কোনো পার্শ্বপ্রতিক্রিয়া তৈরি না করলে, আপনি একেবারে নির্দিষ্ট ইনপুটের জন্য একই আউটপুট আশা করতে পারেন। ফলে স্টেট পরিবর্তন এবং ডিবাগিং আরো সহজ হয়।
- পুনঃব্যবহারযোগ্যতা (Reusability): পিউর ফাংশনগুলো সাধারণত সহজে পুনঃব্যবহারযোগ্য, কারণ তারা নির্দিষ্ট ইনপুটের জন্য নির্দিষ্ট আউটপুট প্রদান করে।
- পারফরম্যান্স উন্নয়ন: Immutable স্টেট ব্যবহারের কারণে, আপনি পরিবর্তিত স্টেটের পরিবর্তে আগের স্টেটের কপি রাখতে পারেন, যা পারফরম্যান্সের দিক থেকে আরো ভালো।
সারাংশ
Pure Functions এবং Reducers Redux-এর অন্যতম মূল অংশ। Pure Functions নিশ্চিত করে যে, স্টেট পরিবর্তন এবং প্রোগ্রামের আচরণ পূর্বানুমানযোগ্য ও নির্ভরযোগ্য হবে, কারণ একটাই ইনপুটের জন্য একটাই আউটপুট পাওয়া যাবে। Redux-এ, Reducers হল পিউর ফাংশন যা স্টেট পরিবর্তন করার জন্য ব্যবহৃত হয়, তবে কখনোই আগের স্টেট পরিবর্তন করে না। স্টেট পরিবর্তন করার জন্য, রিডিউসার একটি নতুন কপি রিটার্ন করে, যা স্টেটের অপরিবর্তনীয়তা বজায় রাখে এবং অ্যাপ্লিকেশনকে আরো সহজ, স্কেলেবল ও ডিবাগযোগ্য করে তোলে।
Redux অ্যাপ্লিকেশনে একাধিক reducer তৈরি এবং কম্বাইন (combine) করার প্রক্রিয়া অত্যন্ত গুরুত্বপূর্ণ, কারণ এটি স্টেটের বিভিন্ন অংশ আলাদা করে ম্যানেজ করার সুযোগ দেয়। সাধারণত অ্যাপ্লিকেশনগুলিতে একাধিক ধরনের স্টেট থাকে, এবং প্রতিটি ধরনের স্টেটকে আলাদা রিডিউসারের মাধ্যমে নিয়ন্ত্রণ করা হয়।
এটি বিশেষত বড় অ্যাপ্লিকেশনগুলিতে প্রয়োজনীয় হয়, যেখানে বিভিন্ন ধরনের স্টেটের জন্য আলাদা রিডিউসার প্রয়োজন হয়। combineReducers ফাংশন ব্যবহার করে আমরা একাধিক রিডিউসারকে একটি রুট রিডিউসারে একত্রিত (combine) করতে পারি।
Multiple Reducers কীভাবে কাজ করে?
Redux-এ, স্টেট সাধারণত একটি বড় অবজেক্ট হিসেবে থাকে, এবং স্টেটের বিভিন্ন অংশের জন্য আলাদা আলাদা রিডিউসার থাকতে পারে। প্রতিটি রিডিউসার একটি নির্দিষ্ট অংশের স্টেটকে পরিবর্তন করে। combineReducers ফাংশন ব্যবহার করে আমরা একাধিক রিডিউসারকে একটি একক রিডিউসারে কম্বাইন (combine) করি।
combineReducers এর ব্যবহার
combineReducers Redux-এর একটি বিল্ট-ইন ফাংশন, যা একাধিক রিডিউসারকে একত্রিত করতে ব্যবহৃত হয়। এটি প্রতিটি রিডিউসারকে একটি নির্দিষ্ট স্টেট স্লাইসের জন্য দায়িত্ব প্রদান করে এবং সব রিডিউসারকে একটি একক রিডিউসারে কম্বাইন করে।
combineReducers এর সাধারণ কাঠামো:
import { combineReducers } from 'redux';
// প্রথম রিডিউসার
function todosReducer(state = [], action) {
switch (action.type) {
case 'ADD_TODO':
return [...state, action.payload];
default:
return state;
}
}
// দ্বিতীয় রিডিউসার
function userReducer(state = { name: '' }, action) {
switch (action.type) {
case 'SET_USER':
return { ...state, name: action.payload };
default:
return state;
}
}
// কম্বাইন করা
const rootReducer = combineReducers({
todos: todosReducer,
user: userReducer
});
export default rootReducer;
এখানে:
todosReducerএকটি রিডিউসার যা টুডু আইটেমগুলির স্টেট পরিচালনা করে।userReducerএকটি রিডিউসার যা ইউজারের তথ্যের স্টেট পরিচালনা করে।combineReducersফাংশনটি এই দুটি রিডিউসারকে একটি রুট রিডিউসারে একত্রিত করছে, যেখানেtodosএবংuserদুটি আলাদা স্টেট স্লাইস।
combineReducers কীভাবে কাজ করে?
combineReducers একটি অবজেক্ট গ্রহণ করে, যেখানে প্রতিটি কীগুলি রিডিউসারের নাম এবং মান হলো সংশ্লিষ্ট রিডিউসার ফাংশন। এই ফাংশনটি একত্রিত রিডিউসার রিটার্ন করে, যা স্টোরের মাধ্যমে স্টেট আপডেট করতে ব্যবহৃত হয়।
উদাহরণস্বরূপ, স্টোরে যে স্টেট থাকবে, তা হবে:
{
todos: [ ... ], // todosReducer দ্বারা পরিচালিত
user: { name: '' } // userReducer দ্বারা পরিচালিত
}
এভাবে, todos এবং user এর জন্য আলাদা স্টেট রয়েছে, এবং প্রতিটি স্টেটকে আলাদা রিডিউসার দ্বারা পরিচালিত করা হচ্ছে। যখন কোনো অ্যাকশন ডেসপ্যাচ করা হয়, তখন প্রতিটি রিডিউসার সেই অ্যাকশনটি পরীক্ষা করে, এবং যদি তা প্রযোজ্য হয়, স্টেট পরিবর্তন করে।
Multiple Reducers এর ব্যবহারের সুবিধা
- কোডের গঠন: একাধিক রিডিউসার ব্যবহার করে, অ্যাপ্লিকেশনটির স্টেটকে আলাদা আলাদা অংশে বিভক্ত করা যায়, যা কোডের গঠন পরিষ্কার এবং সহজ করে।
- স্টেট ম্যানেজমেন্ট: আলাদা রিডিউসার ব্যবহার করলে স্টেটের বিভিন্ন অংশকে আলাদা আলাদা ভাবে নিয়ন্ত্রণ করা সহজ হয়।
- স্কেলেবিলিটি: অ্যাপ্লিকেশন বড় হলে নতুন রিডিউসার যোগ করা সহজ হয়। একাধিক রিডিউসার কম্বাইন করে অ্যাপ্লিকেশনটি আরও স্কেলেবল এবং মেইনটেনেবল হয়।
- রিডিউসারের পুনঃব্যবহারযোগ্যতা: একটি রিডিউসার শুধুমাত্র নির্দিষ্ট স্টেট স্লাইসের জন্য কাজ করে, তাই এটি অন্য জায়গায় পুনঃব্যবহার করা সম্ভব।
combineReducers এর ব্যবহার উদাহরণ
ধরা যাক, আমাদের একটি অ্যাপ্লিকেশন আছে যেখানে টুডু লিস্ট এবং ইউজার প্রোফাইল দুইটি আলাদা ডাটা স্টেট রয়েছে। আমরা এই দুটি স্টেটের জন্য আলাদা রিডিউসার তৈরি করে সেগুলো কম্বাইন করব।
স্টেপ 1: আলাদা রিডিউসার তৈরি
// টুডু রিডিউসার
const initialState = {
todos: []
};
function todosReducer(state = initialState, action) {
switch (action.type) {
case 'ADD_TODO':
return {
...state,
todos: [...state.todos, action.payload]
};
case 'REMOVE_TODO':
return {
...state,
todos: state.todos.filter(todo => todo.id !== action.payload.id)
};
default:
return state;
}
}
// ইউজার রিডিউসার
const userInitialState = {
user: { name: '', age: null }
};
function userReducer(state = userInitialState, action) {
switch (action.type) {
case 'SET_USER':
return {
...state,
user: action.payload
};
default:
return state;
}
}
স্টেপ 2: combineReducers ব্যবহার করে রিডিউসার কম্বাইন করা
import { combineReducers } from 'redux';
const rootReducer = combineReducers({
todos: todosReducer,
user: userReducer
});
export default rootReducer;
স্টেপ 3: Redux Store তৈরি করা
import { createStore } from 'redux';
import rootReducer from './reducers';
const store = createStore(rootReducer);
combineReducers এর আরো উন্নত ব্যবহার
Redux-এ বিভিন্ন ধরনের স্টেট থাকতে পারে যেমন:
- নেটওয়ার্ক স্টেট: যা API কলের স্টেট ম্যানেজমেন্ট করবে।
- UI স্টেট: যা UI এর ভিউ, যেমন লোডিং স্টেট, শো/হাইড মডেল ইত্যাদি পরিচালনা করবে।
- অথেন্টিকেশন স্টেট: যা লগইন, লগআউট ইত্যাদি ম্যানেজ করবে।
এইসব স্টেটের জন্য আলাদা আলাদা রিডিউসার তৈরি করতে পারেন এবং সবগুলোকে combineReducers এর মাধ্যমে একত্রিত করতে পারেন।
সারাংশ
Multiple Reducers তৈরি করা এবং combineReducers ফাংশন ব্যবহার করে একত্রিত করা Redux অ্যাপ্লিকেশনে স্টেট ম্যানেজমেন্টকে আরও পরিষ্কার, স্কেলেবল এবং মেইনটেনেবল করে। একাধিক রিডিউসার ব্যবহার করলে স্টেটের বিভিন্ন স্লাইসের জন্য আলাদা রিডিউসার তৈরি করা সহজ হয়, এবং এতে কোডের গঠন পরিষ্কার ও পুনঃব্যবহারযোগ্য হয়। combineReducers একটি গুরুত্বপূর্ণ টুল যা বিভিন্ন রিডিউসারকে একত্রিত করে অ্যাপ্লিকেশনের স্টেট ম্যানেজমেন্টকে আরও শক্তিশালী করে তোলে।
Redux একটি স্টেট ম্যানেজমেন্ট লাইব্রেরি, যেখানে স্টেট পরিবর্তন করার জন্য বিশেষভাবে লক্ষ্য রাখা হয় যেন স্টেট অপরিবর্তনীয় (immutable) থাকে। স্টেট যদি পরিবর্তনশীল (mutable) হয়, তাহলে অ্যাপ্লিকেশনটি অপ্রত্যাশিতভাবে আচরণ করতে পারে এবং ডিবাগিং কঠিন হয়ে পড়ে। Redux-এ স্টেটকে অপরিবর্তনীয় রাখতে হলে কিছু নির্দিষ্ট নিয়ম এবং কৌশল অনুসরণ করতে হয়, যা অ্যাপ্লিকেশনের পূর্বানুমানযোগ্যতা এবং স্থায়ীত্ব বজায় রাখতে সহায়তা করে।
Redux-এ Immutable স্টেট রাখার প্রয়োজনীয়তা
- একক স্টেট কপি (Single Source of Truth): Redux-এ একটি একক স্টেট কপি থাকে, এবং সেই স্টেটটি সব সময় অপরিবর্তনীয় হওয়া উচিত। যদি স্টেট পরিবর্তনশীল হয়, তাহলে বিভিন্ন অংশে স্টেটের মান অপ্রত্যাশিতভাবে পরিবর্তিত হতে পারে।
- ডিবাগিং সহজ করা: যখন স্টেট অপরিবর্তনীয় থাকে, তখন অ্যাপ্লিকেশনের আচরণ পূর্বানুমানযোগ্য হয় এবং সমস্যা খুঁজে বের করা সহজ হয়।
- বিষয়ভিত্তিক সাবস্ক্রিপশন: যখন স্টেট অপরিবর্তনীয় থাকে, তখন সাবস্ক্রাইবাররা কেবলমাত্র পরিবর্তিত অংশে নতুন স্টেট দেখতে পান, যা পারফরম্যান্স এবং রেন্ডারিং উন্নত করে।
- টেস্টিং: অপরিবর্তনীয় স্টেট টেস্টিংয়ের জন্য সহজ, কারণ আমরা জানি যে স্টেট কখনও সরাসরি পরিবর্তন হবে না।
Redux-এ Immutable স্টেট রাখার উপায়
Redux-এ স্টেট অপরিবর্তনীয় (immutable) রাখতে কিছু বিশেষ কৌশল অবলম্বন করতে হয়, কারণ JavaScript অবজেক্ট এবং অ্যারে ডিফল্টভাবে পরিবর্তনযোগ্য (mutable) থাকে। এখানে কিছু সাধারণ উপায় তুলে ধরা হলো:
১. স্টেটের নতুন কপি তৈরি করা (Creating a New State Copy)
Redux-এ স্টেট কখনো সরাসরি পরিবর্তন করা হয় না। রিডিউসারের ভিতরে, আপনাকে প্রতিবার একটি নতুন স্টেট কপি তৈরি করতে হবে যখনই স্টেট পরিবর্তন করতে হবে। concat(), map(), filter() বা স্প্রেড অপারেটর (...) এর মতো ইমিউটেবল অপারেশন ব্যবহার করা যেতে পারে।
উদাহরণ:
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;
}
}
এখানে:
[...]স্প্রেড অপারেটর ব্যবহার করে পুরানো স্টেট থেকে একটি নতুন অ্যারে তৈরি করা হয়েছে, যাতে কোনো মৌলিক পরিবর্তন না হয়।filter()পদ্ধতি ব্যবহার করে স্টেট থেকে একটি আইটেম সরানো হয়েছে, এবং নতুন অ্যারে রিটার্ন করা হয়েছে।
২. Object.assign() ব্যবহার করা
JavaScript-এর 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 }) দিয়ে একটি নতুন অবজেক্ট তৈরি করা হচ্ছে, যা পুরোনো স্টেটের কপি, তবে count প্রপার্টি পরিবর্তিত হয়েছে।
৩. স্প্রেড অপারেটর (Spread Operator) ব্যবহার করা
JavaScript-এ স্প্রেড অপারেটর (...) ব্যবহার করলে, আপনি একটি অবজেক্ট বা অ্যারে কপি করতে পারেন, যা অপরিবর্তনীয় স্টেট রাখার জন্য খুবই কার্যকরী। এটি অনেক সহজ এবং পরিষ্কার পদ্ধতি।
উদাহরণ:
function counterReducer(state = { count: 0 }, action) {
switch (action.type) {
case 'INCREMENT':
return { ...state, count: state.count + 1 };
case 'DECREMENT':
return { ...state, count: state.count - 1 };
default:
return state;
}
}
এখানে:
{ ...state, count: state.count + 1 }এর মাধ্যমে পুরানো স্টেটের কপি তৈরি হচ্ছে এবং কেবলcountপ্রপার্টি পরিবর্তিত হচ্ছে।
৪. Immutable.js ব্যবহার করা
Immutable.js একটি লাইব্রেরি যা JavaScript-এ ইমিউটেবল ডেটা স্ট্রাকচার সরবরাহ করে। এটি অ্যারে, অবজেক্ট, মেপ, সেট ইত্যাদি পরিবর্তনশীল ডেটা স্ট্রাকচারকে অপরিবর্তনীয় (immutable) করে তোলে। Redux-এ ইমিউটেবল স্টেট ম্যানেজমেন্টের জন্য আপনি Immutable.js ব্যবহার করতে পারেন।
উদাহরণ:
import { Map } from 'immutable';
function counterReducer(state = Map({ count: 0 }), action) {
switch (action.type) {
case 'INCREMENT':
return state.update('count', count => count + 1);
case 'DECREMENT':
return state.update('count', count => count - 1);
default:
return state;
}
}
এখানে, state.update('count', count => count + 1) ব্যবহার করে স্টেটের count প্রপার্টি পরিবর্তন করা হচ্ছে, কিন্তু পুরানো স্টেট অপরিবর্তনীয় রাখা হচ্ছে।
৫. Redux Toolkit ব্যবহার করা
Redux Toolkit Redux-এ স্টেট ম্যানেজমেন্টের জন্য আধুনিক এবং সহজ উপায়। Redux Toolkit এর মধ্যে কিছু ইমিউটেবল ফিচার রয়েছে, যেমন createSlice, যা ইমিউটেবল স্টেট ম্যানেজমেন্টকে আরও সহজ করে তোলে।
উদাহরণ:
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: { count: 0 },
reducers: {
increment: state => {
state.count += 1; // এখানে Redux Toolkit স্বয়ংক্রিয়ভাবে ইমিউটেবল রিয়্যাকশন পরিচালনা করে
},
decrement: state => {
state.count -= 1;
}
}
});
export const { increment, decrement } = counterSlice.actions;
export default counterSlice.reducer;
এখানে, Redux Toolkit ব্যবহার করলে, আমরা সরাসরি স্টেট পরিবর্তন করতে পারি, তবে এটি বাইরেরভাবে স্টেটকে অপরিবর্তনীয় রাখে।
সারাংশ
Redux-এ স্টেটকে অপরিবর্তনীয় (immutable) রাখা গুরুত্বপূর্ণ, কারণ এটি অ্যাপ্লিকেশনের আচরণ পূর্বানুমানযোগ্য এবং সহজে ডিবাগযোগ্য করে তোলে। স্টেটকে ইমিউটেবল রাখার জন্য কিছু কৌশল ব্যবহার করা হয়:
- নতুন কপি তৈরি করা (স্প্রেড অপারেটর বা
Object.assign()ব্যবহার করে), - Immutable.js ব্যবহার করা,
- Redux Toolkit ব্যবহার করা, যা ইমিউটেবল স্টেট পরিচালনা করতে সাহায্য করে।
এই পদ্ধতিগুলির মাধ্যমে Redux অ্যাপ্লিকেশনটির স্টেট ম্যানেজমেন্ট আরও কার্যকর এবং স্থিতিশীল হয়।
Read more