背景 如今很多網站都引入截圖功能,可用於問題反饋、內容分享等實用需求,而前端截圖也不知不覺成為了首選。今天為大家推薦兩種前端截圖方式,雖然有些局限,但是也能應付大部分項目需求。 Canvas截圖:html2canvas SVG截圖:rasterizehtml 原理 首先來談下兩種前端截圖方式的原理, ...
React在寫一個購物車的redux toolkit時遇到了問題。核心代碼如下:
import { createSlice } from "@reduxjs/toolkit";
const cartSlice = createSlice({
name: 'cart',
initialState: {
cartItems: [],
cartItemCount: 0
},
reducers: {
addProduct(state, action) {
const { imageUrl, name, price } = action.payload
let newCartItems = [...state.cartItems]
let flag = newCartItems.some((item, index, arr) => {
if(item.name == name) {
arr[index].quantity += 1
return true
}
})
if(!flag) {
newCartItems = [
...state.cartItems,
{ imageUrl, name, price, quantity: 1 }
]
}
const cartItemCount = newCartItems.reduce(
(prevTotal, currItem) => prevTotal + currItem.quantity, 0
)
return { cartItems: newCartItems, cartItemCount }
}
}
})
export const { addProduct, deleteProduct, incQuantity, decQuantity } = cartSlice.actions
export default cartSlice.reducer
核心邏輯是,調用addProduct來修改redux所管理的cartItems和cartItemCount,當向購物車中添加一個新的物品時,代碼正常運行;但當反覆添加一個物品時,代碼報出如下錯誤:
搜下資料發現是因為redux使用immer,不允許在reducer中修改state值後還return,二者只能取其一。
因此,當添加一個新物品時,由於沒有修改cartItems,因此可以有返回值,不報錯。
但當添加一個重覆的物品時,即使在最開始使用了let newCartItems = [...state.cartItems]
來創建一個新的對象,但由於state.cartItems
數組中保存的不是基本數據類型,而是一個對象,因此newCartItems
保存的是state.cartItems
中各個對象的引用,即
newCartItems == state.cartItems // false
newCartItems[0] == state.cartItems[0] // true
由此可得,添加一個新物品時,由於既修改了state,又return了新值,因此報出immer錯誤。
修改後的代碼如下:
addProduct(state, action) {
const { imageUrl, name, price } = action.payload
let flag = state.cartItems.some((item, index, arr) => {
if(item.name == name) {
arr[index].quantity += 1
state.cartItemCount += 1
return true
}
})
if(!flag) {
state.cartItems.push({ imageUrl, name, price, quantity: 1 })
state.cartItemCount += 1
}
}
這裡只是對state做了修改,而沒有return新值,因此代碼正常運行。