Проблема с производительностью - React Hooks useEffect - PullRequest
0 голосов
/ 24 февраля 2020

У меня проблема с производительностью. Я не уверен, что это потому, что я использую несколько useEffect's (что я пытаюсь ограничить их действие, чтобы они наблюдали соответствующее состояние)?

Или, может быть, потому что я использую кучу операторов if? Или все фильтры, которые я выполняю?

Цель состоит в том, чтобы пользователь мог проверять и снимать флажки с различных функций, а итоговая цена рассчитываться. Расчетная цена будет отличаться в зависимости от выбранного варианта (годовой / подписка).

Вы можете увидеть проблему здесь: https://prisma2-frontend-project.now.sh/

Если вы прокрутите вниз до раздела ценообразования, вы увидите, что если вы начнете выбирать и отменять выбор одного или двух флажки это не действительно проблема. Но когда вы начинаете делать больше или переключаетесь на вкладку покупки, все начинает сильно тормозить. Математика даже начинает шататься! хаха

Соответствующий код:

import React, { useState, useEffect, useRef } from "react";
import PropTypes from "prop-types";
import Link from "next/link";
import Box from "reusecore/src/elements/Box";
import Text from "reusecore/src/elements/Text";
import Heading from "reusecore/src/elements/Heading";
import Checkbox from "reusecore/src/elements/Checkbox";
import Button from "reusecore/src/elements/Button";
import Container from "common/src/components/UI/Container";
import GlideCarousel from "common/src/components/GlideCarousel";
import GlideSlide from "common/src/components/GlideCarousel/glideSlide";
import { useToggle } from "reusecore/src/hooks";

import {
  MONTHLY_PRICING_TABLE,
  YEARLY_PRICING_TABLE
} from "common/src/data/SaasClassic";

import PricingTable, {
  PricingHead,
  PricingPrice,
  PricingButton,
  PricingList,
  ListItem,
  PricingButtonWrapper,
  PricingTableWrapper
} from "./pricing.style";

