حذف 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>
)
}
خودشه. 😃 ممنون که خواندید. 🎉



