در این مقاله قصد داریم تا Redux و Redux Toolkit، را که مجموعهای از ابزارهایی است که استفاده از Redux را سادهتر میکند باهم بررسی کنیم.
Redux یک کتابخانه مدیریت state است که به ما این امکان را میدهد تا state برنامههای جاوااسکریپتی خود را به طور کارآمدتر و قابل پیشبینی مدیریت کنیم.
تصور کنید که در حال ساختن یک خانه هستیم و باید تمام مصالحی که استفاده میکنیم و مقدار پولی که خرج میکنیم را پیگیری نماییم. به جای پیگیری همه این موارد در ذهن خود و یا روی یک تکه کاغذ، میتوانیم از یک دفتر کل برای پیگیری هر معامله استفاده کنیم. Redux به طور مشابه با پیگیری state برنامه ما در یک مکان به نام store کار میکند.
فرض کنید در حال ساخت یک سایت e-commerce هستیم. ممکن است لازم باشد تا اقلام موجود در سبد خرید کاربر، اطلاعات پرداخت و جزئیات حمل و نقل آنها را پیگیری کنیم.
Redux بهجای این که این اطلاعات را با استفاده از props از کامپوننتی به کامپوننت دیگر انتقال دهد، به ما این امکان را میدهد تا آنها را در یک مکان مرکزی ذخیره نماییم، جایی که به راحتی قابل دسترس بوده و بهروز باشد. این امر مدیریت stateهای پیچیده و سازماندهی برنامه را آسانتر میکند.
لازم است به این نکته توجه داشته باشیم که Redux به React محدود نمیشود و میتوانیم از آن با فریمورکهای دیگر یا حتی وانیلا جاوااسکریپت استفاده نماییم.
Redux میتواند به سادهسازی فرآیند مدیریت state کمک کند، بهویژه هنگامی که با کامپوننتهای پیچیده و به هم پیوسته سروکار داریم. در ادامه دلایلی را ذکر میکنیم که ممکن است به آن دلیل بخواهیم از Redux در برنامه خود استفاده کنیم:
همانطور که قبلا به آن اشاره کردیم، Redux ما را قادر میسازد تا یک store متمرکز داشته باشیم که state کل برنامه را مدیریت میکند. همه کامپوننتهای برنامه ما میتوانند به این store دسترسی داشته باشند و در صورت نیاز، دادهها را از آن بازیابی کرده یا بهروز رسانی نمایند.
کامپوننتهای کلیدی که این رویکرد متمرکز را در مدیریت state ممکن میسازند عبارتند از:
در ادامه نقش هر یک از این موارد را به صورت کامل بررسی میکنیم.
Redux store مانند یک ظرف بسیار بزرگ است که تمام دادههای برنامه ما را در خود نگه میدارد. store را به عنوان جعبهای در نظر میگیریم که محفظههای مختلف برای انواع دادههای مختلف دارد. میتوانیم هر دادهای را که میخواهیم، با هر نوع دادهای مانند رشتهها، اعداد، آرایهها، آبجکتها و حتی توابع را در این محفظهها ذخیره نماییم. همچنین، store تنها منبع برای state برنامه ما است. این بدان معناست که هر کامپوننت در برنامه میتواند برای بازیابی و بهروزرسانی دادهها به آن دسترسی داشته باشد.
یک action آبجکتی است که توضیح میدهد چه تغییراتی باید در state برنامه ما ایجاد شود. action دادهها را از برنامه ما به Redux store ارسال میکند و به عنوان تنها راه برای بهروزرسانی store عمل میکند.
یک action باید دارای یک ویژگی type باشد که action در حال انجام را توصیف کند. این ویژگی type معمولاً به عنوان یک constant رشته برای اطمینان از ثبات و جلوگیری از اشتباهات تایپی تعریف میشود.
همینطور یک action علاوه بر ویژگی type، میتواند ویژگی payload نیز داشته باشد. ویژگی payload دادههایی را نشان میدهد که اطلاعات اضافی در مورد action در حال اجرا ارائه میدهند.
برای مثال، اگر یک action از تایپ ADD_TASK
باشد، payload ممکن است یک آبجکت حاوی id
، text
و completed status
یک آیتم تسک جدید باشد. به عنوان مثال:
{ type: 'ADD_TASK', payload: { id: 1, text: 'Buy groceries', completed: false } }
باید به این نکته توجه داشته باشیم که برای ایجاد اکشنها از Action Creatorها استفاده میکنیم. Action creatorها توابعی هستند که آبجکتهای اکشن را ایجاد و return میکنند.
در ادامه مثالی برای یک action creator داریم که text یک تسک را میگیرد و یک آبجکت اکشن را برای اضافه کردن تسک به Redux store برمیگرداند:
function addTask(taskText) { return { type: 'ADD_TASK', payload: { id: 1, text: taskText, completed: false } } }
Dispatch در redux تابعی است که توسط store ارائه میشود و به ما این امکان را میدهد تا برای بهروزرسانی state برنامه خود یک action ارسال کنیم. هنگامی که ما dispatch
را فراخوانی میکنیم، store از طریق همه reducerهای موجود actionای را انجام میدهد، که به نوبه خود state را مطابق با آن بهروزرسانی میکند.
Reducer در Redux تابعی است که state فعلی یک برنامه و یک action را به عنوان آرگومان میگیرد و یک state جدید را بر اساس actionای که دریافت کرده است return میکند. به عنوان مثال:
const initialState = { count: 0 }; function counterReducer(state = initialState, action) { switch(action.type) { case 'INCREMENT': return { ...state, count: state.count + 1 }; case 'DECREMENT': return { ...state, count: state.count - 1 }; default: return state; } }
در کد بالا یک reducer ساده به نام counterReducer
داریم که state متغیر count را مدیریت میکند. این reducer دو آرگومان state
و action
را دریافت میکند. آرگومان state
وضعیت فعلی برنامه ما را نشان میدهد، و آرگومان action
بیانگر اقدامی است که برای تغییر state ارسال شده است.
reducer از یک دستور switch
برای بررسی type اکشن استفاده میکند و بر اساس آن تایپ، state را متناسب با آن بهروزرسانی میکند.
به عنوان مثال، اگر تایپ اکشن INCREMENT باشد، reducer یک آبجکت state جدید که count یک واحد افزایش پیدا کرده است را return میکند. همچنین، اگر تایپ اکشن DECREMENT باشد، reducer یک آبجکت state جدید که count یک واحد کاهش پیدا کرده است را return خواهد کرد.
اکنون که با اصول اولیه Redux و نحوه عملکرد آن آشنا شدیم، قصد داریم تا یک پروژه ساده در دنیای واقعی را پیادهسازی کنیم. برای این مثال، ما یک برنامه ToDo List میسازیم که در آن میتوانیم تسکها را اضافه و حذف نماییم.
با اجرای دستور زیر در ترمینال، یک پروژه React جدید ایجاد میکنیم.
npm create vite@latest your-project-name -- --template react cd your-project-name npm install
برای این کار میتوانیم از ابزاری مانند Vite استفاده کنیم که یک پروژه React جدید ایجاد کرده و تمام وابستگیهای لازم را نصب میکند.
Redux برای عملیات خود به چند dependency نیاز دارد که عبارتند از:
میتوانیم موارد ذکر شده را با استفاده از npm و به صورت زیر نصب کنیم:
npm install \ redux \ react-redux \ redux-thunk \ redux-devtools-extension
اکنون reducer را برای برنامه خود ایجاد میکنیم.
در دایرکتوری src
یک فولدر جدید به نام reducers
ایجاد کرده و در داخل آن دو فایل جدید به نامهای index.js
و taskReducer.js
میسازیم.
فایل index.js
نشان دهنده root reducer است که همه reducerهای منفرد را در برنامه ترکیب میکند. اما در مقابل، فایل taskReducer.js
یکی از reducerهای منفرد است که در root reducer ترکیب میشود.
import taskReducer from "./taskReducer"; import { combineReducers } from "redux"; const rootReducer = combineReducers({ tasks: taskReducer, }); export default rootReducer;
در فایل index.js
بالا، ما از تابع combineReducers
برای ترکیب همه reducerها در یک root reducer استفاده میکنیم. در این مثال، ما فقط یک reducer(taskReducer
) داریم، بنابراین آن را به عنوان آرگومان به combineReducers
ارسال مینماییم.
سپس reducer ترکیبی حاصل export میشود تا سایر فایلهای برنامه بتوانند آن را import کرده و برای ایجاد store از آن بهرهمند شوند. در ادامه کد taskReducer
را داریم:
const initialState = { tasks: [] }; const taskReducer = (state = initialState, action) => { switch (action.type) { case 'ADD_TASK': return { ...state, tasks: [...state.tasks, action.payload] }; case 'DELETE_TASK': return { ...state, tasks: state.tasks.filter(task => task.id !== action.payload) }; default: return state; } }; export default taskReducer ;
در فایل taskReducer.js
بالا، یک تابع reducer تعریف میکنیم که دو آرگومان state
و action
را میگیرد. آرگومان state
نشان دهنده state فعلی برنامه است، و آرگومان action
نشان دهنده actionای است که برای بهروزرسانی state ارسال میشود.
دستور switch
در داخل reducer موارد مختلف را بر اساس type اکشن کنترل میکند. برای مثال، اگر تایپ اکشن ADD_TASK
باشد، reducer یک آبجکت state جدید با یک تسک جدید را به آرایه tasks
اضافه میکند. و اگر تایپ اکشن DELETE_TASK
باشد، reducer یک آبجکت state جدید با تسکهای فعلی فیلتر شده برای حذف تسک با id
مشخص شده return میکند.
اکنون که تنظیمات اولیه برنامه خود را آماده کردهایم، میخواهیم یک فایل جدید به نام store.js
در دایرکتوری src
میسازیم. اینجا جایی است که ما Redux store خود را تعریف میکنیم:
import { createStore, applyMiddleware } from "redux"; import thunk from "redux-thunk"; import { composeWithDevTools } from "redux-devtools-extension"; import rootReducer from "./reducers/index"; const store = createStore( rootReducer, composeWithDevTools(applyMiddleware(thunk)) ); export default store;
کد بالا با ایجاد یک نمونه جدید از store با استفاده از تابع createStore
، یک Redux store را راهاندازی میکند. سپس rootReducer، که تمام reducerهای برنامه را در یک reducer واحد ترکیب میکند، به عنوان آرگومان به createStore
ارسال میشود.
علاوه بر این، کد از دو کتابخانه دیگر به نامهای redux-thunk
و edux-devtools-extension
نیز استفاده میکند.
کتابخانه redux-thunk
به ما این امکان را میدهد تا اکشنهای asynchronous بنویسیم، در حالی که کتابخانه redux-devtools-extension
به ما کمک میکند تا از افزونه مرورگر Redux DevTools برای دیباگ کردم و بازرسی state و actionهای موجود در store استفاده نماییم.
در نهایت، store را export میکنیم تا بتوانیم از آن در برنامه خود استفاده کنیم. ما از تابع composeWithDevTools
برای ارتقای store با قابلیت استفاده از افزونه Redux DevTools و از تابع applyMiddleware
برای اعمال middleware thunk در store استفاده میکنیم.
برای اتصال Redux store به برنامه ToDo، باید از کامپوننت Provider
از کتابخانه react-redux
استفاده نماییم.
ابتدا تابع Provider
و Redux store که ایجاد کردیم را به فایل main.jsx
خود import مینماییم. سپس، کامپوننت App
را داخل تابع Provider
قرار داده و store
را به عنوان prop به آن پاس میدهیم. این باعث میشود تا Redux store در دسترس همه کامپوننتهای داخلی App
قرار بگیرد.
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App"; import "./index.css"; import { Provider } from "react-redux"; import store from "./store"; ReactDOM.createRoot(document.getElementById("root")).render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> );
هنگامی که Redux <Provider>
را در برنامه خود راهاندازی کردیم، میتوانیم از افزونه Redux DevTools بهرهمند شویم. برای شروع کار با آن، ابتدا باید افزونه Redux DevTools را برای مرورگر خود دانلود کنیم.
پس از نصب، DevTools یک تب جدید مخصوص Redux به قسمت Developer Tools مرورگر ما اضافه میکند.
با کلیک بر روی تب State در Redux DevTools، میتوانیم state کل Redux store و هر actionای که ارسال شده است همراه با payloadهای آنها را مشاهده کنیم.
این موضوع میتواند در هنگام دیباگ کردن برنامه بسیار مفید باشد، زیرا میتوانیم state و actionها را به صورت real-time بررسی نماییم.
اکنون قصد داریم تا actionهای خود را ایجاد کنیم. همانطور که قبلا به آن اشاره کردیم، actionها نشان دهنده چیزی هستند که در برنامه اتفاق افتاده است. به عنوان مثال، هنگامی که کاربر یک تسک جدید اضافه میکند، یک اکشن add task را راهاندازی مینماید. به طور مشابه، هنگامی که یک تسک را حذف می کند، یک اکشن delete task را آغاز میکند.
برای ایجاد actionها، یک فولدر جدید به نام actions در دایرکتوری src
ایجاد میکنیم و سپس یک فایل جدید به نام index.js
در آن میسازیم. این فایل شامل تمام action creatorها برای برنامه ما خواهد بود.
export const addTodo = (text) => { return { type: "ADD_TASK", payload: { id: new Date().getTime(), text: text, }, }; }; export const deleteTodo = (id) => { return { type: "DELETE_TASK", payload: id, }; };
کد بالا دو action creator را export میکند: addTodo
و deleteTodo
. این توابع یک آبجکت با ویژگی type
را return میکنند که actionای که رخ داده است را توصیف مینماید.
در مورد addTodo
، ویژگی type
روی "ADD_TASK"
تنظیم میشود که نشان میدهد یک تسک جدید اضافه شده است. ویژگی payload
حاوی یک آبجکت است که مقادیر id
و text
تسک جدید را دربر میگیرد. id
با استفاده از متد جدید new Date().getTime()
تولید میشود و یک شناسه منحصربهفرد بر اساس زمان فعلی ایجاد میکند.
در مورد deleteTodo
، ویژگی type
روی "DELETE_TASK"
تنظیم میشود که نشان میدهد یک تسک حذف شده است. ویژگی payload
حاوی id
تسکی است که باید حذف شود.
میتوانیم این action creatorها را با استفاده از متد dispatch()
به Redux store بفرستیم، که تابع reducer مربوطه را فعال کند تا state برنامه را متناسب با آن، بهروزرسانی نماید.
اکنون که actionهای لازم را ایجاد کردهایم، میتوانیم به سمت ایجاد کامپوننتهایی برویم که این actionها را ارسال میکنند.
یک فولدر جدید به نام components در دایرکتوری src
ایجاد میکنیم. در داخل این فولدر هم دو فایل جدید با نامهای Task.jsx
و TaskList.jsx
میسازیم.
کامپوننت Task.jsx
مسئول افزودن تسکها خواهد بود. اما قبل از ادامه، باید موارد زیر را در فایل خود import کنیم:
addTodo
: برای افزودن تسکهای جدید به state.useDispatch
: برای ارسال اکشن addTodo
.useRef
: برای این که بتوانیم به المنتهای HTML رفرنس دهیم.import { useRef } from "react"; import { useDispatch } from "react-redux"; import { addTodo } from "../actions";
پس از import کردن این کامپوننتهای ضروری، میتوانیم به نوشتن کد برای Task.jsx
ادامه دهیم.
const Task = () => { const dispatch = useDispatch(); const inputRef = useRef(null); function addNewTask() { const task = inputRef.current.value.trim(); if (task !== "") { dispatch(addTodo(task)); inputRef.current.value = ""; } } return ( <div className="task-component"> <div className="add-task"> <input type="text" placeholder="Add task here..." ref={inputRef} className="taskInput" /> <button onClick={addNewTask}>Add task</button> </div> </div> ); }; export default Task;
در کد بالا یک کامپوننت متشکل از یک فیلد ورودی و یک دکمه ایجاد کردیم. هنگامی که کاربر بر روی دکمه Add task کلیک میکند، تابع addNewTask
اجرا میشود. این تابع از هوک useRef
برای بدست آوردن مقدار فیلد ورودی استفاده میکند و هر گونه space اضافی قبل یا بعد را حذف مینماید. سپس اکشن addTodo
را با تسک جدید به عنوان payload
ارسال میکند.
اکنون به کامپوننت TaskList.jsx
میرویم، که مسئول ارائه لیست تسکها و مدیریت حذف آنها میباشد. انجام این کار، باید موارد زیر را import کنیم:
import { useSelector, useDispatch } from "react-redux"; import { deleteTodo } from "../actions";
اکنون کدی را برای TaskList.jsx
مینویسیم که روی آرایه tasks
map انجام میدهد و هر تسک را رندر میکند:
import React from 'react'; import { useSelector, useDispatch } from 'react-redux'; import { deleteTodo } from '../actions'; const TaskList = () => { const tasks = useSelector((state) => state.tasks); const dispatch = useDispatch(); const handleDelete = (id) => { dispatch(deleteTodo(id)); }; return ( <div className="tasklist"> <div className="display-tasks"> <h3>Your tasks:</h3> <ul className="tasks"> {tasks.map((task) => ( <li className="task" key={task.id}> {task.text} <button className="delete-btn" onClick={() => handleDelete(task.id)} > delete </button> </li> ))} </ul> </div> </div> ); }; export default TaskList;
در کدی که داریم، کامپوننت بر روی هر تسک در آرایه tasks
یک loop ایجاد کرده و متن و یک دکمه delete را نمایش میدهد. هنگامی که کاربر روی دکمه delete کلیک میکند، تابع handleDelete
فراخوانی میشود و اکشن deleteTodo
را با id
تسک به عنوان payload ارسال مینماید.
در نهایت کامپوننتها را در فایل App.jsx
خود import کرده و رندر میکنیم.
import Task from "./components/Task"; import TaskList from "./components/TaskList"; function App() { return ( <div className="App"> <Task /> <TaskList /> </div> ); } export default App;
از آن جایی که تمرکز اصلی ما در این مقاله بر روی عملکر برنامه است از این رو یک استایل ساده و اولیه برای زیباتر شدن برنامه در این لینک قرار دادهایم که میتوانیم محتویات آن را در فایل index.css
خود قرار دهیم.
پس از اجرای همه چیز، میتوانیم نتیجه نهایی برنامه ToDo List خود را مشاهده کنیم.
در این برنامه میتوانیم عنوان تسک را در قسمت ورودی وارد کرده و بر روی دکمه Add task کلیک کنیم و به این ترتیب تسکها را اضافه نماییم. همچنین میتوانیم با کلیک روی دکمه delete که در کنار هر تسک قرار دارد، تسک مورد نظرمان را حذف کنیم.
با استفاده از Redux DevTools میتوانیم state و actionهای برنامه را نیز به راحتی ردیابی و بازرسی کنیم. این ویژگی به دیباگ کردن و درک نحوه عملکرد برنامه در پسزمینه کمک میکند.
اکنون ما یک برنامه ToDo کاملاً کاربردی داریم که آن را توسط Redux طراحی کردهایم. سورس کد برنامه در GitHub موجود میباشد.
در نهایت، مهم است که به این موضوع توجه داشته باشیم که state یک برنامه هنگام استفاده از Redux در memory ذخیره میشود. بنابراین، اگر کاربر صفحه را رفرش کند یا برنامه را ببندد، state از بین میرود. بنابراین، برای این که بتوانیم اطلاعات برنامه را حتی پس از خروج یا بستن صفحه توسط کاربر حفظ کنیم، باید آنها را در جایی خارج از حافظه برنامه ذخیره نماییم. برای انجام این کار میتوانیم از تکنیکهای مختلفی مانند local storage یا server-side storage استفاده کنیم.
در بخش بعدی مقاله Redux Toolkit را بررسی خواهیم کرد.
نوشتن کد Redux و مدیریت قسمتهای مختلف برنامه، مخصوصا زمانی که مقیاس برنامه بزرگتر شده و تعداد reducerها و actionها بیشتر میشود، میتواند کمی پیچیده باشد.
خوشبختانه Redux Toolkit راه حلی برای این مشکل ارائه میدهد و با حذف برخی از جنبههای پیچیدهتر و تکراریتر Redux، مانند ایجاد reducerها و actionها، روشی سادهتر و کارآمدتر برای مدیریت state برنامه ارائه میکند.
Redux Toolkit چندین مزیت نسبت به Redux دارد که عبارتند از:
immer
استفاده مینماید، که mutation مستقیم state را فعال میکند و نیاز به کپی دستی state {...state}
با هر reducer را از بین میبرد.در بخشهای بعدی، نحوه استفاده از Redux Toolkit برای سادهسازی کد Reduxای که برنامه ToDo خود را با آن ساختیم، بررسی خواهیم کرد.
برای استفاده از Redux Toolkit در برنامه React خود، باید دو dependency با نامهای @reduxjs/toolkit
و react-redux
را نصب کنیم.
پکیج @reduxjs/toolkit
ابزارهای لازم برای سادهسازی توسعه Redux را فراهم میکند، و react-redux
برای اتصال Redux store به کامپوننتهای React مورد استفاده قرار میگیرد.
npm install @reduxjs/toolkit react-redux
هنگامی که dependencyهای مورد نیاز را نصب کردیم، با استفاده از تابع createSlice
یک slice جدید ایجاد میکنیم. slice بخشی از Redux store است که مسئول مدیریت یک بخش خاص از state میباشد.
اگر Redux store را به عنوان یک کیک در نظر بگیریم، هر slice نشان دهنده یک بخش خاص از داده در store است. با ایجاد یک slice، میتوانیم رفتار state را در پاسخ به actionهای خاص با استفاده از توابع reducer تعریف کنیم.
برای ایجاد یک slice برای مدیریت برنامه ToDo، یک فایل جدید در مسیر src/features/todo/todoSlice.js
ایجاد میکنیم و کد زیر را درون آن قرار میدهیم:
import { createSlice } from "@reduxjs/toolkit"; const initialState = { tasks: [], }; const todoSlice = createSlice({ name: "todo", initialState, reducers: { addTodo: (state, action) => { state.tasks.push({ id: Date.now(), text: action.payload }); }, deleteTodo: (state, action) => { state.tasks = state.tasks.filter((task) => task.id !== action.payload); }, }, }); export const { addTodo, deleteTodo } = todoSlice.actions; export default todoSlice.reducer;
کد بالا یک slice به نام todoSlice
را با یک آبجکت initialState
که حاوی یک آرایه خالی از تسکها است، تعریف میکند.
آبجکت reducers
دو تابع reducer را تعریف میکند که عبارتند از: addTask
و deleteTask
. تابع addTask
یک آبجکت تسک جدید را به آرایه tasks
اضافه مینماید، و تابع deleteTask
یک تسک را بر اساس ویژگی id
آن از آرایه tasks
حذف میکند.
تابع createSlice
به طور خودکار بر اساس نام توابع reducerای که ارائه میدهیم، action creatorها و action typeها را تولید میکند. بنابراین لازم نیست ما به صورت دستی action creatorها را تعریف کنیم.
export
statement سپس action creatorهای تولید شده را export میکند، که میتوانند در قسمتهای دیگر برنامه برای ارسال actionها به slice استفاده شوند.
و در نهایت، تابع todoSlice.reducer
تمام اکشنهایی را که به طور خودکار بر اساس آبجکتهای reducer ارائه شده به تابع createSlice
تولید میشوند، مدیریت میکند. با export کردن آن به عنوان مقدار پیشفرض، میتوانیم آن را با reducerهای دیگر در برنامه ترکیب کنیم تا یک Redux store کامل ایجاد نماییم.
ایجاد یک Redux store با استفاده از Redux Toolkit بسیار ساده است.
ابتداییترین راه برای ایجاد یک store، استفاده از تابع configureStore()
است که به طور خودکار تمام reducerهای تعریف شده در برنامه را با هم ترکیب میکند تا یک root reducer برای ما ایجاد نماید.
برای این که در برنامهای که داشتیم store ایجاد کنیم، فایلی به نام src/store.js
را اضافه کرده و کد زیر را به آن میافزاییم:
import { configureStore } from "@reduxjs/toolkit"; import todoReducer from "./features/todo/todoSlice"; const store = configureStore({ reducer: { todo: todoReducer, }, }); export default store;
در این مثال، ابتدا تابع configureStore
را از پکیج @reduxjs/toolkit
و تابع todoReducer
را از یک فایل جداگانه import میکنیم.
سپس، با فراخوانی configureStore
و ارسال یک آبجکت با ویژگی reducer
، یک آبجکت store
میسازیم. ویژگی reducer
آبجکتی است که نام sliceهای reducer را به توابع reducer مربوطه نگاشت میکند. در این مثال، یک reducer slice به نام todo داریم و تابع reducer متناظر آن todoReducer میباشد.
در نهایت آبجکت store را export میکنیم تا بتوانیم آن را import کرد و در قسمتهای دیگر برنامه مورد استفاده قرار دهیم.
برای اینکه store Redux را در دسترس کامپوننتهای React در برنامه خود قرار دهیم، کامپوننت Provider
را از کتابخانه react-redux
import میکنیم و کامپوننت root، که معمولاً <App>
میباشد را درون آن قرار میدهیم.
کامپوننت Provider
از store بهعنوان یک prop استفاده میکند و آن را به تمام کامپوننتهای childای که نیاز به دسترسی به آن دارند، منتقل میکند.
import React from "react"; import ReactDOM from "react-dom/client"; import App from "./App.jsx"; import "./index.css"; import store from "./store.js"; import { Provider } from "react-redux"; ReactDOM.createRoot(document.getElementById("root")).render( <React.StrictMode> <Provider store={store}> <App /> </Provider> </React.StrictMode> );
اکنون میتوانیم کامپوننتهای React مانند Task.jsx
و TaskList.jsx
را ایجاد کنیم که از هوک useSelector
برای دسترسی به state فعلی از store استفاده می کنند. به طور مشابه، میتوانیم از هوک useDispatch
برای ارسال actionها برای بهروزرسانی store استفاده کنیم، درست همانطور که در Redux ساده انجام دادیم.
در این مقاله سعی کردیم تا با مفاهیم اصلی Redux و Redux toolkit آشنا شویم و به کمک آنها، یک پروژه ساده و واقعی انجام دهیم.