我在应用中显示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
答案 0 :(得分:3)
您的组件对多个渲染没有弹性的事实本身就是一个问题。通常,您不能假设您的组件只能渲染一定次数,并且在即将发布的并发模式发布时尤其如此。出于性能方面的考虑,减少渲染数量可能很有用,但是我不认为这可以解决您的问题。
问题似乎是您的减速器不纯。减速器应该是纯函数:它接受一个状态和一个动作,并产生一个新的状态,而没有副作用。但是,相反,在化简器的中间,您正在调用setFixedAmount
和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>
);
}