У меня проблема с производительностью. Я не уверен, что это потому, что я использую несколько 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]
}
]
},