I am looping through the contents of the following array:
chosenBets: [
{
id: 2,
label: 2,
odd: 4.8,
team_home: "Liverpool",
team_away: "Sheffield United",
},
{
id: 2,
label: 2,
odd: 4.8,
team_home: "Liverpool",
team_away: "Sheffield United",
},
],
To get the total odds of each bet:
const getTotalOdds = () => {
let totalOdds = 0
chosenBets.forEach(bet => {
totalOdds += bet.odd
})
let newState = Object.assign({}, state)
newState.totalOdds = totalOdds
setState({ ...newState })
}
But when I call the function inside of useEffect it causes an infinite loop.
Full code:
import * as React from "react"
import { Frame, Stack, addPropertyControls, ControlType } from "framer"
import { Input } from "./Input"
interface Bets {
id: number
label: number
odd: number
team_home: string
team_away: string
}
interface IProps {
chosenBets: Bets[]
}
const style = {
span: {
display: "block",
},
}
const Row = ({ label, property }) => (
<div style={{ display: "flex", width: "100%" }}>
<span style={{ ...style.span, marginRight: "auto" }}>{label}</span>
<span style={{ ...style.span }}>{property}</span>
</div>
)
export const BetCalculator: React.FC<IProps> = props => {
const { chosenBets } = props
const [state, setState] = React.useState({
stake: 10,
totalOdds: 0,
potentialPayout: 0,
})
const { stake, totalOdds } = state
const onChange = e => {
let newState = Object.assign({}, state)
newState.stake = Number(e.value)
setState({ ...newState })
}
const getTotalOdds = () => {
let totalOdds = 0
chosenBets.forEach(bet => {
totalOdds += bet.odd
})
let newState = Object.assign({}, state)
newState.totalOdds = totalOdds
setState({ ...newState })
}
const getPayout = () => {
let potentialPayout = totalOdds * stake
console.log(potentialPayout, "potentialPayout")
// let newState = Object.assign({}, state)
// newState.potentialPayout = potentialPayout
// setState({ ...newState })
}
React.useEffect(() => {
getTotalOdds()
getPayout()
}, [state])
return (
<Stack alignment="end" backgroundColor="white">
<Row
label="stake"
property={<Input onChange={onChange} value={stake} />}
/>
<Row label="Odds" property={totalOdds} />
</Stack>
)
}
BetCalculator.defaultProps = {
chosenBets: [
{
id: 2,
label: 2,
odd: 4.8,
team_home: "Liverpool",
team_away: "Sheffield United",
},
{
id: 2,
label: 2,
odd: 4.8,
team_home: "Liverpool",
team_away: "Sheffield United",
},
],
}
My questions are as follows:
What is causing this?
How do I resolve?
You can divide state into smaller chunks:
const [stake, setStake] = useState(10);
const [totalOdds, setTotalOdds] = useState(0);
const [potentialPayout, setPotentialPayout] = useState(0);
Easier to manage.
If your useEffect is called every time state has changed, and on the other hand every useEffect returns new state object - well. Infinite loop.
Just put the calculations in the onChange function and you won't need useEffect at all (or just use useEffect to cause side effects, like console.log);
Related
I am trying to access the students variable by putting its value in a state then accessing that state in my handler function but it always returns an empty array.
const students = useSelector((state) => state.students);
useEffect(() => {
setdata(students);
console.log(data);
}, [])
const handleScanWebCam = (result, error) => {
if (result) {
console.log(data)
const list = data.filter(function (student) {
return student.id === result.text;
})
setScanResultWebCam({
id: list.id,
grade: list.grade,
name: list.name,
section: list.section
});
}
}
this is my full code
function QrScanner() {
const dispatch = useDispatch(getStudents())
useEffect(() => {
dispatch(getStudents());
}, [dispatch])
const students = useSelector((state) => state.students);
const [scanResultWebCam, setScanResultWebCam ] = useState({
id: '',
grade: '',
name: '',
section:''
});
const [openVerifier, setOpenVerifier] = useState(false);
const [data, setdata] = useState([]);
useEffect(() => {
setdata(students);
console.log(data);
}, [])
const handleScanWebCam = (result, error) => {
if (result) {
const list = data.filter(function (student) {
return student.id === result.text;
})
setScanResultWebCam({
id: list.id,
grade: list.grade,
name: list.name,
section: list.section
});
setOpenVerifier(true);
}
}
return (
<>
<NavBar />
<Container
sx={{
display: 'flex',
marginTop: '4rem',
flexWrap: 'wrap',
gap: '12px',
width: '90%'
}}
>
<Box
sx={{
width: '50%',
border: 'solid',
display: 'flex',
flex: '1'
}}
>
<QrReader
scanDelay={500}
containerStyle={{ width: '25rem', margin: 'auto'}}
onResult={handleScanWebCam}
// onError={handleErrorWebcam}
/>
</Box>
<PopupVerifier
details={scanResultWebCam}
verifier={openVerifier}
handleClose={() => handleClose()}
/>
</Container>
</>
)
}
If you need to cache a "duplicate" of the selected students state then I'd recommend caching students in a React ref that can have its current value read at any time during the component lifecycle, especially in stale closures.
Example:
function QrScanner() {
const dispatch = useDispatch(getStudents());
useEffect(() => {
dispatch(getStudents());
}, [dispatch]);
const students = useSelector((state) => state.students);
const studentsRef = React.useRef(students);
useEffect(() => {
studentsRef.current = students;
}, [students]);
...
const handleScanWebCam = (result, error) => {
if (result) {
const list = studentsRef.current.find(
(student) => student.id === result.text
);
if (list) {
setScanResultWebCam(list);
}
setOpenVerifier(true);
}
};
return (
...
);
}
You have using from react-redux. so you dont need to set student state.
and dispatch is used for change in store not getting data from it.
if you want to get an item from array use find instead of filter :
const list = students.find(student=>student.id===result.text);
i edit your code to :
function QrScanner() {
const students = useSelector((state) => state.students);
const [scanResultWebCam, setScanResultWebCam ] = useState({
id: '',
grade: '',
name: '',
section:''
});
const [openVerifier, setOpenVerifier] = useState(false);
const handleScanWebCam = (result, error) => {
if(result) {
const list = students.find(student=> student.id === result.text);
setScanResultWebCam({id: list.id, grade: list.grade, name: list.name, section: list.section});
setOpenVerifier(true);
}
}
return(
...
)
}
I am trying to add some 'save preferences' functionality to a DataGrid using https://reactdatagrid.io/docs/miscellaneous but when I add sortInfo makes columns unsortable, the same happens for filterValue (trying to save filtering strings/data). Code here:
import React, { useCallback, useState } from 'react';
import DataGrid from '#inovua/reactdatagrid-enterprise';
import { columnFilters, eeOverviewColumns, filterTypes } from "./overview-columns";
import '#inovua/reactdatagrid-enterprise/index.css';
import { TypeRowProps, TypeRowSelection } from '#inovua/reactdatagrid-community/types';
import { TypeOnSelectionChangeArg } from "#inovua/reactdatagrid-community/types/TypeDataGridProps"
import { Button, FormControl, MenuItem, Select, SelectChangeEvent, TextField } from '#mui/material';
import { TypeColumn, TypeFilterValue, TypeSortInfo } from '#inovua/reactdatagrid-enterprise/types';
interface StoreLayout {
columns: TypeColumn[];
sortInfo: TypeSortInfo;
columnOrder : string[];
filterValue: TypeFilterValue;
}
let STORE: StoreLayout = {
columns: eeOverviewColumns,
sortInfo: [],
columnOrder: eeOverviewColumns.map(ee => ee.name) as string[],
filterValue: columnFilters,
}
let VIEWS= [
{
id: 0,
name: "Default view",
state: STORE
}
]
const EEOverview = (props: any) => {
const dataSource = props.eeData
// Checkbox selection
const [selected, setSelected] = useState<TypeRowSelection>();
const onSelectionChange = useCallback(
(config: TypeOnSelectionChangeArg) => {
setSelected(config.selected)
},
[],
);
const goToEe = useCallback((rowProps: TypeRowProps) => {
window.location.href = `${window.location.href}/${rowProps.data.key}`;
}, [])
const initialState = Object.assign({}, STORE, {});
const [state, setState] = useState(initialState);
const [viewName, setViewName] = useState('')
const sendViewName = (viewName: string) => { setViewName(viewName) }
const saveState = () => {
if (!viewName || viewName.length === 0 ) {
alert("View name not provided")
return
}
STORE = {
columnOrder: state.columnOrder,
columns: state.columns,
sortInfo: state.sortInfo,
filterValue: state.filterValue
}
setState(Object.assign({}, state, {}))
if(VIEWS.map(view => view.name).some(name => name === viewName)) {
const view = VIEWS.find(view => view.name === viewName)!
view.state = state
} else {
VIEWS.push({
id: VIEWS.length,
name: viewName,
state: state
})
}
}
const onSortInfoChange = (sortInfo: TypeSortInfo) => {
setState(Object.assign({}, state, { sortInfo }));
}
const onColumnOrderChange = (columnOrder: string[]) => {
setState(Object.assign({}, state, { columnOrder }));
}
const onFilterValueChange = (filterValue: TypeFilterValue) => {
setState(Object.assign({}, state, { filterValue }));
}
const onBatchColumnResize = (batchColumnInfo: any, { reservedViewportWidth }: any) => {
const colsMap = batchColumnInfo.reduce((acc: any, colInfo: any) => {
const { column, width, flex } = colInfo
acc[column.name] = { width, flex }
return acc
}, {})
const columns = state.columns.map((c: any) => {
return Object.assign({}, c, colsMap[c.name])
})
setState(Object.assign({}, state, {
columns,
reservedViewportWidth
}))
}
return (
<div>
<ViewSelector state = {state} onChange = {setState} ></ViewSelector>
<ViewText onChange = {sendViewName} ></ViewText>
<Button sx={{ mx: 2, my: 2, minWidth: 80 }} variant="contained"
onClick = {saveState}
>
Save view
</Button>
<DataGrid
idProperty="key"
theme="default-light"
className="data-grid"
defaultFilterValue={columnFilters}
filterTypes={filterTypes}
filterValue={state.filterValue} //<- here
onRowClick={goToEe}
columns={state.columns}
sortInfo={state.sortInfo} //<- and here
columnOrder={state.columnOrder}
pagination="local"
dataSource={dataSource}
onSelectionChange={onSelectionChange}
sortable={true}
checkboxColumn
selected={selected}
enableSelection={true}
onSortInfoChange={onSortInfoChange}
onBatchColumnResize={onBatchColumnResize}
onColumnOrderChange={onColumnOrderChange}
onFilterValueChange={onFilterValueChange}
/>
</div>
);
}
export default EEOverview;
const ViewText = ({onChange}: {onChange: any}) => {
const onViewNameChange = (viewName: string) => {
onChange(viewName)
}
return (
<TextField sx={{ mx: 2, my: 2 }}
id="search"
variant="outlined"
size="small"
label="Name current view"
onChange={(e: React.ChangeEvent<HTMLInputElement>) => { onViewNameChange(e.target.value) }}
/>
)
}
const ViewSelector = ({state, onChange}: {state:any, onChange: any}) => {
const [selectedView, setSelectedView] = useState(0)
const handleViewChange = (event: SelectChangeEvent<number>) => {
const selectedView = VIEWS.find(view => view.id===event.target.value)!
setSelectedView(selectedView.id)
const selectedState = selectedView.state
onChange(Object.assign({},selectedState, {}))
}
return (
<FormControl sx={{ m: 2, minWidth: 140 }} >
<Select labelId="view" variant="standard" size="medium" value={selectedView}
renderValue={(selected: any) => { return <div>{VIEWS[selected].name}</div>; }}
onChange={handleViewChange}>
{VIEWS.map((val, key) => (
<MenuItem value={key}>{val.name}</MenuItem>
))}
</Select>
</FormControl>
)
}
If I remove sortInfo/filterValue from passing to DataGrid, it behaves correctly, but it won't be saved to preferences.
Tried to move dataSource from props to state but it has the same behaviour
I am constantly getting this error - This issue is in remove case. as soon as I remove the remove case in Appoint/reducers, the code is working. can someone help me find what the error is in remove case.
undefined is not an object (evaluating 'selectedDoc.quantity')
I don't know why it's undefined. help will be appreciated.
//appoint.js/reducers
import { APPOINT_DOC,Remove_Doc } from "../actions/appoint";
import docAppoint from '../../modules/docAppoint';
const initialState = {
items: {},
totalAmount: 0
};
export default (state = initialState, action) => {
switch (action.type) {
case APPOINT_DOC:
const addedProduct = action.product;
const prodPrice = addedProduct.price;
const prodTitle = addedProduct.title;
let updateOrNewDocAppoint;
if (state.items[addedProduct.id]) {
// already have the item in the cart
updateOrNewDocAppoint = new docAppoint(
state.items[addedProduct.id].quantity + 1,
prodPrice,
prodTitle,
state.items[addedProduct.id].sum + prodPrice
);
} else {
updateOrNewDocAppoint = new docAppoint(1, prodPrice, prodTitle, prodPrice);
}
return {
...state,
items: { ...state.items, [addedProduct.id]: updateOrNewDocAppoint },
totalAmount: state.totalAmount + prodPrice
};
case Remove_Doc:
const selectedDoc = state.items[action.pid];
const quantity = selectedDoc.quantity;
let updatedDoc;
if (quantity > 1) {
// need to reduce it, not erase it
const updatedDoc = new docAppoint(
selectedDoc.quantity - 1,
selectedDoc.prodPrice,
selectedDoc.prodTitle,
selectedDoc.sum - selectedDoc.prodPrice
);
updatedDoc = { ...state.items, [action.pid]: updatedDoc };
} else {
updatedDoc = { ...state.items };
delete updatedDoc[action.pid];
}
return {
...state,
items: updatedDoc,
totalAmount: state.totalAmount - selectedDoc.prodPrice
};
}
//appoint.js/actions
export const APPOINT_DOC = 'APPOINT_DOC';
export const Remove_Doc = 'Remove_Doc';
export const appointDoc = product => {
return {
type : APPOINT_DOC, product:product
};
};
export const removeDoc = productId => {
return{ type: Remove_Doc, pid: productId };
};
//docAppoint.js/modules
class docAppoint {
constructor( quantity,productPrice,productTitle,sum){
this.quantity=quantity;
this.productPrice=productPrice;
this.productTitle=productTitle;
this.sum=sum;
}
}
//registerDr
import React from "react";
import { View, Text, StyleSheet,Button,FlatList } from 'react-native';
import {useSelector,useDispatch} from 'react-redux';
import colors from "../../constants/colors";
import appoint from "../../store/reducers/appoint";
import ProcessDr from "../../components/Doctor/process";
import * as docActions from '../../store/actions/appoint';
const registerDr = props => {
const totalFee = useSelector (state => state.appoint.totalAmount)
const appointDoc = useSelector (state => {
const transformedAppointDoc = []
for (const key in state.appoint.items ) {
transformedAppointDoc.push({
productId : key,
productTitle : state.appoint.items[key].productTitle,
productPrice : state.appoint.items[key].productPrice,
quantity : state.appoint.items[key].quantity,
sum : state.appoint.items[key].sum
});
}
return transformedAppointDoc;
});
const dispatch = useDispatch();
return(
<View style={styles.screen}>
<View style={styles.summary}>
<Text style={styles.summarytext}> Fee: <Text style={styles.amount} > {totalFee} RS </Text> </Text>
<Button disabled = {appointDoc.length === 0}
title="Appoint Doctor" color={colors.primary} />
</View>
<View>
<FlatList data ={appointDoc}
keyExtractor = {item => item.productId}
renderItem ={itemData =>
<ProcessDr quantity={itemData.item.quantity}
title={itemData.item.productTitle}
amount={itemData.item.sum}
onRemove = {() => {
dispatch(docActions.removeDoc(itemData.item.productTitle))
}}
/>} />
</View>
</View>
)
}
const styles= StyleSheet.create({
screen:{
margin: 20,
},
summary:{
flexDirection:'row',
alignItems:'center',
justifyContent:'space-between',
marginBottom:20,
padding: 10,
shadowColor: 'black',
shadowOpacity: 0.26,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 8,
elevation: 5,
borderRadius: 10,
backgroundColor: 'white',
},
summarytext:{
fontFamily:'opsb',
fontSize:18,
},
amount: {
color: colors.primary
}
})
export default registerDr;
at first glance, undefined is not an object (evaluating 'selectedDoc.quantity') is referring to the selectedDoc is undefined.
Have you debugged to see if the items has the the correct key that matches action.pid ?
const selectedDoc = state.items[action.pid];
const quantity = selectedDoc.quantity;
do nothing if undefined.
const selectedDoc = state.items[action.pid];
if (selectedDoc) {
// your logic here
} else {
return state; // do nothing
}
I have an orders component that contains some orders each order has products and the user can update the quantity and price the problem is that the update process is very slow because if I update a product quantity for example all products in the order get remounted again and I think this is the main issue. if I have 100 products the product page render 100 times or more (one time for each product ) here is my current implementation on code sandbox: https://codesandbox.io/s/holy-tdd-3nj7g?file=/src/OrderingPage/Order/index.js
here is the order component that have multiple order but for simplicity lets assume we only have one order
import { useState, useCallback } from "react";
import Order from "./Order/index";
const OrderingScreen = () => {
const initialOrderData = {
order: {
total: 0,
vat: 0,
deliveryCharge: 0,
date: 0,
orderStart: 0,
orderEnd: 0,
customerGender: "",
actualPaid: 0,
dateStr: "",
payType: "cash",
itemsCount: 0,
orderDetails: [
{ name: "prod1", sellPrice: 120, quantity: 3 },
{ name: "prod2", sellPrice: 12, quantity: 2 },
{ name: "prod3", sellPrice: 1123, quantity: 2 },
{ name: "prod4", sellPrice: 1543, quantity: 1 },
{ name: "prod5", sellPrice: 123, quantity: 8 }
]
}
//other properties
};
const [ordersData, setOrdersData] = useState([initialOrderData]);
const resetOrder = useCallback(() => {
let ordersDataCopy = [...ordersData];
ordersDataCopy[0] = initialOrderData;
setOrdersData(ordersDataCopy);
}, [ordersData]);
const updateOrderProducts = useCallback(
(products) => {
let ordersCopy = [...ordersData];
ordersCopy[0]["order"]["orderDetails"] = [...products];
setOrdersData(ordersCopy);
},
[ordersData]
);
const updateOrder = useCallback(
(order) => {
let ordersCopy = [...ordersData];
ordersCopy[0]["order"] = { ...order };
setOrdersData(ordersCopy);
},
[ordersData]
);
return (
<Order
order={ordersData[0].order}
products={ordersData[0].order.orderDetails}
updateOrderProducts={updateOrderProducts}
updateOrder={updateOrder}
resetOrder={resetOrder}
/>
);
};
export default OrderingScreen;
here is the single order component
import OrderItem from "./OrderItem";
import { useEffect, memo, useCallback } from "react";
const Order = ({ order, products, updateOrderProducts, updateOrder }) => {
const handleOrderChange = useCallback((propertyName, value) => {
let orderCopy = { ...order };
orderCopy[propertyName] = value;
updateOrder(orderCopy);
});
const deleteProduct = useCallback((index) => {
let productsCopy = [...products];
productsCopy = productsCopy.filter(
(product) => product !== productsCopy[index]
);
updateOrderProducts(productsCopy);
}, []);
const handleOrderItemRemove = useCallback((index) => {
deleteProduct(index);
}, []);
const handleQuantityChange = useCallback((index, quantity) => {
let productsCopy = [...products];
productsCopy[index]["quantity"] = quantity;
updateOrderProducts(productsCopy);
}, []);
return (
<div className="d-flex px-2 flex-grow-1 mb-1">
{products.map((product, idx) => (
<OrderItem
product={product}
key={idx}
index={idx}
onRemove={handleOrderItemRemove}
onQuantityChange={handleQuantityChange}
updateProduct={handleOrderChange}
/>
))}
</div>
);
};
export default memo(Order);
and the last component which is the product component which I think is causing the performance issue (it render 1 + the number of products in the order if I update the quantity of one product )
import RemoveCircleIcon from "#mui/icons-material/RemoveCircle";
import AddCircleIcon from "#mui/icons-material/AddCircle";
import { memo, useMemo, useState, useEffect } from "react";
const OrderItem = ({ product, index, onQuantityChange }) => {
console.log("remount");
const [itemQuantity, setItemQuantity] = useState(product.quantity);
const incrementQuantity = () => {
onQuantityChange(index, itemQuantity + 1);
};
const decrementQuantity = () => {
itemQuantity > 1 && onQuantityChange(index, itemQuantity - 1);
};
useEffect(() => {
setItemQuantity(product.quantity);
}, [product.quantity]);
const productInfo = useMemo(() => (price, quantity, name) => {
let total = price * quantity;
total = +total.toFixed(2);
price = +price.toFixed(2);
return (
<div className={`col-9 col-xl-10 border rounded-start p-1 `}>
{name}
<div className="justify-content-around d-flex">
{"Price:" + price}
{" Quantity:" + quantity}
{" Total:" + total}
</div>
</div>
);
});
useEffect(() => {
setItemQuantity(product.quantity);
}, [product]);
const quantityColumn = (
<div>
<AddCircleIcon onClick={incrementQuantity} />
{itemQuantity}
<RemoveCircleIcon onClick={decrementQuantity} />
</div>
);
return (
<div style={{ marginBottom: "25px" }}>
{productInfo(product.sellPrice, product.quantity, product.name)}
{quantityColumn}
</div>
);
};
export default memo(OrderItem);
what I want to achieve is a snappy component update (maybe by making the product component mount only for the changed product)
you may see it fast on the sandbox but this version just explains the problem only... the real version is much complicated
You can improve performance by changing your React.memo components.
Instead of memo(OrderItem) pass as second argument function that will compare previous and current state:
function areEqualOrderItem(prevProps, nextProps) {
/*
return true if passing nextProps to render would return
the same result as passing prevProps to render,
otherwise return false
*/
return prevProps.quantity === nextProps.quantity;
}
export default memo(OrderItem, areEqualOrderItem);
Also I suggest do not use array index as component key try product name instead of this.
useCallback do nothing in your code. Instead you can use this one:
const handleOrderItemRemove = useCallback((index) => {
updateOrderProducts(prod => {
let productsCopy = [...prod];
productsCopy = productsCopy.filter(
(product) => product !== productsCopy[index]
);
return productsCopy;
});
}, [updateOrderProducts]);
const updateOrderProducts = useCallback(
(products) => {
setOrdersData(ords => {
let ordersCopy = [...ords];
ords[0]["order"]["orderDetails"] = [...products];
return ordersCopy;
});
},
[setOrdersData]
);
When you fix all your callbacks you can boost performance. At this time, your code cause rerender of all items almost every small change.
My code looks fine as I have checked states and it showing me that the item I have added and deleted in the state is fine but I don't know why I am getting this error?
In CartScreen.js onRemove() is dispatching the action which is stored in the store/actions/cart.js to remove an item from the cart.
CartScreen.js
import React from "react";
import { View, Text, FlatList, Button, StyleSheet } from "react-native";
import { useSelector, useDispatch } from "react-redux";
import Colors from "../../constants/Colors";
import CartItem from "../../components/shop/CartItem";
import * as cartActions from "../../store/actions/cart";
const CartScreen = (props) => {
const cartTotalAmount = useSelector((state) => state.cart.totalAmount);
const dispatch = useDispatch();
const cartItems = useSelector((state) => {
const transformedCartItems = [];
for (const key in state.cart.items) {
transformedCartItems.push({
productId: key,
productTitle: state.cart.items[key].productTitle,
productPrice: state.cart.items[key].productPrice,
quantity: state.cart.items[key].quantity,
sum: state.cart.items[key].sum,
});
}
return transformedCartItems;
});
return (
<View style={styles.screen}>
<View style={styles.summary}>
<Text style={styles.summaryText}>
Total:{" "}
<Text style={styles.amount}>${cartTotalAmount.toFixed(2)}</Text>
</Text>
<Button
color={Colors.primary}
title="Order Now"
disabled={cartItems.length === 0}
/>
</View>
<FlatList
data={cartItems}
keyExtractor={(item) => item.productId}
renderItem={(itemData) => (
<CartItem
quantity={itemData.item.quantity}
title={itemData.item.productTitle}
amount={itemData.item.sum}
onRemove={() => {
dispatch(cartActions.removeFromCart(itemData.item.productId)); //this is the function to remove item from cart.
}}
/>
)}
/>
</View>
);
};
const styles = StyleSheet.create({
screen: {
margin: 20,
},
summary: {
flexDirection: "row",
alignItems: "center",
justifyContent: "space-between",
marginBottom: 20,
padding: 10,
shadowColor: "black",
shadowOpacity: 0.26,
shadowOffset: { width: 0, height: 2 },
shadowRadius: 8,
elevation: 5,
borderRadius: 10,
backgroundColor: "white",
},
summaryText: {
fontFamily: "openSansBold",
fontSize: 18,
},
amount: {
color: Colors.secondary,
},
});
export default CartScreen;
store/actions/cart.js:
import { ADD_TO_CART, REMOVE_FROM_CART } from "../actions/cart";
import CartItem from "../../models/cart-item";
const intialState = {
items: {},
totalAmount: 0,
};
export default (state = intialState, action) => {
switch (action.type) {
case ADD_TO_CART:
const addedProduct = action.product;
const prodPrice = addedProduct.price;
const prodTitle = addedProduct.title;
let updatedOrNewCartItem;
if (state.items[addedProduct.id]) {
updatedOrNewCartItem = new CartItem(
state.items[addedProduct.id].quantity + 1,
prodPrice,
prodTitle,
state.items[addedProduct.id].sum + prodPrice
);
} else {
updatedOrNewCartItem = new CartItem(1, prodPrice, prodTitle, prodPrice);
}
return {
...state,
items: { ...state.items, [addedProduct.id]: updatedOrNewCartItem },
totalAmount: state.totalAmount + prodPrice,
};
case REMOVE_FROM_CART:
const selectedCartItem = state.items[action.pid];
const currentQty = selectedCartItem.quantity;
let updatedCartItems;
if (quantity > 1) {
const updatedCartItem = new CartItem(
selectedCartItem.quantity - 1,
selectedCartItem.productPrice,
selectedCartItem.productTitle,
selectedCartItem.sum - selectedCartItem.productPrice
);
updatedCartItems = { ...state.items, [action.pid]: updatedCartItem };
} else {
updatedCartItems = { ...state.items };
delete updatedCartItems[action.pid];
}
return {
...state,
items: updatedCartItems,
totalAmount: state.totalAmount - selectedCartItem.productPrice,
};
default:
break;
}
return state;
};
In this code, addedProduct.price is in the addToCart() which is working fine. I can add the items in my cart but If I try to remove the item by calling onRemove() then it is giving me above error. I don't why and How to solve this issue?
I was returning the type of action ADD_To_Cart in removeFromCart() that's why I was getting this error.
Before:
export const ADD_TO_CART = "ADD_TO_CART";
export const REMOVE_FROM_CART = "REMOVE_FROM_CART";
export const addToCart = (products) => {
return { type: ADD_TO_CART, product: products };
};
export const removeFromCart = (productId) => {
return { type: ADD_TO_CART, pid: productId };
};
So, I have corrected the type of action returned in the removeFromCart().
export const ADD_TO_CART = "ADD_TO_CART";
export const REMOVE_FROM_CART = "REMOVE_FROM_CART";
export const addToCart = (products) => {
return { type: ADD_TO_CART, product: products };
};
export const removeFromCart = (productId) => {
return { type: REMOVE_FROM_CART, pid: productId };
};
Now It's working fine.