React:使用事件触发功能

问题描述 投票:0回答:1

我正在我的网站上构建侧车功能,并基于包含购物车项目的本地存储阵列进行实时更新。我正在使用事件来检测更改,但我很难更新小计价格:

YourCart.js:

这是购物车的上部,它检索本地存储物品。每次在本地存储中修改项目时,它都会重新渲染。当它重新渲染时,它还会调度

"updateSubtotal"
事件。

  function YourCart() {

    //state to store the items retrieved from local storage
    const [cartItems, setCartItems] = useState([]);
    //add a trigger state to re-render the cart items
    const [trigger, setTrigger] = useState(false);

    useEffect(() => {
      //retrieve the items from local storage

      const cartItemsFromStorage = JSON.parse(localStorage.getItem(LOCALSTORAGEKEY)) || [];
      setCartItems(cartItemsFromStorage);

      //listens for AddToCart clicks, triggers re-render when clicks happen
      updateCartEvent.addEventListener('updateCart', updateCartlistener);

      //dispatches updateSubtotal every re-render
      updateCartEvent.dispatchEvent('updateSubtotal',  "subtotal update!" )
    }, [trigger]);

    //updateCart callback function
    const updateCartlistener = (event) => {
      //removes old listener before setting a new one (prevents leaks)
      updateCartEvent.removeEventListener('updateCart', updateCartlistener);
      setTrigger(!trigger);
    };

仍然在同一个组件上,我想展示如何触发 useEffect。每个项目操作(添加、减去、删除)都会调用

updateLocalStorage()
,然后更新本地存储并触发组件重新渲染:

  /*function to update local storage with the updated cart items, after that
  trigger the component re-render with setCartItems*/
  const updateLocalStorage = (updatedCartItems) => {

    //updates local storage
    localStorage.setItem(LOCALSTORAGEKEY, JSON.stringify(updatedCartItems));  

    //toggle the trigger state to force a re-render
    setTrigger(!trigger);
  };

  //function to handle the removal of an item
    const remove = (itemId) => {
      removeFromGlobalState(itemId);
      const updatedCartItems = cartItems.filter((item) => item._id !== itemId);

      updateLocalStorage(updatedCartItems);
  };

  //function to handle the subtraction of quantity
  const subtract = (itemId) => {
    const updatedCartItems = cartItems.map((item) => {
      if (item._id === itemId && item.quantity > 1) {
        item.quantity -= 1;
      }
      return item;
    });

    updateLocalStorage(updatedCartItems);
  };

  //function to handle the addition of quantity
  function add(itemId) {
    const updatedCartItems = cartItems.map((item) => {
      if (item._id === itemId) {
        item.quantity += 1;
      }
      return item;
    });

    updateLocalStorage(updatedCartItems);
  };

yourCartActions.js

这是购物车的下半部分,是显示总价的组件。它侦听

updateSubtotal
事件并从我的本地存储代码调用
calculateTotalPrice()
函数:

function YourCartActions(){

  //initialize subtotalPrice with an initial value
  const [subtotalPrice, setSubtotalPrice] = useState(calculateTotalPrice());

  useEffect(() => {
    //update subtotalPrice when the event is triggered
    const handleCartUpdated = () => {
      setSubtotalPrice(calculateTotalPrice());
      console.log("Subtotal Updated!");
    };

    //add an event listener for 'updateSubtotal' event
    updateCartEvent.addEventListener('updateSubtotal', handleCartUpdated);

    //cleanup the event listener when the component unmounts
    return () => {
      updateCartEvent.removeEventListener('updateSubtotal', handleCartUpdated);
    };
  }, []);

问题:

当使用其他

AddToCart
组件添加项目以及使用
remove()
功能删除项目时,小计实际上会实时更新,但当我使用
add()
subtract() 时,小计不会实时更新
功能(仅当我刷新页面时)。

如您所见,我确实为每次调用

console.log("Subtotal Updated!");
时设置了
handleCartUpdated()
,然后我继续多次单击
add()
subtract()
,每次都会打印
Subtotal Updated!
,所以这意味着实际上正在调用更新价格的函数,但正如我所说,它仅在我刷新页面时才实际更新总价。

javascript reactjs local-storage
1个回答
0
投票

您不需要

trigger
状态。您的
useEffect
可以使用
cartItems
数组作为依赖项,并且每当数组更新时它都会更新。

由于每次修改数组时都会触发

useEffect
钩子,因此您可以将更新本地存储的代码放入此钩子中。您可以在这个官方文档中阅读useEffect如何工作

您的购物车

const [cartItems, setCartItems] = useState([]);

// this hook stores into local storage
useEffect(() => {
   localStorage.setItem(LOCALSTORAGEKEY, JSON.stringify(cartItems));
}, [cartItems]);

// this hook is only executed once to update your cart items
useEffect(() => {
   const cartItemsFromStorage = JSON.parse(localStorage.getItem(LOCALSTORAGEKEY)) || [];
}, []);
setCartItems(cartItemsFromStorage);

但是,为了确保触发

useEffect
钩子,您必须像这样更新数组:

function add(itemId) {
   const updatedCartItems = cartItems.map((item) => {
      if(item.id === itemId) {
         return {
            ...item,
            quantity: item.quantity + 1
         }
      }
   });
} 

map
返回一个新数组,因此它将触发您的
useEffect
再次运行。


您不需要使用自定义事件侦听器来处理购物车中的添加/删除/更新事件。请阅读此有关处理事件的 React 文档

为了确保

CartActions
组件正确计算小计,只需将您的
cartItems
传递给它即可。

您的购物车

// ... other code
return (
   <YourCartActions cartItems={cartItems} />
   { /* other jsx elements */ }
)

您的购物车操作

function YourCartActions({ cartItems }) {
   const [subtotal, setSubtotal] = useState(0);
   
   useEffect(() => {
      setSubtotal(calculateTotalPrice()); // or just calculate here
   }, [cartItems])
}
//...other code
© www.soinside.com 2019 - 2024. All rights reserved.