0

I get some data from back-end to show. When I inspect element with React Developer Tools, I can see that data is there but not shown in production. ChartJS version is 3.8, not react-chartjs

I was having the same problem in development, too, but solved it by setting a unique key with key={Math.random()}. In development build, it works just fine. Problem occurs in production. I deploy my app on Firebase.

I wait for data before rendering: {isAnyFetching ? "Loading..." : <BarChart01 data={chartData} width={595} height={248} key={Math.random()} />}

I tried giving an array of zeroes until data is loaded to be sure chartData changed to trigger re-render by changing the state of the chart component. I also tried giving an extraKey prop and change it with useEffect to re-render again.

The whole chart component is:

function BarChart01({
  data,
  width,
  height
}) {

  const canvas = useRef(null);
  const legend = useRef(null);

  useEffect(() => {
    const ctx = canvas.current;
    // eslint-disable-next-line no-unused-vars
    const chart = new Chart(ctx, {
      type: 'bar',
      data: data,
      options: {
        layout: {
          padding: {
            top: 12,
            bottom: 16,
            left: 20,
            right: 20,
          },
        },
        scales: {
          y: {
            grid: {
              drawBorder: false,
            },
            ticks: {
              maxTicksLimit: 6,
              callback: (value) => formatValue(value),
            },
          },
          x: {
            type: 'time',
            time: {
              parser: 'MM-DD-YYYY',
              unit: 'month',
              displayFormats: {
                month: 'MMM YY',
              },
            },
            grid: {
              display: false,
              drawBorder: false,
            },
          },
        },
        plugins: {
          legend: {
            display: true,
          },
          tooltip: {
            callbacks: {
              title: () => false, // Disable tooltip title
              label: (context) => formatValue(context.parsed.y),
            },
          },
        },
        interaction: {
          intersect: false,
          mode: 'nearest',
        },
        animation: {
          duration: 500,
        },
        maintainAspectRatio: false,
        resizeDelay: 200,
      },
      plugins: [{
        id: 'htmlLegend',
        afterUpdate(c, args, options) {
          const ul = legend.current;
          if (!ul) return;
          // Remove old legend items
          while (ul.firstChild) {
            ul.firstChild.remove();
          }
          // Reuse the built-in legendItems generator
          const items = c.options.plugins.legend.labels.generateLabels(c);
          items.forEach((item) => {
            const li = document.createElement('li');
            li.style.marginRight = tailwindConfig().theme.margin[4];
            // Button element
            const button = document.createElement('button');
            button.style.display = 'inline-flex';
            button.style.alignItems = 'center';
            button.style.opacity = item.hidden ? '.3' : '';
            button.onclick = () => {
              c.setDatasetVisibility(item.datasetIndex, !c.isDatasetVisible(item.datasetIndex));
              c.update();
            };
            // Color box
            const box = document.createElement('span');
            box.style.display = 'block';
            box.style.width = tailwindConfig().theme.width[3];
            box.style.height = tailwindConfig().theme.height[3];
            box.style.borderRadius = tailwindConfig().theme.borderRadius.full;
            box.style.marginRight = tailwindConfig().theme.margin[2];
            box.style.borderWidth = '3px';
            box.style.borderColor = item.fillStyle;
            box.style.pointerEvents = 'none';
            // Label
            const labelContainer = document.createElement('span');
            labelContainer.style.display = 'flex';
            labelContainer.style.alignItems = 'center';
            const value = document.createElement('span');
            value.style.color = tailwindConfig().theme.colors.slate[800];
            value.style.fontSize = tailwindConfig().theme.fontSize['3xl'][0];
            value.style.lineHeight = tailwindConfig().theme.fontSize['3xl'][1].lineHeight;
            value.style.fontWeight = tailwindConfig().theme.fontWeight.bold;
            value.style.marginRight = tailwindConfig().theme.margin[2];
            value.style.pointerEvents = 'none';
            const label = document.createElement('span');
            label.style.color = tailwindConfig().theme.colors.slate[500];
            label.style.fontSize = tailwindConfig().theme.fontSize.sm[0];
            label.style.lineHeight = tailwindConfig().theme.fontSize.sm[1].lineHeight;
            const theValue = c.data.datasets[item.datasetIndex].data.reduce((a, b) => a + b, 0);
            const valueText = document.createTextNode(formatValue(theValue));
            const labelText = document.createTextNode(item.text);
            value.appendChild(valueText);
            label.appendChild(labelText);
            li.appendChild(button);
            button.appendChild(box);
            button.appendChild(labelContainer);
            labelContainer.appendChild(value);
            labelContainer.appendChild(label);
            ul.appendChild(li);
          });
        },
      }],
    });
    chart.update();
    return () => chart.destroy();
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [data]); 

  return (
    <>
      <div className="px-5 py-3">
        <ul ref={legend} className="flex flex-wrap"></ul>
      </div>
      <div className="grow">
        <canvas ref={canvas} width={width} height={height}></canvas>
      </div>
    </>
  );
}

According to the code, it seems like

button.onclick = () => {
              c.setDatasetVisibility(item.datasetIndex,!c.isDatasetVisible(item.datasetIndex));
              c.update();
        };

part in forEach loop is responsible of this update operation when I click on a label. So it somehow doesn't call update function in production as it should as useEffect listens to data prop.

0 Answers0