首页 > 解决方案 > 子组件在本地存储被清除之前重新渲染

问题描述

我有一个小型餐厅应用程序,它呈现菜单并让用户下订单。父组件接收菜单项数组并为每个项呈现一个子组件。每个项目的数量在子组件('menu-item')中初始化,并且还保存在本地存储中,因此如果用户刷新页面,订单仍然存在。提交订单后,父组件会清除本地存储,但子组件不会获取此更改。因此,即使在订单提交后,用户也能看到订单数量。我希望在提交订单后将订单数量重置为 0。下面是精简的代码库。

//父母

const TotalStore = {
  total: 0,
  reset_timer: setTimeout(() => {}, 0),
  compute() {
    let newTotal = 0;
    let types = new Map<string, boolean>();
    TotalStore.items.forEach((value: TotalStoreMenuItem) => {
      newTotal += value.price * value.count;
      types.set(value.type, true);
    });

    if (TotalStore.total !== newTotal) {
      clearTimeout(TotalStore.reset_timer);
      TotalStore.reset_timer = setTimeout(() => {
        TotalStore.total = newTotal;
        TotalStore.onChange(newTotal);
      }, 50);
    }
  },
  update(id: number, price: number, count: number, type: string) {
    TotalStore.items.set(id, {
      id,
      price,
      count,
      type,
    });
    TotalStore.compute();
  },
  reset() {
    TotalStore.items.clear();
    localStorage.clear();
    TotalStore.total = 0;
  },
  onChange(t: number) {},
  items: new Map<number, TotalStoreMenuItem>(),
};
const itemChanged = (
    id: number,
    price: number,
    count: number,
    type: string
  ) => {
    TotalStore.update(id, price, count, type);
  };
useEffect(() => {
    apiFetch("menu").then((json) => setMenu(json.menu));
  }, []);
async function handleSubmit(e: any) {
    e.preventDefault();
    const selectedItems = getSelectedItems(TotalStore);
    apiFetch("order", "post", { selectedItems })
      .then((json) => {
        alert("Order has been submitted");
        TotalStore.reset();
}
return (
    <div>
      {menu.length > 0 ? (
        <>
          <div className="menu">
            <div className="menu-title">Food Menu</div>
            <form id="menu-form" onSubmit={handleSubmit} autoComplete="off">
              <Menu onChange={itemChanged} props={menu} />
              <button type="submit" disabled={!orderPlaced(total)}>
                Place Order
              </button>
            </form>
          </div>
          <div className="order-total">
            <h2>
              Total: $<span>{total.toFixed(2)}</span>
            </h2>
          </div>
        </>
      ) : (
        <>Loading Menu</>
      )}
    </div>
  );

//菜单

export default function Menu({ onChange, props }: MenuProps) {
  return (
    <div>
      {props.map((food: any, index: number) => {
        return (
          <MenuItem
            key={index}
            onChange={onChange}
            type={food.type}
            item={food}
          />
        );
      })}
    </div>
  );
}

//菜单项

const FoodItemLocalStore = {
  setCount(id: Number, count: Number) {
    localStorage.setItem(`menu_item_id_${id}`, String(count));
  },
  getCount(id: Number) {
    return parseInt(localStorage.getItem(`menu_item_id_${id}`) || "0");
  },
};

export default function MenuItem({ onChange, item, type }: MenuItemProps) {
  const [data, setData] = useState({
    count: FoodItemLocalStore.getCount(item.id),
  });

  const menuItemCountChange = (e: any) => {
    data.count = parseInt(e.target.value);
    FoodItemLocalStore.setCount(item.id, data.count);
    setData({ ...data });
  };

  onChange(item.id, item.price, data.count, type);

  return (
    <div>
      <article className="menu-item" data-item-type={type}>
        <h3 className="item-name">{item.name}</h3>
        <input
          type="number"
          className="menu-item-count"
          min="0"
          value={data.count}
          onChange={menuItemCountChange}
        />
        <strong className="item-price">${item.price.toFixed(2)}</strong>
      </article>
    </div>
  );
}

标签: javascriptnode.jsreactjs

解决方案


推荐阅读