【问题标题】:React helpers to react componentsReact 助手以响应组件
【发布时间】:2021-10-02 04:24:05
【问题描述】:

我创建了一个辅助函数来重用。 在我的第一个组件上,辅助函数运行良好。 但是当我在其他组件上使用它时。它有一个错误,当我将产品添加到收藏夹时,它会添加到收藏夹中,但是当我单击其他产品时,它会覆盖以前添加的收藏夹。

我的助手

function getFromLocalStorage(key) {
  return JSON.parse(localStorage.getItem(key))
}

export function setToLocalStorage(key, data) {
  return localStorage.setItem(key, JSON.stringify(data))
}

export const favoriteProductsStorageKey = "favorites_products"

export function getAllFavoriteProducts() {
  return getFromLocalStorage(favoriteProductsStorageKey) || []
}

export function createFavoriteHelpers(favorites, setFavorites) {

  function addFavorite(product) {
    const isProductAlreadyFavorite = isProductInFavorites(product);

    if (isProductAlreadyFavorite) return;

    const newFavoriteProducts = [...favorites, product];

    setFavorites(newFavoriteProducts);
    setToLocalStorage(favoriteProductsStorageKey, newFavoriteProducts);
  }

  function removeFavorite(product) {
    const newFavoriteProducts = favorites.filter(
      (iteratedProduct) => iteratedProduct._id !== product._id
    );

    setFavorites(newFavoriteProducts);
    setToLocalStorage(favoriteProductsStorageKey, newFavoriteProducts);
  }

  function isProductInFavorites(product) {
    return favorites.some(
        (iteratedProduct) => iteratedProduct._id === product._id
    );
  }

  return {
    addFavorite,
      removeFavorite,
      isProductInFavorites,
  };
}

我的第一个组件运行良好。

const ProductList = ({ products }) => {
  const classes = useStyles()

  const [favorites, setFavorites] = useState(getAllFavoriteProducts())
  const favoriteHelpers = createFavoriteHelpers(favorites, setFavorites)

  return (
    <>
      <div className={classes.root}>
        {products?.map((product) => {
          return (
            <div className="ProductCard" key={product._id}>
              <div>
                <Link to="/shop" state={{ shop: product.shop }}>
                  <img
                    className="ProductImage"
                    src={product.imagePrimary}
                    alt={product.name}
                  />
                </Link>
                <div className="FavButton">
                  {favoriteHelpers.isProductInFavorites(product) ? (
                    <FavoriteIcon
                      fontSize="small"
                      style={{ fill: "red" }}
                      onClick={() => favoriteHelpers.removeFavorite(product)}
                    />
                  ) : (
                    <FavoriteIcon
                      fontSize="small"
                      style={{ fill: "gray" }}
                      onClick={() => favoriteHelpers.addFavorite(product)}
                    />
                  )}
                </div>
              </div>
              <div className="ProductCardDetails">
                <div className="NameAndPrice">
                  <div className="ProductName">{product.name}</div>
                  <div className="ProductPrice">P{product.price}</div>
                </div>
                <div className="Description"> by {product.shop.name}</div>
              </div>
            </div>
          )
        })}
      </div>
    </>
  )
}

export default ProductList

在添加和删除时出现错误的那个。

const ProductCard = ({ data }) => {

  const [favorites, setFavorites] = useState(getAllFavoriteProducts())
  const favoriteHelpers = createFavoriteHelpers(favorites, setFavorites)

  return (
    <div className="ProductCard">
      <div>
        <Link to="/product" state={{ product: data }}>
          <img
            className="ProductImage"
            src={data.imagePrimary}
            alt={data.name}
          />
        </Link>
        <div
          aria-hidden="true"
          className="AddButton"
          onClick={() => {
            addToBag(data)
            // useAddToBag(data)
          }}
          onKeyDown={() => {
            addToBag(data)
          }}
        >
          <AddIcon fontSize="small" />
        </div>
        <div className="FavButton">
          {favoriteHelpers.isProductInFavorites(product) ? (
            <FavoriteIcon
              fontSize="small"
              style={{ fill: "red" }}
              onClick={() => favoriteHelpers.removeFavorite(product)}
            />
          ) : (
            <FavoriteIcon
              fontSize="small"
              style={{ fill: "gray" }}
              onClick={() => favoriteHelpers.addFavorite(product)}
            />
          )}
        </div>
      </div>
      <div className="ProductCardDetails">
        <div className="NameAndPrice">
          <div className="ProductName">{data.name}</div>
          <div className="ProductPrice">P{data.price}</div>
        </div>
        <div className="Description"> {data.description}</div>
      </div>
      <AddToBagDialog
        showDialog={dialogState.showDialog}
        message={dialogState.dialogMessage}
        onGotoBag={() => {
          setDialogState((prevState) => ({
            ...prevState,
            showDialog: false,
          }))
          navigate("/bagpage")
        }}
        onAddMoreProducts={() => {
          setDialogState((prevState) => ({
            ...prevState,
            showDialog: false,
          }))
        }}
      />
      <ConfirmationDialog
        showDialog={confirmDialogState.showDialog}
        message={confirmDialogState.dialogMessage}
        onConfirm={() => {
          updateBag([])
          updateBag((prevState) => [...prevState, product])
          setConfirmDialogState((prevState) => ({
            ...prevState,
            showDialog: false,
          }))
          setDialogState((prevState) => ({
            ...prevState,
            showDialog: true,
            dialogMessage: "Product added to bag",
            isError: false,
          }))
        }}
        onDecline={() => {
          setConfirmDialogState((prevState) => ({
            ...prevState,
            showDialog: false,
          }))
        }}
      />
    </div>
  )
}

