هوک useReducer (useReducer)
هوک useReducer در ری اکت زمانی کاربردی است که state های زیادی داری و منطق تغییرشان پیچیده است. این هوک شبیه useState است، اما مدیریت state را شبیه یک قانون نامه مرکزی انجام می دهد.
هوک useReducer در ری اکت چیست؟
هوک (Hook) یعنی تابع کمکی ری اکت که امکانات اضافه می دهد. useReducer در ری اکت کمک می کند state را با یک تابع به نام reducer کنترل کنی. reducer می گوید اگر این اتفاق افتاد، state چگونه عوض شود.
وقتی چند تکه state داری و منطقشان به هم وابسته است، به جای چند useState، می توانی از useReducer استفاده کنی تا همه چیز مرتب تر و قابل پیش بینی باشد.
قبل از ادامه، اگر useState را خوب نمی شناسی، صفحه هوک useState و صفحه هوکس در ری اکت را هم ببین.
سینتکس useReducer در ری اکت
سینتکس کلی useReducer در ری اکت سه آرگومان می گیرد: reducer، initialState و یک init اختیاری برای مقداردهی اولیه.
useReducer(reducer, initialState, init);
تابع reducer منطق تغییر state را دارد. initialState مقدار اولیه است که معمولاً یک شی یا آرایه است. آرگومان init اختیاری است و فقط برای راه اندازی اولیه استفاده می شود.
خروجی useReducer در ری اکت دو چیز است: state فعلی و تابع dispatch. با dispatch می گویی چه اتفاقی افتاده است؛ reducer بر اساس آن، state جدید را برمی گرداند.
مثال امتیاز دو بازیکن با useReducer در ری اکت
در مثال منبع، با useReducer امتیاز دو بازیکن را نگه می داریم. شبیه مسابقه در حیاط مدرسه است؛ هر بار روی اسم یک نفر کلیک می کنی، امتیازش یکی زیاد می شود.
initialState یک آرایه از بازیکن هاست. reducer روی این آرایه کار می کند و اگر type عمل "INCREASE" باشد، امتیاز همان بازیکن را یک واحد زیاد می کند.
کد کامل مثال useReducer در ری اکت
import { useReducer } from "react";
import { createRoot } from "react-dom/client";
const initialScore = [
{
id: 1,
score: 0,
name: "John",
},
{
id: 2,
score: 0,
name: "Sally",
},
];
const reducer = (state, action) => {
switch (action.type) {
case "INCREASE":
return state.map((player) => {
if (player.id === action.id) {
return {
...player,
score: player.score + 1,
};
} else {
return player;
}
});
default:
return state;
}
};
function Score() {
const [score, dispatch] = useReducer(reducer, initialScore);
const handleIncrease = (player) => {
dispatch({
type: "INCREASE",
id: player.id,
});
};
return (
<>
{score.map((player) => (
<div key={player.id}>
<label>
<input
type="button"
onClick={() => {
handleIncrease(player);
}}
value={player.name}
/>
{player.score}
</label>
</div>
))}
</>
);
}
createRoot(document.getElementById("root")).render(
<Score />
);
در این کد، state یک آرایه از بازیکن هاست. هر بازیکن id، name و score دارد. وقتی روی دکمه یک بازیکن کلیک می کنی، تابع handleIncrease با dispatch یک action می فرستد.
reducer براساس action.type تصمیم می گیرد چه کند. اگر نوع عمل "INCREASE" باشد، فقط امتیاز همان بازیکنی که id برابر action.id دارد، زیاد می شود. بقیه بازیکن ها بدون تغییر برمی گردند.
نکته: این الگو در پروژه های واقعی بزرگ کمک می کند منطق تغییر state در یک جای مشخص و قابل فهم بماند.
برای کارهای ساده، همان useState کافی است. اما وقتی state تو تو در تو و وابسته شد، useReducer در ری اکت انتخاب بهتری است. می توانی کنار useContext هم از آن استفاده کنی و یک مدیریت state سراسری تمیز بسازی.
هر وقت خواستی این مفاهیم را مرور کنی، صفحه useReducer در ری اکت در UnderDevelops نقطه شروع خوبی است.
جمع بندی سریع
- useReducer در ری اکت شبیه useState است اما برای منطق پیچیده.
- سه ورودی دارد: reducer، initialState و init اختیاری.
- خروجی دو چیز است: state و تابع dispatch.
- منطق تغییر state فقط داخل تابع reducer تعریف می شود.
- برای چند state وابسته و سنگین، useReducer انتخاب خیلی خوبی است.