Почему react загружает изображения много раз? возможно ли сохранить первую загрузку?

#javascript #reactjs #image #api #react-redux

#javascript #reactjs #изображение #API #реагировать-redux

Вопрос:

чтобы понаблюдать за проблемой, вы можете вивсить тестовый сайт http://u100525.test-handyhost.ru/products

проблема возникает, если нажимать много раз на элементы категории, изображения продуктов начинают давать сбои, потому что react загружает изображение одного элемента снова и снова, при каждом изменении категории — в каждом фильтре продуктов, так как сделать одну загрузку и сохранить каким-то образом загруженные изображения?

итак, если я нажимаю на категории, мой код фильтрует массив продуктов и оператор обновления — visibleProducts, тогда я делаю visibleProducts.map((product)=>{});

и я получаю проблему с ошибкой, потому что каждый раз, когда react рендерит мой компонент, он запрашивает сервер для получения изображения по идентификатору и ждет, пока изображение загрузится, но если я нажимаю на другую категорию, react (ProductItem) запускает другой запрос на новые изображения, тогда они начинают давать ошибку мигает и меняется; c

я новичок в react и просто заявил, чтобы практиковать то, что я должен делать, ребята?

правильный ли мой код?

вот мой компонент ProductItem ->

 import React, { useState, useEffect, memo, useCallback } from "react";
import { Link } from "react-router-dom";
import { connect } from "react-redux";
import { setModalShow, onQuickViewed, addedToCart } from "../../actions";

import Checked from "../checked";

import "./product-item.css";
import Spinner from "../spinner";

const ProductItem = ({
  product,
  wpApi,
  addedToCart,
  onQuickViewed,
  setModalShow,
}) => {
  const [prodImg, setProdImg] = useState("");
  const [animated, setAnimated] = useState(false);
  const [checked, setChecked] = useState(false);
  const [itemLoading, setItemLoading] = useState(true);

  const checkedFn = useCallback(() => {
    setChecked(true);
    setTimeout(() => {
      setChecked(false);
    }, 800);
  },[product]);

  const onModalOpen = useCallback((e, id) => {
    onQuickViewed(e, id);
    setModalShow(true);
  }, product);

  const addHandle = useCallback((e, id) => {
    e.preventDefault();
    addedToCart(id);
    checkedFn();
  },[product]);

  useEffect(()=>{
    setItemLoading(false);
  }, [prodImg]);

  useEffect(() => {
    wpApi.getImageUrl(product.imageId).then((res) => {
      setProdImg(res);
    });
  });

  return (
    <div className="product foo">
      <div
        className='product__inner'}
      >
        {!itemLoading?         <div
          className="pro__thumb"
          style={{
            backgroundImage:prodImg
              ? `url(${prodImg})`
              : "assets/images/product/6.png",
          }}
        >
          <Link
            to={`/product-details/${product.id}`}
            style={{ display: `block`, width: `100%`, paddingBottom: `100%` }}
          >

          </Link>
        </div>: <Spinner/>}


        <div className="product__hover__info">
          <ul className="product__action">
            <li>
              <a
                onClick={(e) => {
                  onModalOpen(e, product.id);
                }}
                title="Quick View"
                className="quick-view modal-view detail-link"
                href="#"
              >
                <span ><i class="zmdi zmdi-eye"></i></span>
              </a>
            </li>
            <li>
              <a
                title="Add TO Cart"
                href="#"
                onClick={(e) => {
                  addHandle(e, product.id);
                }}
              >
                {checked ? (
                  <Checked />
                ) : (
                  <span className="ti-shopping-cart"></span>
                )}
              </a>
            </li>
          </ul>
        </div>
      </div>
      <div className="product__details">
        <h2>
          <Link to={`/product-details/${product.id}`}>{product.title}</Link>
        </h2>
        <ul className="product__price">
          <li className="old__price">${product.price}</li>
        </ul>
      </div>
    </div>
  );
};

const mapStateToProps = ({ options, cart, total, showModal }) => {
  return {};
};

const mapDispatchToProps = {
  onQuickViewed,
  setModalShow,
  addedToCart,
};

export default connect(mapStateToProps, mapDispatchToProps)(memo(ProductItem));
 

вот мои родительские компоненты Products ->

 import React, { useEffect, useState } from "react";
import { connect } from "react-redux";
import ProductItem from "../product-item";
import { withWpApiService } from "../hoc";
import { onQuickViewed, addedToCart, categoriesLoaded } from "../../actions";
import CategoryFilter from "../category-filter";
import Spinner from "../spinner";

import "./products.css";

const Products = ({
  maxProducts,
  WpApiService,
  categoriesLoaded,
  addedToCart,
  onQuickViewed,
  products,
  categories,
  loading,
}) => {
  const [activeIndex, setActiveIndex] = useState(0);
  const [activeCategory, setActiveCategory] = useState(0);
  const [visibleProducts, setVisibleProducts] = useState([]);

  const wpApi = new WpApiService();

  useEffect(() => {
    updateVisibleProducts(activeCategory, products);
  }, [products]);

  useEffect(() => {
    wpApi.getCategories().then((res) => {
      categoriesLoaded(res);
    });
  }, []);

  const getCatId = (cat) => {
    setActiveCategory(cat);
    updateVisibleProducts(cat, products);
    setActiveIndex(cat);
  };

  const updateVisibleProducts = (category, products) => {
    let updatedProducts = [];
    switch (category) {
      case 0:
        updatedProducts = products;

        setVisibleProducts(updatedProducts);

        break;
      default:
        updatedProducts = products.filter(
          (product) => product.categories.indexOf(category) >= 0
        );

        setVisibleProducts(updatedProducts);
    }
  };

  let currentLocation = window.location.href.split("/");

  if (!loading) {
    return (
      <section className="htc__product__area shop__page mb--60 mt--130 bg__white">
        <div className={currentLocation[3] == "" ? `container` : ""}>
          <div className="htc__product__container">
            <CategoryFilter
              activeIndex={activeIndex}
              categories={categories}
              getCatId={getCatId}
            />

            <div
              className="product__list another-product-style"
              style={{ height: "auto" }}
            >
              {visibleProducts
                .slice(0, maxProducts ? maxProducts : products.length)
                .map((prod, id) => {
                  return (
                    <ProductItem
                      wpApi={wpApi}
                      key={id}
                      onQuickViewed={onQuickViewed}
                      addedToCart={addedToCart}
                      product={prod}
                    />
                  );
                })}
            </div>
          </div>
        </div>
      </section>
    );
  } else {
    return <Spinner />;
  }
};

const mapStateToProps = ({ products, loading, activeCategory, categories }) => {
  return {
    products,
    activeCategory,
    categories,
    loading,
  };
};

const mapDispatchToProps = {
  addedToCart,
  categoriesLoaded,
  onQuickViewed,
};

export default withWpApiService()(
  connect(mapStateToProps, mapDispatchToProps)(Products)
);
 

и если вам нужно, вот мой компонент CategoryFilter ->

 import React from 'react'

const CategoryFilter = ({categories, getCatId, activeIndex}) => {
    return (
        <div className="row mb--60">
        <div className="col-md-12">
          <div className="filter__menu__container">
            <div className="product__menu">
              {categories.map((cat) => {
                return (
                  <button key={cat.id}
                   className={activeIndex === cat.id? 'is-checked' : null}
                    onClick={() => getCatId(cat.id)}
                    data-filter=".cat--4"
                  >
                    {cat.name}
                  </button>
                );
              })}
            </div>
          </div>
        </div>
      </div>
    )
}

export default CategoryFilter