Home > Software design >  First value in array is not getting updated
First value in array is not getting updated

Time:12-07

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 Codesandbox

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);
  };

Demo

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.

  • Related