Search code examples
javascriptreactjsobjectstate

How to copy an object function when updating nested state


I have two pie charts that display the ratio of completed tasks for a given period, and a number of medals received for the period. The issue is that the state contains a function that is responsible for displaying tooltips when hovering over the charts, and so far the only way I've found to copy that function to the clone of the state, with which the state then gets updated, is by manually copying that function. For example, the function for the completionRateData state looks like this

function(context) {
 let value = context.formattedValue
 let sum = 0
 let dataArr = context.chart.data.datasets[0].data
 dataArr.map(data => {
 sum += Number(data)
})
 let percentage = (value * 100 / sum).toFixed(0) + '%'
 return tasksForPeriod.length ? " " + percentage : ""
}

And this is how I'm currently updating the function in the state

completionRateClone.datasets[0].tooltip.callbacks.label =  function(context) {
      let value = context.formattedValue
      let sum = 0
      let dataArr = context.chart.data.datasets[0].data
      dataArr.map(data => {
          sum += Number(data)
      })
      let percentage = (value * 100 / sum).toFixed(0) + '%'
      return tasksForPeriod.length ? " " + percentage : ""
  }

The update happens in the applyPeriod() function right below the states. Here's the link to the editor https://stackblitz.com/edit/stackblitz-starters-ntdk3g?file=src%2FApp.js


Solution

  • You can directly update your state like the following:

    setCompletionRateData((prevData) => ({
      ...prevData,
      datasets: prevData.datasets.map((dataset) => ({
        ...dataset,
        tooltip: {
          callbacks: {
            label: function (context) {
              let value = context.formattedValue;
              let sum = 0;
              let dataArr = context.chart.data.datasets[0].data;
              dataArr.map((data) => {
                sum += Number(data);
              });
              let percentage = ((value * 100) / sum).toFixed(0) + '%';
              return tasksForPeriod.length ? ' ' + percentage : '';
            },
          },
        },
      })),
    }));