حذف useState و useReducer: چرا useImmer گزینه بهتری است

در React، useState
و useReducer
معمولا برای مدیریت دولت استفاده می شود. در حالی که useImmer
یک جایگزین محبوب برای useState
، در این مقاله، بررسی خواهیم کرد که چگونه می تواند به عنوان یک جایگزین ساده تر و موثرتر نیز عمل کند useReducer
.
در صورتی که هنوز با استفاده از آن آشنا نیستید useImmer
و استفاده از آن به عنوان جایگزینی برای useState
، می توانید بخش زیر را مطالعه کنید. در غیر این صورت، به راحتی به بخش اصلی این مقاله بروید.
در صورتی که با useImmer آشنایی ندارید
useImmer
یک قلاب سفارشی React است. شبیه به useState
اما برخی از مزایای متمایز را ارائه می دهد، به خصوص وقتی صحبت از مدیریت وضعیت پیچیده می شود. با useImmer
، می توانید وضعیت را طوری به روز کنید که گویی مستقیماً قابل تغییر است، شبیه به جاوا اسکریپت معمولی. این امکان پذیر است زیرا در پشت صحنه useImmer
استفاده می کند Immer
کتابخانه برای ایجاد یک نسخه تغییرناپذیر جدید از حالت.
برای استفاده useImmer
ابتدا باید با اجرای دستور زیر در ترمینال خود آن را نصب کنید:
npm install immer use-immer
یک مثال ساده از useImmer
:
/* importing useImmer */
import { useImmer } from 'use-immer';
/* functional component */
function Count() {
/* Declaring a new state variable using the useImmer hook.
Here, we are initializing our state with a single
property called "count" with an initial value of 0 */
const [state, updateState] = useImmer({ count: 0 });
/* Defining a function that will modify our state */
const increment = () => {
/* calling the updateState function and passing as
it a draft */
updateState(draft => {
/* Here we are directly modifying the draft as
if it were mutable */
draft.count += 1;
})
}
/* Defining another function that will modify our state */
const decrement = () => {
/* Calling the updateState function and pass it a draft */
updateState(draft => {
/*Here we are directly modifying the draft as
if it were mutable */
draft.count -= 1;
})
}
/* Rendering the UI using the state */
return (
<div>
<h3>Count: {state.count}</h1>
<button onClick={increment}>Increment</button>
<button onClick={decrement}>Decrement</button>
</div>
)
}
چرا باید به جای useReducer از useImmer استفاده کنیم
نمونه ای از آن را بررسی خواهیم کرد useImmer
که به دنبال آن است useReducer
الگو. ما حالت و اقدامات را ایجاد خواهیم کرد و از آنها به روشی مشابه استفاده خواهیم کرد useReducer
، اما با افزایش خوانایی، انعطاف پذیری و تغییرپذیری useImmer. از طریق این مثال، خواهیم دید که چرا useImmer
باید بیشتر از useReducer
.
useImmer را وارد کنید و کامپوننت عملکردی را ایجاد کنید
// import useImmer
import { useImmer } from 'use-immer';
// functional component
function Cart() {
// ...
}
حالت اولیه را تعریف کنید
هنگام استفاده از useReducer
، تعریف حالت اولیه قبل از ادامه کار معمول است. به طور مشابه، ما از این رویکرد با استفاده از useImmer
قلاب. برای انجام این کار، حالتی ایجاد می کنیم که تا حدودی پیچیده است و شبیه حالتی است که معمولاً با آن تعریف می کنید. useReducer
.
// initial state
const initialState = {
items: [],
shippingAddress: {
street: '',
city: ''
}
}
دولت را ایجاد کنید
ما حالت اولیه خود را تعریف کرده ایم. اکنون، ما می توانیم حالت خود را با استفاده از useImmer
قلاب.
// Creating the state
const [cart, updateCart] = useImmer(initialState)
را useImmer
هوک آرایه ای حاوی دو مقدار را برمی گرداند: وضعیت فعلی (cart
در این مثال) و تابعی که می توانیم برای به روز رسانی حالت (updateCart
در این مثال).
Actions را ایجاد کنید
هنگام استفاده از useReducer
قلاب، برای به روز رسانی حالت، تعریف اقدامات اجباری است. به طور مشابه، ما اقداماتی را برای ایجاد خواهیم کرد useImmer
برای شبیه سازی همان الگو و دستیابی به به روز رسانی حالت قابل پیش بینی.
const actions = {
// Add an item to the cart
addItemToCart: (payload) => {
const { item } = payload
updateCart(draft => {
draft.items.push(item)
});
},
// Remove an item from the cart
removeItemFromCart: (payload) => {
const { itemIndex } = payload
updateCart(draft => {
draft.items.splice(itemIndex, 1)
})
},
// Update the shipping address of the cart
updateShippingAddress: (payload) => {
const { shippingAddress } = payload
updateCart(draft => {
draft.shippingAddress = shippingAddress
})
}
}
تعریف اقدامات با استفاده از روش فوق دو مزیت نسبت به آن دارد useReducer
:
⚡️ تغییرپذیری: با useImmer
، ما قدرت به روز رسانی های قابل تغییر را داریم که به کد کمتر و کدهای بیشتر شبیه جاوا اسکریپت اجازه می دهد. این بر خلاف است useReducer
که به یک رویکرد برنامه نویسی کاربردی تر و به روز رسانی های تغییرناپذیر نیاز دارد. با استفاده از به روز رسانی های قابل تغییر در useImmer
، می توانید با خطوط کمتر کد به همان نتیجه برسید و نوشتن و نگهداری آن را آسان تر می کند.
⚡️ خوانایی: در مقایسه با useReducer
، که در آن اقدامات معمولاً به عنوان a تعریف می شوند switch
مورد در یک تابع کاهنده، useImmer
رویکرد می تواند خواناتر باشد زیرا هر عمل یک تابع جداگانه با نامی واضح و مختصر است.
UI را با JSX رندر کنید
در نهایت می توانیم از cart
ایالت و actions
شی در JSX برای رندر کردن رابط کاربری.
<div>
{/* Displaying the changes of the 'cart' state */}
<p>Cart State: {JSON.stringify(cart)}</p>
{/* Display a list of items in the cart */}
<ul>
{cart.items.map((item, index) => (
<li key={index}>
{item.name} - ${item.price}
{/* Call the removeItemFromCart action when the remove button is clicked */}
<button onClick={() => actions.removeItemFromCart({ itemIndex: index })}>Remove</button>
</li>
))}
</ul>
{/* Call the addItemToCart action when the add item button is clicked */}
<button onClick={() => actions.addItemToCart({ item: { name: 'Product', price: 9.99 } })}>
Add Item
</button>
{/* Allow the user to update the shipping address */}
<div>
<h4>Shipping Address:</h4>
<input type="text" placeholder="Street"
value={cart.shippingAddress.street}
onChange={(e) => actions.updateShippingAddress({ shippingAddress: { ...cart.shippingAddress, street: e.target.value } })}
/>
<input type="text" placeholder="City"
value={cart.shippingAddress.city}
onChange={(e) => actions.updateShippingAddress({ shippingAddress: { ...cart.shippingAddress, city: e.target.value } })}
/>
</div>
</div>
مزایای استفاده از useImmer نسبت به useReducer
ما قبلاً دو مزیت (تغییرپذیری و خوانایی) استفاده از useImmer نسبت به useReducer را بررسی کرده ایم. Create Actions
بخش. با این حال، یک مزیت مهم دیگر وجود دارد که ارزش بحث را دارد که در این بخش به آن خواهیم پرداخت.
⚡️ انعطاف پذیری: با useImmer، امکان به روز رسانی شی حالت خارج از اکشن های تعریف شده وجود دارد. این در useReducer امکان پذیر نیست و می تواند به ویژه در شرایط خاصی که به انعطاف پذیری بیشتری در به روز رسانی حالت نیاز دارید مفید باشد.
در اینجا مثالی از نحوه پاک کردن سبد خرید با استفاده از آن آورده شده است useImmer
بدون تعریف عمل جدید:
<button onClick={() => updateCart(initialState)}>Clear Cart</button>
این مولفه دکمه را بازنشانی می کند cart
وضعیت را به حالت اولیه خود بازگردانید و تمام موارد موجود در سبد خرید را پاک کنید. با useImmer
، میتوانیم شی state را مستقیماً به این روش ad-hoc بدون نیاز به تعریف عمل بهروزرسانی کنیم. این امکان پذیر نیست با useReducer
، که در آن تمام به روز رسانی های حالت باید از طریق اقدامات تعریف شده ارسال شوند.
کد کامل
// import useImmer
import { useImmer } from 'use-immer';
// functional component
export default function Cart() {
// Define the initial state of the cart
const initialState = {
items: [],
shippingAddress: {
street: '',
city: ''
}
};
// Call the useImmer hook to create a cart state
const [cart, updateCart] = useImmer(initialState);
// Define a set of actions that can be used to update the cart state
const actions = {
// Add an item to the cart
addItemToCart: (payload) => {
const { item } = payload
updateCart(draft => {
draft.items.push(item)
});
},
// Remove an item from the cart
removeItemFromCart: (payload) => {
const { itemIndex } = payload
updateCart(draft => {
draft.items.splice(itemIndex, 1)
})
},
// Update the shipping address of the cart
updateShippingAddress: (payload) => {
const { shippingAddress } = payload
updateCart(draft => {
draft.shippingAddress = shippingAddress
})
}
}
// Render the cart UI
return (
<div>
{/* Displaying the changes of the 'cart' state */}
<p>Cart State: {JSON.stringify(cart)}</p>
{/* Display a list of items in the cart */}
<ul>
{cart.items.map((item, index) => (
<li key={index}>
{item.name} - ${item.price}
{/* Call the removeItemFromCart action when the remove button is clicked */}
<button onClick={() => actions.removeItemFromCart({ itemIndex: index })}>Remove</button>
</li>
))}
</ul>
{/* Call the addItemToCart action when the add item button is clicked */}
<button onClick={() => actions.addItemToCart({ item: { name: 'Product', price: 9.99 } })}>
Add Item
</button>
{/* Allow the user to update the shipping address */}
<div>
<h4>Shipping Address:</h4>
<input type="text" placeholder="Street"
value={cart.shippingAddress.street}
onChange={(e) => actions.updateShippingAddress({ shippingAddress: { ...cart.shippingAddress, street: e.target.value } })}
/>
<input type="text" placeholder="City"
value={cart.shippingAddress.city}
onChange={(e) => actions.updateShippingAddress({ shippingAddress: { ...cart.shippingAddress, city: e.target.value } })}
/>
</div>
{/* Call the updateCart function with the initial state to clear the cart */}
<button onClick={() => updateCart(initialState)}>Clear Cart</button>
</div>
)
}
خودشه. 😃 ممنون که خواندید. 🎉