My Chartjs is not updating after setstate full code attached Reactjs Update

Chartjs is not showing my changes after updating the datasets value. I have the slider controller from material ui. I am using import update from ‘immutability-helper’; to update the state.

<PrettoSlider valueLabelDisplay="auto" aria-label="pretto slider" defaultValue={20} onChange={handleChange}/>

my chart looks like this.

const RadarChart = () => {
const data = {
  datasets: [
    {
      data: [1, 3, 7, 3, 4, 6],
    },
  ],
};
  const [update, setUpdate] = useState(data.datasets[0].data[2]);
  // Initialized a hook to hold the reference to the title div.
  const titleRef = useRef();

  const handleChange = (e, v) => {
    // Imutable Update .. nested Object .. really hard to this manually. 
    const newDate = update(dataState,{
      datasets: {
        data: {$set: v}
      }
    } )
    setDataState(newDate)
    titleRef.current.render();
    titleRef.current.update();
  };

  return (
    <>
      <CustomizedSlider handleChange={handleChange} />
      <Radar ref={titleRef} data={data} />
    </>
  );
};

The slider works and I get the correct values in my handleChange method, so my problem relies with updating the state of the chart itself.

Answer

In ReactJS you need to use the useState() hook for any data (state) you want to update. Something like this:

  const RadarChart = () => {
  const data = {
    datasets: [
      {
        data: [1, 3, 7, 3, 4, 6],
      },
    ],
  }
  const [dataState, setDataState] = useState(data)
  const [update, setUpdate] = useState(data.datasets[0].data[2]);    // <-- Is this necessary? You don't seem to be using it.
  
  const titleRef = useRef();

  const handleChange = (e, v) => {
      // create a copy of the array:
      let newArr = [...dataState.datasets[0].data];
      newArr[2] = v;
      // set state to updated array:
      setDataState(previous => ({
          ...previous,
          datasets: [{data: newArr}]
      }))
      setUpdate(v);     // best to use v here as dataState may not be finished updating, but again, don't know if necessary.
  };

  useEffect(()=>{
    if (titleRef.current) {  
      titleRef.current.render()
      titleRef.current.update()
    }
  }, [dataState])    // moved this update into a `React.useEffect` block, to make sure `dataState` has updated when they are triggered.

  return (
    <>
      <CustomizedSlider handleChange={handleChange} />
      <Radar ref={titleRef} data={dataState} />
    </>
  );
};
 

Another thing you can do is use state for one of the elements of the array, which saves a few lines of code, as the state is an integer and not an object. You would do it like this:

  const RadarChart = () => {
  const [variableState, setVariableState] = useState(7);
  const data = {
    datasets: [
      {
        data: [1, 3, variableState, 3, 4, 6]
      },
    ],
  };
  
  const titleRef = useRef();

  const handleChange = (e, v) => {
      setVariableState(v);
  };

  useEffect(()=>{
    if (titleRef.current) {  
      titleRef.current.render()
      titleRef.current.update()
    }
  }, [variableState])

  return (
    <>
      <CustomizedSlider handleChange={handleChange} />
      <Radar ref={titleRef} data={data} />
    </>
  );
};

This might be trickier depending on how you are getting the data though.

Update to question regarding immutability-helper

At a glance, the problem with immutability-helper, it looks like you are trying to set the value of the array itself to v (v being just a single number). You should be using data instead of dataState in the update method. Also it looks like a different object you are creating. data.datasets was an array before and it is an object in your update. Not exactly sure why you wouldn’t just use the setDataState function in the same ways as above, seems less complicated, and doesn’t require external libraries.

I literally just read the docs myself but you could try something similar to above:

let newArr = [...data.datasets[0].data];
newArr[2] = v;
const newData = update(data,{
      datasets: {$set: [{data: newArr}]}});
setDataState(newData);