React项目计算保单最大折扣百分比报错#301求修复方案
React组件获取最大折扣百分比报错的修复思路
错误信息
react-dom.production.min.js:5309 Error: Minified React error #301; visit https://reactjs.org/docs/error-decoder.html?invariant=301 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at ta (react-dom.production.min.js:3855:1) at zu (react-dom.production.min.js:6955:1) at Oc (react-dom.production.min.js:6411:1) at bc (react-dom.production.min.js:6400:1) at yc (react-dom.production.min.js:6382:1) at lc (react-dom.production.min.js:6103:4) at react-dom.production.min.js:2898:1 at t.unstable_runWithPriority (scheduler.production.min.js:289:1) at Uo (react-dom.production.min.js:2868:1) at Wo (react-dom.production.min.js:2893:1) overrideMethod @ console.js:213 ou @ react-dom.production.min.js:5309 n.callback @ react-dom.production.min.js:5329 sit @ react-dom.production.min.js:3182 fu @ react-dom.production.min.js:5463 (anonymous) @ react-dom.production.min.js:6687 t.unstable_runWithPriority @ scheduler.production.min.js:289 Uo @ react-dom.production.min.js:2868 Sc @ react-dom.production.min.js:6470 lc @ react-dom.production.min.js:6109 (anonymous) @ react-dom.production.min.js:2898 t.unstable_runWithPriority @ scheduler.production.min.js:289 Uo @ react-dom.production.min.js:2868 Wo @ react-dom.production.min.js:2893 Vo @ react-dom.production.min.js:2883 fc @ react-dom.production.min.js:6134 notify @ Subscription.js:23 t.notifyNestedSubs @ Subscription.js:63 t.handleChangeWrapper @ Subscription.js:68 g @ redux.js:220 (anonymous) @ index.js:11 dispatch @ redux.js:638 (anonymous) @ insuranceReducer.ts:146 l @ runtime.js:64 (anonymous) @ runtime.js:281 (anonymous) @ runtime.js:117 r @ asyncToGenerator.js:3 u @ asyncToGenerator.js:25 Show 1 more frame Show less react-dom.production.min.js:3855 Uncaught (in promise) Error: Minified React error #301; visit https://reactjs.org/docs/error-decoder.html?invariant=301 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at ta (react-dom.production.min.js:3855:1) at zu (react-dom.production.min.js:6955:1) at Oc (react-dom.production.min.js:6411:1) at bc (react-dom.production.min.js:6400:1) at yc (react-dom.production.min.js:6382:1) at lc (react-dom.production.min.js:6103:4) at react-dom.production.min.js:2898:1 at t.unstable_runWithPriority (scheduler.production.min.js:289:1) at Uo (react-dom.production.min.js:2868:1) at Wo (react-dom.production.min.js:2893:1)
问题代码片段
const [maxPercentage, setMaxPercentage] = useState([] as any); data.map((d) => setMaxPercentage(getDiscountPercentage(d.amount,d.discountedAmount).toFixed(0))) <div>Знижка {Math.max(...maxPercentage)}%</div>
完整Policy组件代码
import React, { useState } from "react"; import { ICompanyInsurance } from "../../typings/IDataOffers"; import { useDispatch, useSelector } from "react-redux"; import { getSelectedAmountItem, getDiscountPercentage, getCashBack } from "../../redux-data/insurance/insuranceSelector"; import { setIdPolicy } from "../../redux-data/insurance/insuranceReducer"; import { companyImage, companyImages } from "../../constants/companyImages"; //import im from '../../assets/img/providna.webp'; interface IPolicy extends ICompanyInsurance { formId?: string; index?: number; onBuy?: Function; onPay?: Function; } const Policy = ({ name, data, formId, id, onBuy, onPay, contractorId, companyId }: IPolicy) => { const getDiscountPercentage = (payment, discountedPayment) => { return ((payment - discountedPayment) / payment) * 100; }; const dispatch = useDispatch() const min = Math.min(...data.map((d) => d.amount)); const max = Math.max(...data.map((d) => d.amount)); const minDiscount = Math.min(...data.map((d) => d.discountedAmount)); const maxDiscount = Math.max(...data.map((d) => d.discountedAmount)); const policy = useSelector(getSelectedAmountItem); const price = policy ? policy.amount : min !== max ? `${min.toFixed(2)} - ${max.toFixed(2)}` : min.toFixed(2); const discountedPrice = policy ? policy.discountedAmount : minDiscount !== maxDiscount ? `${minDiscount.toFixed(2)} - ${maxDiscount.toFixed(2)}` : minDiscount.toFixed(2); const [maxPercentage, setMaxPercentage] = useState([] as any); data.map((d) => setMaxPercentage(getDiscountPercentage(d.amount, d.discountedAmount).toFixed(0))); const cashBackPercentage = 10; const greenCardCashBack = getCashBack(price, cashBackPercentage); const handleClick = () => { if (onPay) { onPay(); } else if (onBuy) { dispatch(setIdPolicy(contractorId)) onBuy(id); } }; const img = companyImages.find((company: companyImage) => company.id === companyId) return ( <div className="search-result_one"> <figure className="search-result_pic"> <img src={img ? require(`../../assets/img/logos/${img.key}`) : "\img\base.webp"} alt="" /> </figure> <article className="search-result_info"> <h4>{name}</h4> {min > minDiscount || max > maxDiscount ? <div className="search-result_price"> <div className="old-price">{price} ₴</div> <div>Знижка {Math.max(...maxPercentage)}%</div> <div>До сплати {discountedPrice} ₴</div> </div> : <div className="search-result_price">{price} ₴ {data.map((item, index) => item.isCashBack && index < 1 ? <div className="cash-back-item">Кешбек на Вашу карту {`${greenCardCashBack.toFixed(2)} ₴ (${cashBackPercentage}%)`}</div> : "")} </div> } </article> <div className="search-result_right"> <button form={formId} type="submit" className="btn btn-link btn-primary btn-buy" onClick={handleClick} > {!formId ? "Вибрати" : "Оплатити"}{" "} <i className="fa fa-long-arrow-right" aria-hidden="true"></i> </button> </div> </div> ); }; export default Policy;
修复思路与代码修改
1. 解决无限重渲染循环
直接在组件渲染阶段调用setMaxPercentage会触发组件重新渲染,每次渲染又会重复调用setState,形成无限循环,这是触发错误的核心原因。不需要用useState存储折扣数组,直接计算最大折扣值即可。
2. 修正数值类型错误
toFixed(0)会将数字转为字符串,而Math.max无法对字符串数组取最大值,导致逻辑错误。应该先计算数值类型的折扣百分比,取最大值后再转为字符串展示。
3. 优化计算逻辑(可选)
使用useMemo缓存计算结果,只有当data变化时才重新计算,提升组件性能。
修改后的代码示例
替换原来的useState和data.map部分:
import React, { useState, useMemo } from "react"; // ... 其他代码保持不变 const Policy = ({ name, data, formId, id, onBuy, onPay, contractorId, companyId }: IPolicy) => { // ... 其他代码保持不变 // 计算最大折扣百分比,处理空数据边界情况 const maxPercentage = useMemo(() => { if (data.length === 0) return 0; const percentages = data.map(d => getDiscountPercentage(d.amount, d.discountedAmount)); return Math.max(...percentages); }, [data]); // ... 其他代码保持不变 return ( // ... 其他代码保持不变 <div>Знижка {Math.floor(maxPercentage)}%</div> // ... 其他代码保持不变 ); };
额外边界处理
如果payment可能为0,需要在getDiscountPercentage里处理除以0的情况:
const getDiscountPercentage = (payment, discountedPayment) => { if (payment === 0) return 0; return ((payment - discountedPayment) / payment) * 100; };
内容的提问来源于stack exchange,提问作者Hunter91151
相关产品推荐
相关产品推荐

