برنامه نویسی

حذف 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>
    )
}
وارد حالت تمام صفحه شوید

از حالت تمام صفحه خارج شوید

خودشه. 😃 ممنون که خواندید. 🎉

نوشته های مشابه

دیدگاهتان را بنویسید

نشانی ایمیل شما منتشر نخواهد شد. بخش‌های موردنیاز علامت‌گذاری شده‌اند *

دکمه بازگشت به بالا