reactjs - 如何防止应用程序不渲染两次?(反应)
问题描述
我在我的应用程序中显示 a 时遇到问题totalAmount
。由于两次渲染,它显示错误的值。我尝试为此使用 useMemo 钩子。
这就是它的样子(不要打扰 css :D )
所以它是这样计算的:
7.99 * 2 + 4.99 = 20.97
最后添加的项目 -44.99
尚未计入totalAmount
2
我猜它会因为渲染两次而将第一项乘以
这是我的代码沙箱:https ://codesandbox.io/s/objective-kare-805kc?file=/src/components/App.tsx
解决方案
您的组件对多次渲染没有弹性这一事实本身就是一个问题。通常,您不能假设您的组件只会渲染一定次数,当即将发布的并发模式发布时尤其如此。出于性能原因,减少渲染次数可能很有用,但我不认为这可以解决您的问题。
问题似乎是您的减速器不纯。reducer 应该是一个纯函数:它接受一个状态和一个动作,并产生一个没有副作用的新状态。但相反,在你的减速器中间你调用setFixedAmount
and setTotalAmount
,它将设置状态并导致重新渲染。
通过查看您的代码,我认为拥有三个状态是错误的。您有products
、totalAmount
和fixedAmount
,并且正在尝试编写代码以使它们彼此同步。相反,更好的方法是只有一个状态:products
. totalAmount
然后fixedAmount
是根据产品计算得出的值。
function App() {
const [allData] = useState(data.products);
const [products, dispatch] = useReducer((state: any, action: any): any => {
switch (action.type) {
case "ADD_PRODUCT":
state.filter((i: any) => {
if (i.id === action.payload.id) {
i.count = i.count + 1;
}
return i;
});
const noDuplicateArr = state.filter(
(i: any) => i.id !== action.payload.id
);
return [...noDuplicateArr, action.payload];
case "DELETE_PRODUCT":
state.filter((i: any) => {
if (i.id === action.payload.id) {
i.count = 1;
}
return i;
});
return state.filter((item: any) => item.id !== action.payload.id);
default:
return state;
}
}, []);
let totalAmount = 0;
products.forEach(product => {
totalAmount += product.count * product.price.amount;
})
const fixedAmount = totalAmount.toFixed(2);
const store = useMemo(() => ({ products, dispatch }), [products]);
return (
<div className="app">
<ProductContext.Provider value={{ allData, fixedAmount, store }}>
<ShoppingList />
<ShoppingBag />
</ProductContext.Provider>
</div>
);
}
推荐阅读
- python - Python 用总数的百分比替换 Counter 中的整数
- email - 回复交易电子邮件 Magento 1
- python - 使用正则表达式从目录中读取文件
- javascript - 未捕获的类型错误:无法设置未定义的属性(设置“pdfMake”)
- docker - 使用 docker image 为本地测试设置 kubernetes 的问题
- javascript - 反应如何添加悬停边框标签
- html - CSS 文件可以更改或删除,但页面上的 css 不会更改
- kubernetes - ingress-nginx、cert-manager 和 ingressClassName
- java - 找不到 android.arch.lifecycle:extensions:2.1.0。要求:项目:app > com.paypal.checkout:android-sdk:0.1.0
- api - 我想要一个模型和控制器功能来测试数据库中的 api 而不使用视图