export default ProductCard

使用本地存储时,ProductList 在添加和删除收藏夹时工作正常,但在 ProductCard 上,它正在替换之前添加收藏夹时添加的那些。

这里example

【问题讨论】:

    标签: reactjs react-hooks local-storage


    【解决方案1】:

    每个组件都用getAllFavoriteProducts() 初始化[favorites, setFavorites],但它们从那里分开生活。

    因此,当您在第一个组件内更新收藏夹时,第二个组件内的状态不会更新,而当您从第二个组件内更新时,它将覆盖 localStorage 内的收藏夹。

    如果您需要两个组件共享相同的状态,您需要在first common ancestor 上提升状态。

    另一种解决方案是使用Context API 在两个组件之间共享状态。

    根据问题作者的要求,这里是一个草稿,目的是展示如何解决问题的一些示例。

    首先,您需要创建(或编辑)两个组件的公共父级。由于我不知道您的代码,因此我将发布一个基本组件,只是为了向您展示如何做。

    const Container = () => {
      const [favorites, setFavorites] = useState(getAllFavoriteProducts())
    
      return <div>
        <ProductList products={products} favorites={favorites} setFavorites={setFavorites} />
        <ProductCard data={data} favorites={favorites} setFavorites={setFavorites} />
      </div>
    }
    

    以这种方式,favorites 最初是从localStorage 中读取的,并且保留在Container 内,并与setFavorites 方法一起传递给ProductListProductCard,以便编辑@每个子组件内部的 987654334@ 状态。

    那么你需要通过以下方式编辑每个组件:

    const ProductList = ({ products, favorites, setFavorites }) => {
      // const [favorites, setFavorites] = useState(getAllFavoriteProducts()) ---> comment or delete this
    
      // ...rest of your code
    }
    const ProductCard = ({ data, favorites, setFavorites }) => {
      // const [favorites, setFavorites] = useState(getAllFavoriteProducts()) ---> comment or delete this
    
      // ...rest of your code
    }
    

    通过这些更改,您应该可以使其正常工作,但由于我没有您项目的代码,我无法确定。无论如何,我确信有了这些技巧,您将能够做任何您需要的事情。

    【讨论】:

    • 你好,你能举个例子吗? @Marco Nisi
    • @PinkyPromise 我发布了一些示例,如果对您有帮助,请告诉我。
    • 你好,如果他们没有父组件怎么办? @Marco Nisi
    • @PinkyPromise 如果组件是类似的,那么您可以为此创建一个父组件,它只包含favorites 状态管理的逻辑,就像在示例中一样。
    • 您好,我上传了一个沙箱供您查看真实输出。在 ProductList 的本地存储中,添加和删除收藏夹时效果很好。但在 ProductCard 上,它正在替换添加收藏夹时添加的那些。 codesandbox.io/s/empty-river-jm94p?file=/src/components/…@Marco Nisi
    【解决方案2】:

    为了部分解决您的问题,您需要在使用getAllFavoriteProducts() 填充初始组件的状态时提供localStorage 的密钥,其中保存了您最喜欢的产品。因为,目前您在没有任何键的情况下调用它,所以它总是会返回一个空数组,而不是从 localStorage 检索保存的收藏产品。

    因此,在两个组件中将 const [favorites, setFavorites] = useState(getAllFavoriteProducts()) 替换为 const [favorites, setFavorites] = useState(getAllFavoriteProducts(favoriteProductsStorageKey))

    但是,如果您的组件有机会同时处于挂载状态,那么在一个组件中添加收藏的产品不会影响其他组件状态中的收藏产品,因为它们都有独立的本地状态。要将一个组件所做的更改同步到另一个组件,您需要在它们之间拥有某种共享状态。为此,您可以使用像 reduxmobx 这样的全局状态库,或者将收藏夹的状态保留在顶级父组件中,并将此状态作为道具传递给您提到的两个组件。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-06
      • 2015-12-01
      • 2015-01-29
      • 2019-06-01
      • 1970-01-01
      相关资源
      最近更新 更多