Search code examples
reactjsuse-effect

Unable to update array with Min and Max values


I'm writing a code where I need to get Min and Max values. In my real-time scenario, I've got an SDK to which I make two promise calls and it returns min and max values. I'm trying to mock up the same in my example below. I've got a context in place that is used to store the values. Here is my sample code.

Here is my context:

import React, { useState } from "react";
import { useContext } from "react";

const ProductsContext = React.createContext();

export const ProductsProvider = ({ children }) => {
  const [priceValues, setPriceValues] = useState([0, 0]);
  return (
    <ProductsContext.Provider
      value={{
        priceValues,
        setPriceValues
      }}
    >
      {children}
    </ProductsContext.Provider>
  );
}; 
export const useProductsContext = () => {
  return useContext(ProductsContext);
};

And my code is as below:

import { useEffect } from "react";
import { PriceRange } from "./PriceRange";
import { useProductsContext } from "./ProductsContext";

const ShowRange = () => {
  const { priceValues, setPriceValues } = useProductsContext();

  const getMinVal = () => {
    setPriceValues([Math.random() * 100, priceValues[1]]);
  };

  const getMaxVal = () => {
    setPriceValues([priceValues[0], Math.random() * 100]);
  };

  useEffect(() => {
    getMinVal();
    getMaxVal();
  }, []);

  console.log(JSON.stringify(priceValues));
  return <>{priceValues[0] && priceValues[1] && <PriceRange />}</>;
};

export default ShowRange;

Currently, when I run this, priceValues is of format [0, randomNumber]. And once I get the values.

I'm confused on why only the second value in Array gets updated but not the first. Where am I going wrong?

Here is working code of the same.


Solution

  • Even though getMinVal and getMaxVal are separate functions that update state, they are called at the same time. This is causing the first update to be lost by the second update since priceValues[1] will not be updated until the next render.

    You could solve this by using the function update form of setting state:

      const getMinVal = () => {
        setPriceValues((prev) => ([Math.random() * 100, prev[1]]));
      };
    
      const getMaxVal = () => {
        setPriceValues((prev) => ([prev[0], Math.random() * 100]));
      };