ریداکس تولکیت (Redux Toolkit) یک مجموعه ابزار برای توسعه ریداکس (Redux) است. این ابزار بسیار هوشمند و کامل طراحی شده است. در این مقاله خواهید دید که چرا ریداکس تولکیت انتخاب بهتری برای برنامهنویسان ری اکت است. ریداکس تولکیت را در اصطلاح یک batteries-included میدانند. یعنی ابزاری که خودش همه نیازهای خود را برطرف میکند. نه مانند اسباب بازی کودکان که همه چیز داخل آن است به جز باتری! و برای کار کردن باید باتری جداگانه برای آن خریداری کنید!!
چرا ریداکس تولکیت؟
در ابتدا یک تعریف ساده از ریداکس ارائه میدهیم: ریداکس یک الگو و کتابخانه برای مدیریت و بهروزرسانی وضعیت (State) برنامه با استفاده از رویدادهایی به نام Action است. ریداکس، یک انبار (Store) متمرکز برای State محسوب میشود که در سراسر برنامه مورد استفاده قرار میگیرد و دارای قوانینی است که وظیفه آن تضمین بهروزرسانی State است. در ابتدای معرفی ریداکس، بسیاری از برنامهنویسان اعتقاد داشتند که ریاکت و ریداکس بهترین ترکیب برای مدیریت State در برنامههای نوشته شده به زبان ری اکت در مقیاس بزرگ هستند. اما بعد از مدتی محبوبیت ریداکس به دلیل موارد زیر کاهش پیدا کرد:
- پیکربندی store در ریداکس اصلا کار سادهای نیست.
- برای اینکه ریداکس با ریاکت کار کند نیاز به نصب چندین Package جداگانه داریم.
- ریداکس به کدهای تکراری بیش از حد نیاز دارد. کدهایی که بارها و بارها مجبور به نوشتن آن هستید.
به خاطر وجود این مشکلات، خالق ریداکس، Dan Abramov مقالهای را با نام You Might Not Need Redux منتشر کرد که به افراد توصیه میکند فقط در مواقع نیاز از ریداکس استفاده کنند و در هنگام توسعه برنامههای پیچیدهتر از روشهای دیگر پیروی کنند. آیا به دنبال دلیل واضحتری برای استفاده از ریداکس تولکیت به جای ریداکس هستید؟ پس اگر قانع نشدید، در ادامه این مطلب با ما همراه باشید. ابتدا موارد بهبود یافته در ریداکس تولکیت را به شما معرفی میکنیم و سپس با دو مثال خوب شما را با بهبودهای عملیاتی آن آشنا خواهیم کرد.
ریداکس تولکیت چه مشکلاتی را حل میکند؟
ریداکس تولکیت (که قبلاً به عنوان Redux Starter Kit شناخته میشد) گزینههایی را برای پیکربندی store و ایجاد اکشنها و کاهشدهندههای سادهتر فراهم میکند. ریداکس تولکیت این کار را با انتزاع API Redux فراهم میآورد. این صرفاً یک پاسخ ساده و کوتاه بود و برای شرح دقیق نحوه سادهسازی کارها نیاز به مطلب تخصصیتری است که از حوصله این بحث خارج میباشد. به بیان ساده ریداکس تولکیت یک جعبه ابزار برای نوشتن منطق ریداکس است. این جعبه ابزار شامل بستهها و توابعی میشود که برای ساخت یک برنامه ریداکس ضروری هستند. در واقع عمل اصلی ریداکس تولکیت سادهتر کردن ریداکس است تا از اشتباهات رایج جلوگیری کرده و نوشتن برنامههای ریداکس را آسانتر کند.
عنوان تبلیغ: آموزش پروژه محور ریداکس تولکیت
ریداکس تولکیت شامل چه ابزاری است؟
ریداکس تولکیت با چندین بسته مفید مانند Immer، Redux-Thunk و Reselect همراه است. این بستهها کمک زیادی به سادهتر کردن توسعه برنامههای ریاکت میکند و به برنامهنویسان اجازه میدهد تا State را مستقیماً تغییر دهند. Reselect نیز یک کتابخانه ساده انتخاب کننده برای ریداکس است که عملکردهای Reduce را ساده میکند.
در ادامه با توابعی آشنا میشویم که ریداکس را سادهتر کرده و مدیریت آن را آسان میکنند.
- configureStore: یک نمونه مانند createStore اصلی از ریداکس ایجاد میکند و یک object را میپذیرد و افزونه Redux DevTools را به طور خودکار تنظیم میکند.
- createAction: رشتهای از نوع action میپذیرد و یک تابع ایجاد کننده action را که از آن استفاده میکند، برمیگرداند.
- createReducer: یک مقدار state اولیه و یک جدول جستجو از انواع actionها را برای توابع reducer میپذیرد و یک reducer ایجاد میکند که تمام انواع actionها را کنترل میکند.
- createSlice: یک stateاولیه و یک جدول جستجو با نام و توابع reducer را میپذیرد و به طور خودکار توابع ایجاد کننده action رشتههای action و یک تابع reducer را تولید میکند.
میتوانید از API های بالا برای سادهسازی کد boilerplate در ریداکس استفاده کنید، به خصوص با استفاده از متدهای createAction و createReducer. با این حال، میتوان با استفاده از createSlice به طور خودکار توابع action و reducer را تولید کرد. بیایید به همین نکته نگاه دقیقتری بیاندازیم. چه ویژگی خاصی createSlice برای ما به ارمغان میآورد؟ createSlice یک تابع کمکی است که یک Slice ایجاد میکند و سه ورودی و سه خروجی دارد که در جدول زیر نمایش داده شده است:
تابع | ورودی | خروجی |
createSlice | slice’s name | reducer |
initial state | action types | |
reducer function | action creators |
مثال اول: ابتدا، بیایید ببینیم که reducer ها و action ها در برنامههای سنتی React-Redux چگونه کار میکنند:
Actions
import {GET_USERS,CREATE_USER,DELETE_USER} from "../constant/constants";export const GetUsers = (data) => (dispatch) => {
dispatch({
type: GET_USERS,
payload: data,
});
};export const CreateUser = (data) => (dispatch) => {
dispatch({
type: CREATE_USER,
payload: data,
});
};export const DeleteUser = (data) => (dispatch) => {
dispatch({
type: DELETE_USER,
payload: data,
});
};
Reducers
import {GET_USERS,CREATE_USER,DELETE_USER} from "../constant/constants";const initialState = {
errorMessage: "",
loading: false,
users:[]
};const UserReducer = (state = initialState, { payload }) => {
switch (type) {
case GET_USERS:
return { ...state, users: payload, loading: false };
case CREATE_USER:
return { ...state, users: [payload,...state.users],
loading: false };
case DELETE_USER:
return { ...state,
users: state.users.filter((user) => user.id !== payload.id),
, loading: false };
default:
return state;
}
};export default UserReducer;
حالا ببینیم چگونه میتوان با استفاده از createSlice عملکرد مشابه را ساده کرد:
import { createSlice } from '@reduxjs/toolkit';export const initialState = {
users: [],
loading: false,
error: false,
};const userSlice = createSlice({
name: 'user',
initialState,
reducers: {
getUser: (state, action) => {
state.users = action.payload;
state.loading = true;
state.error = false;
},
createUser: (state, action) => {
state.users.unshift(action.payload);
state.loading = false;
},
deleteUser: (state, action) => {
state.users.filter((user) => user.id !== action.payload.id);
state.loading = false;
},
},
});export const { createUser, deleteUser, getUser } = userSlice.actions;export default userSlice.reducer;
همانطور که میبینید همه actionها و reducerها در یک جا قرار دارند که دو مزیت بزرگ برای ما خواهد داشت؛ اول اینکه دیگر نیاز نیست هر action و عملکرد مربوط به آن را در داخل reducerمدیریت کنید و دوم اینکه هنگام استفاده از createSlice نیازی به استفاده از سوئیچ برای شناسایی actionنیست.
وقتی صحبت از حالت mutating به میان میآید، (یعنی زمانی که بخواهید وضعیت یک state را بدون استفاده از تابع setState به روز کنید) در ریداکس خطاهایی ایجاد میشود که برای رفع آنها به توابع جاوا اسکریپت مانند spread operator وObject assign نیاز دارید. اما از آنجایی که ریداکس تولکیت از Immer استفاده میکند، لازم نیست نگران تغییر state باشید. به این خاطر که در ریداکس تولکیت یک Slice از actionها و reducerها ایجاد شده و میتوانید آن را Export کرده و در کامپوننت و store خود برای پیکربندی ریداکس استفاده کنید. پس دیگر نیازی به داشتن فایل و دایرکتوری جداگانه برای actionها و reducerها نیست.
import { configureStore } from "@reduxjs/toolkit";
import userSlice from "./features/user/userSlice";export default configureStore({
reducer: {
user: userSlice,
},
});
این store میتواند مستقیماً در کامپوننت از طریق APIهای ریداکس با استفاده از useSelector و useDispatch استفاده شود.
مثال دوم: مدیریت جریانهای ناهمگام ریداکس
ریداکس تولکیت برای این کار یک متد API ویژه به نام createAsyncThunk ارائه میکند که در واقع یک شناسه از نوع string و یک بازخوانی ایجادکننده بار (payload creator callback) را میپذیرد که منطق واقعی همگامسازی را انجام میدهد و ارسال action مربوطه را انجام میدهد. با این کار میتوانید انواع actionرا در reducerهای خود مدیریت کنید.
import axios from "axios";
import { createAsyncThunk } from "@reduxjs/toolkit";export const GetPosts = createAsyncThunk(
"post/getPosts", async () => await axios.get(`${BASE_URL}/posts`)
);export const CreatePost = createAsyncThunk(
"post/createPost",async (post) => await axios.post(`${BASE_URL}/post`, post)
);
برخلاف جریان دادههای سنتی، actionهای انجامشده توسط createAsyncThunk توسط بخش extraReducers در داخل یک slice مدیریت میشوند.
import { createSlice } from "@reduxjs/toolkit";
import { GetPosts, CreatePost } from "../../services";export const initialState = {
posts: [],
loading: false,
error: null,
};export const postSlice = createSlice({
name: "post",
initialState: initialState,
extraReducers: {
[GetPosts.fulfilled]: (state, action) => {
state.posts = action.payload.data;
},
[GetPosts.rejected]: (state, action) => {
state.posts = [];
},
[CreatePost.fulfilled]: (state, action) => {
state.posts.unshift(action.payload.data);
},
},
});export default postSlice.reducer;
توجه داشته باشید که در داخل extraReducers، میتوانید هر دو حالت تکمیل شده (fulfilled) و رد شده (rejected) را مدیریت کنید. از طریق این قطعه کد، میتوانید ببینید که ریداکس تولکیت چقدر کد را در مقایسه با ریداکس ساده میکند.
کلام آخر
بر اساس تجربیات به اشتراک گذاشته شده توسط برنامهنویسان ری اکت، ریداکس تولکیت یک انتخاب عالی برای شروع با ریداکس است زیرا هم کد را ساده میکند و با کاهش کد boilerplate به مدیریت stateها در ریداکس کمک میکند. در نهایت به این نکته باید اشاره کنیم که درست مانند ریداکس، ریداکس تولکیت نیز فقط برای ریاکت ساخته نشده است و میتوانیم آن را با هر فریمورک دیگری مانند Angular استفاده کنیم.
در پایان اگر علاقهمند به یادگیری ریداکس تولکیت هستید؛ پیشنهاد میکنیم دوره آموزش پروژه محور Redux Toolkit در سایت سکان آکادمی را از دست ندهید. این دورهی آموزشی، ویژگیهای کاربردی این ابزار قدرتمند، برای مدیریت State ها در پروژههای React را به صورت عملی و همراه با مثال و پروژه بیان میکند. در این دوره شما همراه با یادگیری مفاهیم اصلی Redux، به صورت پروژه محور Redux Toolkit را یاد خواهید گرفت.