I'm building a shopping cart where the user can change the amount they want to invest per asset, and then see how much their investment is worth when compounded 10% over 5 years.
I first have my Checkout component:
import React, { useEffect, useState } from "react";
import CartInner from "./CartInner";
export default function Checkout() {
const [cart, setCart] = useState<any>([
{ price: 2000, id: 1 },
{ price: 4000, id: 2 }
]);
const [projectedGrowth, setProjectedGrowth] = useState<any>([]);
const handleOnChange = (index: any, e: any) => {
const newValue = {
price: Number(e.target.value),
id: index 1,
property_id: index 1
};
const newArray = [...cart];
newArray.splice(index, 1, newValue);
setCart(newArray);
};
const getGrowthAmount = (index: any) => {
console.log(cart[index].price, "default values for price");
const newValue = calcTotalCompoundInterest(cart[index].price, 5, 10);
const newArray = [...projectedGrowth];
newArray.splice(index, 1, newValue);
setProjectedGrowth(newArray);
};
// whenever the cart is updated call the getGrowthAmount function
useEffect(() => {
for (let index = 0; index < cart.length; index ) {
getGrowthAmount(index);
}
}, [cart]);
console.log(projectedGrowth, "projectedGrowth");
console.log(cart, "cart");
return (
<>
<form className="grid gap-8 grid-cols-3">
<div className="col-span-2">
{cart.map((element, index) => {
return (
<fieldset key={index}>
<CartInner
// projectedGrowth={projectedGrowth[index]}
element={element}
handleOnChange={(e) => handleOnChange(index, e)}
defaultValues={cart[index]?.price}
/>
</fieldset>
);
})}
</div>
<button>Proceed to payment</button>
</form>
</>
);
}
Which allows the user to change their investment amount and calculate compound interest:
function calcTotalCompoundInterest(total: any, year: any, rate: any) {
var interest = rate / 100 1;
return parseFloat((total * Math.pow(interest, year)).toFixed(4));
}
My problem is only the second value is getting updated, not the first. E.g if the first input I write 100 and the second 100,000 then the projectedGrowth
array will return:
(2) [6442.04, 16105.1]
Which is correct for the second amount (but not for the first).
Here's the child component:
import PureInput from "./PureInput";
import React, { useEffect, useState, useMemo } from "react";
const CartInner = React.forwardRef(
(
{
handleOnChange,
price,
projectedGrowth,
defaultValues,
id,
...inputProps
}: any,
ref: any
) => {
return (
<input
min={200}
max={price}
handleOnChange={handleOnChange}
type="number"
step={200}
defaultValue={defaultValues}
id={id}
ref={ref}
{...inputProps}
/>
);
}
);
export default CartInner;
What am I doing wrong here?
How can I get the array to return the correct compounded values (both onl oad and Onchange when the user enters into the input)?
CodePudding user response:
Issue is with the splice. accessing the index directly from the array works
const getGrowthAmount = (index: any) => {
console.log(cart[index].price, "default values for price");
const newValue = calcTotalCompoundInterest(cart[index].price, 5, 10);
console.log(newValue, "newValue");
projectedGrowth[index] = newValue;
console.log(projectedGrowth, "list");
setProjectedGrowth(projectedGrowth);
};
CodePudding user response:
The correct code is this one:
import React, { useEffect, useState, useMemo } from "react";
import { useForm, Controller } from "react-hook-form";
import CartInner from "./CartInner";
function calcTotalCompoundInterest(total: any, year: any, rate: any) {
var interest = rate / 100 1;
return parseFloat((total * Math.pow(interest, year)).toFixed(4));
}
export default function Checkout() {
const [cart, setCart] = useState<any>([
{ price: 2000, id: 1 },
{ price: 4000, id: 2 }
]);
const [projectedGrowth, setProjectedGrowth] = useState<any>([]);
const onSubmit = async (data: any) => {};
const handleOnChange = (index: any, e: any) => {
console.log(index);
const newValue = {
price: Number(e.target.value),
id: index 1,
property_id: index 1
};
const newArray = [...cart];
newArray[index] = newValue;
setCart(newArray);
};
const getGrowthAmount = () => {
const newArray = [...projectedGrowth];
for (let index = 0; index < cart.length; index ) {
console.log(index);
//console.log(cart[index].price, "default values for price");
console.log(cart);
const newValue = calcTotalCompoundInterest(cart[index].price, 5, 10);
newArray[index] = newValue;
//newArray.splice(index, 1, newValue);
}
setProjectedGrowth(newArray);
};
// whenever the cart is updated call the getGrowthAmount function
useEffect(() => {
//for (let index = 0; index < cart.length; index ) {
getGrowthAmount();
//}
}, [cart]);
console.log(projectedGrowth, "projectedGrowth");
console.log(cart, "cart");
return (
<>
<form className="grid gap-8 grid-cols-3">
<div className="col-span-2">
{cart.map((element, index) => {
return (
<fieldset key={index}>
<CartInner
// projectedGrowth={projectedGrowth[index]}
element={element}
handleOnChange={(e) => handleOnChange(index, e)}
defaultValues={cart[index]?.price}
/>
</fieldset>
);
})}
</div>
<div className="bg-slate-200 p-8 flex flex-col items-stretch">
<button>Proceed to payment</button>
</div>
</form>
</>
);
}
the error is on the useEffect
function. In your implementation the function on all change call iteratively on the index the getGrowthAmount
function that create a new array each time.
You should call only one time the getGrowthAmount
function and in the cycle value the array at the index of the cycle. Then you can update pass the array to be updated.