🎈 perf(购物页面): 优化购物页面的性能
This commit is contained in:
parent
bf80f95ead
commit
34abf8fc7f
@ -49,6 +49,7 @@
|
||||
"@tarojs/taro-h5": "^3.5.5",
|
||||
"big.js": "^6.2.1",
|
||||
"dayjs": "^1.11.3",
|
||||
"immer": "^9.0.16",
|
||||
"qs": "^6.10.3",
|
||||
"react": "^18.2.0",
|
||||
"react-dom": "^18.2.0",
|
||||
|
@ -236,5 +236,5 @@
|
||||
]
|
||||
}
|
||||
},
|
||||
"libVersion": "2.26.2"
|
||||
"libVersion": "2.27.3"
|
||||
}
|
@ -11,7 +11,6 @@ interface PropsType {
|
||||
}
|
||||
const InputX: FC<PropsType> = (props) => {
|
||||
const {customClassName, customStyle,customInputStyle, customInputClassName,...inputProps} = props
|
||||
console.log('props', props);
|
||||
return (
|
||||
<View className={customClassName} style={customStyle}>
|
||||
<CustomWrapper>
|
||||
|
@ -10,21 +10,30 @@ import { EnumSaleMode } from '@/common/Enumerate'
|
||||
import { selectList } from '../../config'
|
||||
import { AdjestShoppingCartApi } from '@/api/shopping/index'
|
||||
import { Goods, ShoppingDispatchType, ShoppingStateContextValue, useShoppingDispatch, useShoppingState } from '../../context'
|
||||
import { ShoppingStore } from '../../context/shoppingStore'
|
||||
import { events, ShoppingStore } from '../../context/shoppingStore'
|
||||
import LabAndImg from '@/components/LabAndImg'
|
||||
import { usePropsValue } from '@/use/useCommon'
|
||||
|
||||
type PropsType = {
|
||||
state?: {
|
||||
multipleSelection: Goods[]
|
||||
Observer: ShoppingStore
|
||||
}
|
||||
purchaserId: number
|
||||
itemData: Record<string, any> & object
|
||||
checked?: boolean
|
||||
onChange?: (isChecked: boolean, goodsId: number) => void
|
||||
}
|
||||
|
||||
const ColorKindItem: FC<PropsType> = props => {
|
||||
const { state, purchaserId, itemData } = props
|
||||
const dispatch = useShoppingDispatch()
|
||||
console.log('rerender component ColorKindItem', props);
|
||||
const { state, purchaserId, itemData, checked = false } = props
|
||||
const [isChecked, setCheck] = usePropsValue({
|
||||
value: checked,
|
||||
defaultValue: checked,
|
||||
onChange: (value) => {
|
||||
props.onChange?.(value, itemData.id)
|
||||
}
|
||||
})
|
||||
|
||||
//格式化数量
|
||||
const formatCount = itemData => {
|
||||
@ -32,6 +41,7 @@ const ColorKindItem: FC<PropsType> = props => {
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
console.log('itemData==>',itemData);
|
||||
setCount(formatCount(itemData))
|
||||
}, [itemData.roll, itemData.length])
|
||||
|
||||
@ -46,7 +56,6 @@ const ColorKindItem: FC<PropsType> = props => {
|
||||
const handleCountChange = (nextValue: number) => {
|
||||
setCount(nextValue)
|
||||
}
|
||||
|
||||
|
||||
|
||||
//格式化单位
|
||||
@ -55,36 +64,21 @@ const ColorKindItem: FC<PropsType> = props => {
|
||||
}
|
||||
// 选中
|
||||
const handleSelect = () => {
|
||||
dispatch({
|
||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||
data: {
|
||||
purchaserId: purchaserId,
|
||||
multipleSelection: {
|
||||
...state?.multipleSelection,
|
||||
[itemData.id]: {
|
||||
id: itemData?.id,
|
||||
estimate_amount: itemData.estimate_amount,
|
||||
product_code: itemData.product_code,
|
||||
product_color_code: itemData.product_color_code,
|
||||
sale_mode: itemData.sale_mode,
|
||||
count: itemData.sale_mode === EnumSaleMode.Bulk ? itemData.roll : Number(formatMeterDiv(itemData.length)),
|
||||
}
|
||||
},
|
||||
},
|
||||
})
|
||||
const payload = {
|
||||
id: itemData?.id,
|
||||
estimate_amount: itemData.estimate_amount,
|
||||
product_code: itemData.product_code,
|
||||
product_color_code: itemData.product_color_code,
|
||||
sale_mode: itemData.sale_mode,
|
||||
count: itemData.sale_mode === EnumSaleMode.Bulk ? itemData.roll : Number(formatMeterDiv(itemData.length)),
|
||||
}
|
||||
events.trigger('updatePurchaserMultipleSelection', purchaserId, payload, 'add', itemData?.id)
|
||||
setCheck(true)
|
||||
}
|
||||
// 未选中
|
||||
const handleClose = () => {
|
||||
const temp = {...state?.multipleSelection}
|
||||
delete temp?.[itemData.id]
|
||||
console.log('handleClose==>',temp);
|
||||
dispatch({
|
||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||
data: {
|
||||
purchaserId: purchaserId,
|
||||
multipleSelection: temp,
|
||||
},
|
||||
})
|
||||
events.trigger('updatePurchaserMultipleSelection', purchaserId, null, 'delete', itemData.id)
|
||||
setCheck(false)
|
||||
}
|
||||
const { fetchData } = AdjestShoppingCartApi()
|
||||
|
||||
@ -99,7 +93,7 @@ const ColorKindItem: FC<PropsType> = props => {
|
||||
itemData.roll = num
|
||||
targetColor.roll = num
|
||||
} else {
|
||||
itemData.length = num
|
||||
itemData.length = formatMeterMul(num)
|
||||
targetColor.length = formatMeterMul(num)
|
||||
}
|
||||
const res = await fetchData({
|
||||
@ -118,10 +112,10 @@ const ColorKindItem: FC<PropsType> = props => {
|
||||
|
||||
return (
|
||||
<MCheckbox
|
||||
status={state?.multipleSelection?.hasOwnProperty(itemData.id) || false}
|
||||
status={isChecked}
|
||||
onSelect={handleSelect}
|
||||
onClose={handleClose}
|
||||
customClassName={classnames(styles.checkbox, state?.multipleSelection?.hasOwnProperty(itemData.id) ? styles.selected : '')}
|
||||
customClassName={classnames(styles.checkbox, isChecked ? styles.selected : '')}
|
||||
customTextClass={styles.colorKindItem}>
|
||||
<View className={styles['colorKindItem__left']}>
|
||||
<LabAndImg value={labAndImgObj(itemData)} />
|
||||
@ -157,7 +151,26 @@ const ColorKindItem: FC<PropsType> = props => {
|
||||
// State 分割组件 思路就是把 context 直接通过 props 的形式传给组件,这样的话就解决了 context 强制刷新 memo 的问题了
|
||||
// 那么当 context 内的 value 被更新的时候,react 只会强制渲染 Wrapper
|
||||
const withStateSlice = (comp, slice) => {
|
||||
const MemoComp = memo(comp)
|
||||
const MemoComp = memo(comp, (prevProps, nextProps) => {
|
||||
let needMemo = true
|
||||
if (prevProps.itemData !== nextProps.itemData) {
|
||||
console.log('itemData 有变化');
|
||||
needMemo = false
|
||||
}
|
||||
if (prevProps.state.Observer !== nextProps.state.Observer) {
|
||||
console.log('Observer 有变化');
|
||||
needMemo = false
|
||||
}
|
||||
if (prevProps.checked !== nextProps.checked) {
|
||||
console.log('checked 有变化', prevProps.checked, nextProps.checked);
|
||||
needMemo = false
|
||||
}
|
||||
if (prevProps.purchaserId !== nextProps.purchaserId) {
|
||||
console.log('purchaserId 有变化');
|
||||
needMemo = false
|
||||
}
|
||||
return needMemo
|
||||
})
|
||||
const Wrapper = (props, ref) => {
|
||||
const state = useShoppingState()
|
||||
return <MemoComp ref={ref} state={slice(state, props)} {...props} />
|
||||
@ -167,7 +180,6 @@ const withStateSlice = (comp, slice) => {
|
||||
|
||||
const ColorKindItemWithStateSlice = withStateSlice(ColorKindItem, (state: ShoppingStateContextValue, props: PropsType) => {
|
||||
return {
|
||||
multipleSelection: state.colorStore[props.purchaserId]['multipleSelection'],
|
||||
Observer: state.Observer,
|
||||
}
|
||||
})
|
||||
|
@ -1,3 +1,4 @@
|
||||
import produce from 'immer'
|
||||
import { FC, ReactNode, useEffect, useMemo, useReducer, useRef } from 'react'
|
||||
import {
|
||||
GoodsMeta,
|
||||
@ -7,6 +8,7 @@ import {
|
||||
ShoppingDispatchType,
|
||||
shoppingReducer,
|
||||
ShoppingStateContext,
|
||||
throwError,
|
||||
} from '../../context'
|
||||
import { ColorStore, ShoppingStateContextValue } from '../../context'
|
||||
import { ShoppingStore } from '../../context/shoppingStore'
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { Text, View } from '@tarojs/components'
|
||||
import { FC, forwardRef, memo, useEffect, useMemo, useRef, useState, useTransition } from 'react'
|
||||
import { FC, forwardRef, memo, useCallback, useEffect, useMemo, useRef, useState, useTransition } from 'react'
|
||||
import styles from './index.module.scss'
|
||||
import classnames from 'classnames'
|
||||
import { formatMeterDiv } from '@/common/format'
|
||||
@ -15,8 +15,10 @@ import { alert, isEmptyObject } from '@/common/common'
|
||||
import classNames from 'classnames'
|
||||
import LoadingCard from '@/components/loadingCard'
|
||||
import { ShoppingCartListApi } from '@/api'
|
||||
import { ShoppingStore } from '../../context/shoppingStore'
|
||||
import { events, ShoppingStore } from '../../context/shoppingStore'
|
||||
import { usePropsValue } from '@/use/useCommon'
|
||||
import produce, { setAutoFreeze } from 'immer'
|
||||
import { nextTick } from '@tarojs/taro'
|
||||
|
||||
interface ButtonPropsType {
|
||||
isActive: boolean
|
||||
@ -24,6 +26,7 @@ interface ButtonPropsType {
|
||||
children?: React.ReactNode
|
||||
customStyle?: React.CSSProperties
|
||||
}
|
||||
type OperationType = 'add' | 'delete'
|
||||
// 订单类型
|
||||
const SaleModeButton: FC<ButtonPropsType> = props => {
|
||||
const { onClick, children, isActive = false, customStyle } = props
|
||||
@ -62,7 +65,7 @@ type PropsType = {
|
||||
|
||||
const ShoppingCartItem: FC<PropsType> = props => {
|
||||
const { state } = props
|
||||
console.log('props ShoppingCartItem', props)
|
||||
console.log('rerender component ShoppingCartItem', props)
|
||||
|
||||
const [itemData, setItemData] = usePropsValue({
|
||||
value: props.itemData,
|
||||
@ -143,9 +146,45 @@ const ShoppingCartItem: FC<PropsType> = props => {
|
||||
|
||||
const [isPending, startTransition] = useTransition()
|
||||
const { fetchData } = ShoppingCartListApi()
|
||||
|
||||
// 更新当前客户的多选项
|
||||
const updatePurchaserMultipleSelection = (purchaserId, payload, operationType: OperationType, goodsId: number) => {
|
||||
if(operationType === 'add'){
|
||||
dispatch({
|
||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||
data: {
|
||||
purchaserId: purchaserId,
|
||||
multipleSelection: produce(multipleSelection, (multipleSelectionDraft) =>{
|
||||
if(!multipleSelectionDraft){
|
||||
return {
|
||||
[goodsId]: payload
|
||||
}
|
||||
}else{
|
||||
multipleSelectionDraft[goodsId] = payload
|
||||
}
|
||||
}),
|
||||
},
|
||||
})
|
||||
|
||||
}else if(operationType === 'delete'){
|
||||
const temp = {...multipleSelection}
|
||||
delete temp?.[goodsId]
|
||||
dispatch({
|
||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||
data: {
|
||||
purchaserId: purchaserId,
|
||||
multipleSelection: temp,
|
||||
},
|
||||
})
|
||||
}
|
||||
}
|
||||
// 发布订阅
|
||||
useEffect(()=>{
|
||||
events.on('updatePurchaserMultipleSelection', updatePurchaserMultipleSelection)
|
||||
return () => {
|
||||
events.off('updatePurchaserMultipleSelection', updatePurchaserMultipleSelection)
|
||||
}
|
||||
}, [updatePurchaserMultipleSelection])
|
||||
// 发布订阅
|
||||
|
||||
useEffect(() => {
|
||||
console.log('update multipleSelection',multipleSelection);
|
||||
const unsubscribe = state?.Observer?.subscribe(async id => {
|
||||
@ -290,25 +329,60 @@ interface GoodsListPropType {
|
||||
}
|
||||
const GoodsList = memo<GoodsListPropType>(props => {
|
||||
const { itemData, selected, isPending, startTransition, multipleSelection } = props
|
||||
|
||||
const prevMultipleSelection = useRef(multipleSelection)
|
||||
const currentSelected = useRef<EnumSaleMode | null>(null)
|
||||
|
||||
const dispatch = useShoppingDispatch()
|
||||
|
||||
const [component, setComponent] = useState<JSX.Element | null>(null)
|
||||
// 使用 produce 更新特定的 ColorKindItem
|
||||
const updateSpecifiedComponent = () => {
|
||||
let newId
|
||||
if(multipleSelection && prevMultipleSelection.current !== multipleSelection){
|
||||
for(let key in multipleSelection){
|
||||
if(!prevMultipleSelection.current?.hasOwnProperty(key)){
|
||||
newId = key
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
console.log('multipleSelection==+>',multipleSelection);
|
||||
console.log('currentSelected', currentSelected.current, selected);
|
||||
console.log('component',component);
|
||||
if(component){
|
||||
if(itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0){
|
||||
setComponent(produce(component, (draft) => {
|
||||
console.log('prev',component);
|
||||
const index = (draft as unknown as any[]).findIndex((item)=> item.key === newId)
|
||||
console.log('index',index)
|
||||
if(index !== -1) {
|
||||
const item = itemData?.[BackEndSaleModeListFieldMap[selected]].find(item => {
|
||||
return item.id === Number(newId)
|
||||
})
|
||||
console.log('item', item, newId);
|
||||
draft![index] = <ColorKindItem checked={multipleSelection?.hasOwnProperty(newId)} purchaserId={itemData?.purchaser_id} key={newId} itemData={item}></ColorKindItem>
|
||||
}
|
||||
}))
|
||||
}else{
|
||||
setComponent(<View className={styles.noList}>暂无数据</View>)
|
||||
}
|
||||
}
|
||||
prevMultipleSelection.current = multipleSelection
|
||||
|
||||
}
|
||||
// 更新 GoodsList 组件
|
||||
const updateComponent = () => {
|
||||
setComponent(
|
||||
itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0 ? (
|
||||
() => itemData?.[BackEndSaleModeListFieldMap[selected]].length !== 0 ? (
|
||||
itemData?.[BackEndSaleModeListFieldMap[selected]].map(item => {
|
||||
console.log('item===>', item)
|
||||
return <ColorKindItem purchaserId={itemData.purchaser_id} key={item.id} itemData={item}></ColorKindItem>
|
||||
console.log('item===>', item, multipleSelection?.hasOwnProperty(item.id))
|
||||
return <ColorKindItem checked={multipleSelection?.hasOwnProperty(item.id)} purchaserId={itemData.purchaser_id} key={item.id} itemData={item}></ColorKindItem>
|
||||
})
|
||||
) : (
|
||||
<View className={styles.noList}>暂无数据</View>
|
||||
),
|
||||
)
|
||||
)
|
||||
prevMultipleSelection.current = multipleSelection
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
@ -337,8 +411,8 @@ const GoodsList = memo<GoodsListPropType>(props => {
|
||||
})
|
||||
updateComponent()
|
||||
} else {
|
||||
// 重新把当前的选中状态赋值给ref 作为下一次比较的旧状态
|
||||
currentSelected.current = selected
|
||||
// 重新把当前的选中状态赋值给ref 作为下一次比较的旧状态
|
||||
dispatch({
|
||||
type: ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX,
|
||||
data: {
|
||||
@ -368,28 +442,32 @@ const GoodsList = memo<GoodsListPropType>(props => {
|
||||
const withStateSlice = (comp, slice) => {
|
||||
const MemoComp = memo(comp, (prevProps, nextProps) => {
|
||||
let needMemo = true
|
||||
// const prevCheckedPurchaserId = prevProps.state.currentCheckedPurchaserId
|
||||
// const nextCheckedPurchaserId = nextProps.state.currentCheckedPurchaserId
|
||||
// const purchaser_id = prevProps.itemData.purchaser_id
|
||||
// const prevMultipleSelection = prevProps.state.colorStore[purchaser_id].multipleSelection
|
||||
// const nextMultipleSelection = nextProps.state.colorStore[purchaser_id].multipleSelection
|
||||
if (JSON.stringify(prevProps.itemData) !== JSON.stringify(nextProps.itemData)) {
|
||||
needMemo = false
|
||||
}
|
||||
if(prevProps.itemData.purchaser_name === 'Hhjh'){
|
||||
if(prevProps.itemData.purchaser_name === 'JENNIE'){
|
||||
console.log('------withStateSlice props-------');
|
||||
console.log('withStateSlice props prevProps', prevProps);
|
||||
console.log('withStateSlice props prevProps comparison itemData', prevProps.itemData === nextProps.itemData);
|
||||
console.log('withStateSlice props nextProps', nextProps);
|
||||
console.log('withStateSlice props prevProps comparison multipleSelection', prevProps.state.multipleSelection === nextProps.state.multipleSelection);
|
||||
console.log('withStateSlice props prevProps comparison currentCheckedPurchaserId', prevProps.state.currentCheckedPurchaserId === nextProps.state.currentCheckedPurchaserId);
|
||||
console.log('withStateSlice props prevProps comparison Observer', prevProps.state.Observer === nextProps.state.Observer);
|
||||
console.log('withStateSlice props prevProps comparison state', prevProps.state === nextProps.state);
|
||||
console.log('------withStateSlice props-------');
|
||||
}
|
||||
if (JSON.stringify(prevProps.state) !== JSON.stringify(nextProps.state)) {
|
||||
console.log('MultipleSelection 有变化');
|
||||
if (prevProps.state.Observer !== nextProps.state.Observer) {
|
||||
console.log('Observer 有变化');
|
||||
needMemo = false
|
||||
}
|
||||
if (prevProps.state.multipleSelection !== nextProps.state.multipleSelection) {
|
||||
console.log('multipleSelection 有变化');
|
||||
needMemo = false
|
||||
}
|
||||
if (prevProps.state.currentCheckedPurchaserId !== nextProps.state.currentCheckedPurchaserId) {
|
||||
console.log('currentCheckedPurchaserId 有变化');
|
||||
needMemo = false
|
||||
}
|
||||
// if (JSON.stringify(prevCheckedPurchaserId) !== JSON.stringify(nextCheckedPurchaserId)) {
|
||||
// console.log('checkedPurchaserId 有变化');
|
||||
// needMemo = false
|
||||
// }
|
||||
return needMemo
|
||||
})
|
||||
const Wrapper = (props, ref) => {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import { EnumSaleMode } from '@/common/Enumerate'
|
||||
import produce from 'immer'
|
||||
import React, { Dispatch } from 'react'
|
||||
import { useContext } from 'react'
|
||||
import { ShoppingStore } from './shoppingStore'
|
||||
@ -88,44 +89,54 @@ export type ShoppingAction = {
|
||||
data?: any
|
||||
}
|
||||
|
||||
export function shoppingReducer(state: ShoppingStateContextValue, action: ShoppingAction) {
|
||||
export const shoppingReducer = produce((draft: ShoppingStateContextValue, action: ShoppingAction)=>{
|
||||
const { type, data } = action
|
||||
switch (type) {
|
||||
case ShoppingDispatchType.UPDATE_MANAGE_STATUS: {
|
||||
return { ...state, isManageStatus: data }
|
||||
draft.isManageStatus = data
|
||||
break
|
||||
}
|
||||
case ShoppingDispatchType.UPDATE_MULTIPLE_SELECTION_STATUS: {
|
||||
return { ...state, isMultipleSelection: data }
|
||||
draft.isMultipleSelection = data
|
||||
break
|
||||
}
|
||||
case ShoppingDispatchType.UPDATE_CURRENT_CHECKED_PURCHASERID: {
|
||||
return { ...state, currentCheckedPurchaserId: data }
|
||||
draft.currentCheckedPurchaserId = data
|
||||
break
|
||||
}
|
||||
case ShoppingDispatchType.UPDATE_CURRENT_CHECKED_SALEMODE: {
|
||||
return { ...state, currentCheckedSaleMode: data }
|
||||
draft.currentCheckedSaleMode = data
|
||||
break
|
||||
}
|
||||
case ShoppingDispatchType.UPDATE_COLOR_STORE: {
|
||||
return { ...state, colorStore: data }
|
||||
draft.colorStore = data
|
||||
break
|
||||
}
|
||||
case ShoppingDispatchType.UPDATE_SELECTED_AMOUNT: {
|
||||
return { ...state, selectedAmount: data }
|
||||
draft.selectedAmount = data
|
||||
break
|
||||
}
|
||||
case ShoppingDispatchType.UPDATE_CHANGED_CHECKBOX: {
|
||||
return {
|
||||
...state,
|
||||
colorStore: {
|
||||
...state.colorStore,
|
||||
[data.purchaserId as number]: {
|
||||
purchaserId: data.purchaserId,
|
||||
goodsKind: { ...state.colorStore[data.purchaserId]?.goodsKind, ...data.goodsKind },
|
||||
multipleSelection: data.multipleSelection ? data.multipleSelection : state.colorStore[data.purchaserId]?.multipleSelection,
|
||||
},
|
||||
},
|
||||
if(!draft.colorStore[data.purchaserId]){
|
||||
draft.colorStore[data.purchaserId] = {
|
||||
purchaserId: data.purchaserId,
|
||||
goodsKind: data.goodsKind,
|
||||
multipleSelection: data.multipleSelection
|
||||
}
|
||||
}else{
|
||||
draft.colorStore[data.purchaserId] = produce(draft.colorStore[data.purchaserId], purchaserDraft => {
|
||||
purchaserDraft.purchaserId = data.purchaserId
|
||||
purchaserDraft.goodsKind = { ...purchaserDraft.goodsKind, ...data.goodsKind }
|
||||
purchaserDraft.multipleSelection = data.multipleSelection ? data.multipleSelection : purchaserDraft?.multipleSelection
|
||||
})
|
||||
}
|
||||
break
|
||||
}
|
||||
default:
|
||||
throwError()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
export const ShoppingStateContext = React.createContext<ShoppingStateContextValue | null>(null)
|
||||
|
||||
@ -161,6 +172,6 @@ export interface InternalShoppingCartAction extends ShoppingCartAction {
|
||||
__INTERNAL__: React.MutableRefObject<ShoppingCartAction | null>
|
||||
}
|
||||
|
||||
function throwError(): never {
|
||||
export function throwError(): never {
|
||||
throw new Error('没有这个action.type')
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
|
||||
// 用于优化数据流 结合发布订阅 更新组件内部状态可以组件自己处理
|
||||
|
||||
import { Events } from "@tarojs/taro"
|
||||
import { ColorStore } from "."
|
||||
export const events = new Events()
|
||||
|
||||
export type SubscribeCallback = (changedGoods: any) => void
|
||||
|
||||
|
@ -7558,6 +7558,11 @@ image-size@~0.5.0:
|
||||
resolved "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz"
|
||||
integrity sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==
|
||||
|
||||
immer@^9.0.16:
|
||||
version "9.0.16"
|
||||
resolved "https://registry.npmmirror.com/immer/-/immer-9.0.16.tgz#8e7caab80118c2b54b37ad43e05758cdefad0198"
|
||||
integrity sha512-qenGE7CstVm1NrHQbMh8YaSzTZTFNP3zPqr3YU0S0UY441j4bJTg4A2Hh5KAhwgaiU6ZZ1Ar6y/2f4TblnMReQ==
|
||||
|
||||
immutable@^4.0.0:
|
||||
version "4.1.0"
|
||||
resolved "https://registry.npmjs.org/immutable/-/immutable-4.1.0.tgz"
|
||||
|
Loading…
x
Reference in New Issue
Block a user