const PricingSection = ({
  sectionWrapper,
  isChecked,
  secTitleWrapper,
  secHeading,
  secText,
  nameStyle,
  descriptionStyle,
  priceStyle,
  priceLabelStyle,
  buttonFillStyle,
  listContentStyle
}) => {
  const [state, setState] = useState({
    data: MONTHLY_PRICING_TABLE,
    active: true
  });

  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const sumSubscriptionBusiness = businessState.subscription.cost.reduce(
      (total, next) => total + Number(next),
      0
    );
    const sumPurchaseBusiness = businessState.purchase.cost.reduce(
      (total, next) => total + Number(next),
      0
    );
    setBusinessTotal({
      purchase: sumPurchaseBusiness,
      subscription: sumSubscriptionBusiness
    });
  }, businessState);

  useEffect(() => {
    const sumSubscriptionInformation = informationState.subscription.cost.reduce(
      (total, next) => total + Number(next),
      0
    );
    const sumPurchaseInformation = informationState.purchase.cost.reduce(
      (total, next) => total + Number(next),
      0
    );
    setInformationTotal({
      purchase: sumPurchaseInformation,
      subscription: sumSubscriptionInformation
    });
  }, informationState);

  useEffect(() => {
    const sumSubscriptionEcommerce = ecommerceState.subscription.cost.reduce(
      (total, next) => total + Number(next),
      0
    );
    const sumPurchaseEcommerce = ecommerceState.purchase.cost.reduce(
      (total, next) => total + Number(next),
      0
    );
    setEcommerceTotal({
      purchase: sumPurchaseEcommerce,
      subscription: sumSubscriptionEcommerce
    });
  }, ecommerceState);

  const [toggleValue, toggleHandler] = useToggle(isChecked);

  const [businessState, setBusinessState] = useState({
    purchase: {
      service: [],
      cost: []
    },
    subscription: {
      service: [],
      cost: []
    }
  });

  const [informationState, setInformationState] = useState({
    purchase: {
      service: [],
      cost: []
    },
    subscription: {
      service: [],
      cost: []
    }
  });
  const [ecommerceState, setEcommerceState] = useState({
    purchase: {
      service: [],
      cost: []
    },
    subscription: {
      service: [],
      cost: []
    }
  });

  const [businessTotal, setBusinessTotal] = useState({
    purchase: [],
    subscription: []
  });
  const [informationTotal, setInformationTotal] = useState({
    purchase: [],
    subscription: []
  });
  const [ecommerceTotal, setEcommerceTotal] = useState({
    purchase: [],
    subscription: []
  });

  const handleChecking = (e, item) => {
    const { name } = e.target;
    const { id } = e.target;
    const newService = item.service;
    const newCost = item.cost;
    const newPCost = item.pcost;

    if (
      name === "business" &&
      businessState.subscription.service[0] !== undefined &&
      !Object.values(businessState.subscription.service).includes(newService)
    ) {
      const oldBusinessPurchaseService = businessState.purchase.service;
      const oldBusinessPurchaseCost = businessState.purchase.cost;
      const oldBusinessSubscriptionService = businessState.subscription.service;
      const oldBusinessSubscriptionCost = businessState.subscription.cost;
      setBusinessState({
        purchase: {
          service: [...oldBusinessPurchaseService, newService],
          cost: [...oldBusinessPurchaseCost, newPCost]
        },
        subscription: {
          service: [...oldBusinessSubscriptionService, newService],
          cost: [...oldBusinessSubscriptionCost, newCost]
        }
      });
    }
    if (
      name === "business" &&
      businessState.subscription.service[0] !== undefined &&
      Object.values(businessState.subscription.service).includes(newService)
    ) {
      const removeBusinessIndex = businessState.subscription.service.indexOf(
        newService
      );
      const reducedBusinessSubscriptionService = businessState.subscription.service.filter(
        (s, i) => i !== removeBusinessIndex
      );
      const reducedBusinessSubscriptionCost = businessState.subscription.cost.filter(
        (s, i) => i !== removeBusinessIndex
      );
      const reducedBusinessPurchaseService = businessState.purchase.service.filter(
        (s, i) => i !== removeBusinessIndex
      );
      const reducedBusinessPurchaseCost = businessState.purchase.cost.filter(
        (s, i) => i !== removeBusinessIndex
      );
      setBusinessState({
        purchase: {
          service: [...reducedBusinessPurchaseService],
          cost: [...reducedBusinessPurchaseCost]
        },
        subscription: {
          service: [...reducedBusinessSubscriptionService],
          cost: [...reducedBusinessSubscriptionCost]
        }
      });
    }
    if (
      name === "business" &&
      businessState.subscription.service[0] === undefined
    ) {
      setBusinessState({
        purchase: {
          service: [newService],
          cost: [newPCost]
        },
        subscription: {
          service: [newService],
          cost: [newCost]
        }
      });
    }
    if (
      name === "information" &&
      informationState.subscription.service[0] !== undefined &&
      !Object.values(informationState.subscription.service).includes(newService)
    ) {
      const oldInformationPurchaseService = informationState.purchase.service;
      const oldInformationPurchaseCost = informationState.purchase.cost;
      const oldInformationSubscriptionService =
        informationState.subscription.service;
      const oldInformationSubscriptionCost = informationState.subscription.cost;
      setInformationState({
        purchase: {
          service: [...oldInformationPurchaseService, newService],
          cost: [...oldInformationPurchaseCost, newPCost]
        },
        subscription: {
          service: [...oldInformationSubscriptionService, newService],
          cost: [...oldInformationSubscriptionCost, newCost]
        }
      });
    }
    if (
      name === "information" &&
      informationState.subscription.service[0] !== undefined &&
      Object.values(informationState.subscription.service).includes(newService)
    ) {
      const removeInformationIndex = informationState.subscription.service.indexOf(
        newService
      );
      const reducedInformationSubscriptionService = informationState.subscription.service.filter(
        (s, i) => i !== removeInformationIndex
      );
      const reducedInformationSubscriptionCost = informationState.subscription.cost.filter(
        (s, i) => i !== removeInformationIndex
      );
      const reducedInformationPurchaseService = informationState.purchase.service.filter(
        (s, i) => i !== removeInformationIndex
      );
      const reducedInformationPurchaseCost = informationState.purchase.cost.filter(
        (s, i) => i !== removeInformationIndex
      );
      setInformationState({
        purchase: {
          service: [...reducedInformationPurchaseService],
          cost: [...reducedInformationPurchaseCost]
        },
        subscription: {
          service: [...reducedInformationSubscriptionService],
          cost: [...reducedInformationSubscriptionCost]
        }
      });
    }
    if (
      name === "information" &&
      informationState.subscription.service[0] === undefined
    ) {
      setInformationState({
        purchase: {
          service: [newService],
          cost: [newPCost]
        },
        subscription: {
          service: [newService],
          cost: [newCost]
        }
      });
    }
    if (
      name === "ecommerce" &&
      ecommerceState.subscription.service[0] !== undefined &&
      !Object.values(ecommerceState.subscription.service).includes(newService)
    ) {
      const oldEcommercePurchaseService = ecommerceState.purchase.service;
      const oldEcommercePurchaseCost = ecommerceState.purchase.cost;
      const oldEcommerceSubscriptionService =
        ecommerceState.subscription.service;
      const oldEcommerceSubscriptionCost = ecommerceState.subscription.cost;
      setEcommerceState({
        purchase: {
          service: [...oldEcommercePurchaseService, newService],
          cost: [...oldEcommercePurchaseCost, newPCost]
        },
        subscription: {
          service: [...oldEcommerceSubscriptionService, newService],
          cost: [...oldEcommerceSubscriptionCost, newCost]
        }
      });
    }
    if (
      name === "ecommerce" &&
      ecommerceState.subscription.service[0] !== undefined &&
      Object.values(ecommerceState.subscription.service).includes(newService)
    ) {
      const removeEcommerceIndex = ecommerceState.subscription.service.indexOf(
        newService
      );
      const reducedEcommerceSubscriptionService = ecommerceState.subscription.service.filter(
        (s, i) => i !== removeEcommerceIndex
      );
      const reducedEcommerceSubscriptionCost = ecommerceState.subscription.cost.filter(
        (s, i) => i !== removeEcommerceIndex
      );
      const reducedEcommercePurchaseService = ecommerceState.purchase.service.filter(
        (s, i) => i !== removeEcommerceIndex
      );
      const reducedEcommercePurchaseCost = ecommerceState.purchase.cost.filter(
        (s, i) => i !== removeEcommerceIndex
      );
      setEcommerceState({
        purchase: {
          service: [...reducedEcommercePurchaseService],
          cost: [...reducedEcommercePurchaseCost]
        },
        subscription: {
          service: [...reducedEcommerceSubscriptionService],
          cost: [...reducedEcommerceSubscriptionCost]
        }
      });
    }
    if (
      name === "ecommerce" &&
      ecommerceState.subscription.service[0] === undefined
    ) {
      setEcommerceState({
        purchase: {
          service: [newService],
          cost: [newPCost]
        },
        subscription: {
          service: [newService],
          cost: [newCost]
        }
      });
    }
  };

  const data = state.data;
  const activeStatus = state.active;

  const pricingCarouselOptions = {
    type: "slider",
    perView: 3,
    gap: 30,
    bound: true,
    breakpoints: {
      1199: {
        perView: 2,
        type: "carousel",
        peek: {
          before: 100,
          after: 100
        }
      },
      990: {
        type: "carousel",
        perView: 1,
        peek: {
          before: 160,
          after: 160
        }
      },
      767: {
        type: "carousel",
        perView: 1,
        peek: {
          before: 80,
          after: 80
        }
      },
      575: {
        type: "carousel",
        perView: 1,
        gap: 15,
        peek: {
          before: 20,
          after: 20
        }
      }
    }
  };

  return (
    <Box {...sectionWrapper} id="pricing_section">
      <Container>
        <Box {...secTitleWrapper}>
          <Text {...secText} content="PRICING PLAN" />
          <Heading
            {...secHeading}
            content="Customize your website according to your needs"
          />
          <PricingButtonWrapper>
            <Button
              title="Monthly Subscription Pricing"
              className={activeStatus ? "active-item" : ""}
              onClick={() =>
                setState({ data: MONTHLY_PRICING_TABLE, active: true })
              }
            />
            <Button
              title="One-Time Purchase Pricing"
              className={activeStatus === false ? "active-item" : ""}
              onClick={() =>
                setState({ data: YEARLY_PRICING_TABLE, active: false })
              }
            />
            <Link href="#">
              <a>+ Custom Plan</a>
            </Link>
          </PricingButtonWrapper>
        </Box>
        <PricingTableWrapper>
          <GlideCarousel
            carouselSelector="pricing-carousel"
            options={pricingCarouselOptions}
            controls={false}
          >
            <>
              {data.map((pricingTable, index) => (
                <GlideSlide key={`pricing-table-${index}`}>
                  <PricingTable
                    freePlan={pricingTable.freePlan}
                    className="pricing_table"
                  >
                    <PricingHead>
                      <Heading content={pricingTable.name} {...nameStyle} />
                      <Text
                        content={pricingTable.description}
                        {...descriptionStyle}
                      />
                    </PricingHead>
                    <PricingPrice>
                      {pricingTable.name === "Informational Website" &&
                      pricingTable.type === "subscription" ? (
                        <Text
                          content={`$${informationTotal.subscription}`}
                          {...priceStyle}
                        />
                      ) : pricingTable.name === "Informational Website" &&
                        pricingTable.type === "purchase" ? (
                        <Text
                          content={`$${informationTotal.purchase}`}
                          {...priceStyle}
                        />
                      ) : pricingTable.name === "Business Website" &&
                        pricingTable.type === "subscription" ? (
                        <Text
                          content={`$${businessTotal.subscription}`}
                          {...priceStyle}
                        />
                      ) : pricingTable.name === "Business Website" &&
                        pricingTable.type === "purchase" ? (
                        <Text
                          content={`$${businessTotal.purchase}`}
                          {...priceStyle}
                        />
                      ) : pricingTable.category === "ecommerce" &&
                        pricingTable.type === "subscription" ? (
                        <Text
                          content={`$${ecommerceTotal.subscription}`}
                          {...priceStyle}
                        />
                      ) : pricingTable.category === "ecommerce" &&
                        pricingTable.type === "purchase" ? (
                        <Text
                          content={`$${ecommerceTotal.purchase}`}
                          {...priceStyle}
                        />
                      ) : (
                        <Text content="error" {...priceStyle} />
                      )}
                      <Text
                        content={pricingTable.priceLabel}
                        {...priceLabelStyle}
                      />
                    </PricingPrice>
                    <PricingList>
                      {pricingTable.listItems.map((item, index) => (
                        <ListItem key={`pricing-table-list-${index}`}>
                          <Checkbox
                            name={`${pricingTable.category}`}
                            id={`${pricingTable.type}`}
                            labelText={item.service}
                            checked={toggleValue}
                            value={item}
                            onChange={e => {
                              toggleHandler;
                              handleChecking(e, item);
                            }}
                            // onChange={e => {
                            //   toggleHandler;
                            //   handleChecking(e);
                            // }}
                          />
                          {/* <Text content={item.content} {...listContentStyle} /> */}
                          {pricingTable.type === "subscription" ? (
                            <Text
                              content={`$${item.cost}`}
                              {...listContentStyle}
                            />
                          ) : (
                            <Text
                              content={`$${item.pcost}`}
                              {...listContentStyle}
                            />
                          )}
                        </ListItem>
                      ))}
                    </PricingList>
                    <PricingButton>
                      <Link href={pricingTable.url}>
                        <a>
                          <Button
                            title={pricingTable.buttonLabel}
                            {...buttonFillStyle}
                          />
                        </a>
                      </Link>
                      {pricingTable.trialButtonLabel ? (
                        <Link href={pricingTable.trialURL || "#"}>
                          <a className="trial_button">
                            {pricingTable.trialButtonLabel}
                          </a>
                        </Link>
                      ) : (
                        ""
                      )}
                    </PricingButton>
                  </PricingTable>
                </GlideSlide>
              ))}
            </>
          </GlideCarousel>
        </PricingTableWrapper>
      </Container>
    </Box>
  );
};

export default PricingSection;

Пример данных:

 {
    name: "Informational Website",
    category: "information",
    type: "subscription",
    description:
      " Beautiful landing page for small businesses or personal portfolios",
    price: "$0",
    priceLabel: "Per month",
    buttonLabel: "Start for free",
    url: "#",
    listItems: [
      {
        service: ["Mobile-ready, Responsive Design"],
        cost: [6],
        pcost: [600]
      },
      {
        service: ["Blog Articles"],
        cost: [14],
        pcost: [1300]
      },
      {
        service: ["Collect visitor information (email / phone)"],
        cost: [10],
        pcost: [1000]
      },
      {
        service: ["eCommerce Store "],
        cost: [25],
        pcost: [3200]
      },
      {
        service: ["30+ Webmaster Tools"],
        cost: [2],
        pcost: [500]
      }
    ]
  },
...