javascriptreactjsreact-hooksaxiosapexcharts

Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'toString') Apexcharts React


I'm relatively new to react and I'm facing some problems with charts, I do have an array of integers and I'm trying to pass this array of integers in the chart component that I have created as prop but I get 2 errors.

1:

Uncaught (in promise) TypeError: Cannot read properties of undefined (reading 'x')
 at t.value (apexcharts.common.js:6:113947)
    at t.value (apexcharts.common.js:6:113596)
    at t.value (apexcharts.common.js:6:120591)
    at t.value (apexcharts.common.js:6:123454)
    at t.value (apexcharts.common.js:15:37106)
    at t.eval [as create] (apexcharts.common.js:6:4473)
    at eval (apexcharts.common.js:15:36106)
    at new Promise (<anonymous>)
    at t.value (apexcharts.common.js:15:21675)
    at r.value (react-apexcharts.min.js:1:2927)
    at safelyCallComponentDidMount (react-dom.development.js:22877:14)
    at reappearLayoutEffectsOnFiber (react-dom.development.js:23531:11)
    at reappearLayoutEffects_complete (react-dom.development.js:24833:7)
    at reappearLayoutEffects_begin (react-dom.development.js:24821:7)
    at commitLayoutEffects_begin (react-dom.development.js:24644:11)
    at commitLayoutEffects (react-dom.development.js:24607:3)
    at commitRootImpl (react-dom.development.js:26818:5)
    at commitRoot (react-dom.development.js:26677:5)
    at finishConcurrentRender (react-dom.development.js:25976:9)
    at performConcurrentWorkOnRoot (react-dom.development.js:25804:7)
    at workLoop (scheduler.development.js:266:34)
    at flushWork (scheduler.development.js:239:14)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js:533:21)

2:

Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'toString')
 at t.value (apexcharts.common.js:6:390713)
    at t.value (apexcharts.common.js:6:387088)
    at t.value (apexcharts.common.js:15:36720)
    at t.eval [as create] (apexcharts.common.js:6:4473)
    at eval (apexcharts.common.js:15:36106)
    at new Promise (<anonymous>)
    at t.value (apexcharts.common.js:15:21675)
    at r.value (react-apexcharts.min.js:1:2927)
    at invokeLayoutEffectMountInDEV (react-dom.development.js:25128:22)
    at invokeEffectsInDev (react-dom.development.js:27346:11)
    at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27322:5)
    at flushPassiveEffectsImpl (react-dom.development.js:27051:5)
    at flushPassiveEffects (react-dom.development.js:26979:14)
    at eval (react-dom.development.js:26764:9)
    at workLoop (scheduler.development.js:266:34)
    at flushWork (scheduler.development.js:239:14)
    at MessagePort.performWorkUntilDeadline (scheduler.development.js:533:21)

Here's where I make the Axios call and I call my component. I want to pass the Array TotalSalesArray to the component.

import Head from 'next/head';
import { Box, Container, Unstable_Grid2 as Grid } from '@mui/material';
import { Layout as DashboardLayout } from 'src/layouts/dashboard/admin/layout';
import axios from 'axios';
import { useEffect, useState } from 'react';
import { TotalSalesChart } from '../../sections/overview/Admin/TotalSalesChart';


const Page = () => {
  const [currentMonth, setCurrentMonth] = useState([]);
  const [data, setData] = useState([]);
  const [totalSalesArray, setTotalSalesArray] = useState([]);

  useEffect(() => {
    axios.get('http://localhost:8001/admin/getSalesPerMonth', { withCredentials: true })
         .then((response) => {

           setCurrentMonth(response.data['currentMonth']);
           setData(response.data['pastMonths']);

         }).catch((error) => {
      console.log(error);
    });
  },[]);
  const totalSales = currentMonth[0]?.totalSales;

  useEffect(() => {
    const salesArray = Object.values(data).map(month => month.totalSales);
    setTotalSalesArray([...salesArray.reverse(), totalSales]);
  }, [data]);
  return (
    <>
      <Head>
        <title>
          Overview
        </title>
      </Head>
      <Box
        component="main"
        sx={{
          flexGrow: 1,
          py: 8
        }}
      >
        <Container maxWidth="xl">
          <Grid
            container
            spacing={3}
          >
            <Grid
              xs={12}
              lg={8}
            >
              <TotalSalesChart
                chartSeries={[
                  {
                    name: 'This year',
                    data: totalSalesArray
                  }
                ]}
              />
            </Grid>
          </Grid>
        </Container>
      </Box>
    </>
  );
};

Page.getLayout = (page) => (
  <DashboardLayout>
    {page}
  </DashboardLayout>
);

export default Page;


Here is the component code itself

import DotsHorizontalIcon from '@untitled-ui/icons-react/build/esm/DotsHorizontal';
import { Box, Card, CardContent, CardHeader, IconButton, SvgIcon } from '@mui/material';
import { useTheme } from '@mui/material/styles';
import { Chart } from '../../../components/chart';
import { Scrollbar } from '../../../components/scrollbar';

const useChartOptions = () => {
  const theme = useTheme();

  return {
    chart: {
      background: 'transparent',
      stacked: false,
      toolbar: {
        show: false
      },
      zoom: {
        enabled: false
      }
    },
    colors: [theme.palette.primary.main],
    dataLabels: {
      enabled: false
    },
    fill: {
      gradient: {
        opacityFrom: 0.4,
        opacityTo: 0.1,
        stops: [0, 100]
      },
      type: 'gradient'
    },
    grid: {
      borderColor: theme.palette.divider,
      strokeDashArray: 2,
      xaxis: {
        lines: {
          show: false
        }
      },
      yaxis: {
        lines: {
          show: true
        }
      }
    },
    markers: {
      size: 6,
      strokeColors: theme.palette.background.default,
      strokeWidth: 3
    },
    stroke: {
      curve: 'smooth'
    },
    theme: {
      mode: theme.palette.mode
    },
    xaxis: {
      axisBorder: {
        show: false
      },
      axisTicks: {
        show: false
      },
      categories: [
        'Jan',
        'Feb',
        'Mar',
        'Apr',
        'May',
        'Jun',
        'Jul',
        'Aug',
        'Sep',
        'Oct',
        'Nov',
        'Dec'
      ],
      labels: {
        offsetY: 5,
        style: {
          colors: theme.palette.text.secondary
        }
      }
    },
    yaxis: {
      labels: {
        formatter: (value) => (value > 0 ? `${value}` : `${value}`),
        offsetX: -10,
        style: {
          colors: theme.palette.text.secondary
        }
      }
    }
  };
};

export const TotalSalesChart = (props) => {
  const { chartSeries } = props;
  const chartOptions = useChartOptions();

  return (
    <Box
      sx={{
        backgroundColor: (theme) => theme.palette.mode === 'dark'
          ? 'neutral.800'
          : 'neutral.100',
        p: 3
      }}
    >
      <Card>
        <CardHeader
          action={(
            <IconButton>
              <SvgIcon>
                <DotsHorizontalIcon/>
              </SvgIcon>
            </IconButton>
          )}
          title="Sales chart"
        />
        <CardContent>
          <Scrollbar>
            <Box
              sx={{
                height: 375,
                minWidth: 500,
                position: 'relative'
              }}
            >
              <Chart
                height={350}
                options={chartOptions}
                series={chartSeries}
                type="area"
              />
            </Box>
          </Scrollbar>
        </CardContent>
      </Card>
    </Box>
  );
};

Here is a sample of totalSalesArray:

[6020, 6890, 600, 600, 60, 60, 60, 750, 750, 7550, 232, 1500]

Solution

  • Issue: Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'toString')

    I encountered a runtime error in my React application with ApexCharts, manifesting as follows:

    Unhandled Runtime Error TypeError: Cannot read properties of undefined (reading 'toString')
     at t.value (apexcharts.common.js:6:390713)
        at t.value (apexcharts.common.js:6:387088)
        at t.value (apexcharts.common.js:15:36720)
        at t.eval [as create] (apexcharts.common.js:6:4473)
        at eval (apexcharts.common.js:15:36106)
        at new Promise (<anonymous>)
        at t.value (apexcharts.common.js:15:21675)
        at r.value (react-apexcharts.min.js:1:2927)
        at invokeLayoutEffectMountInDEV (react-dom.development.js:25128:22)
        at invokeEffectsInDev (react-dom.development.js:27346:11)
        at commitDoubleInvokeEffectsInDEV (react-dom.development.js:27322:5)
        at flushPassiveEffectsImpl (react-dom.development.js:27051:5)
        at flushPassiveEffects (react-dom.development.js:26979:14)
        at eval (react-dom.development.js:26764:9)
        at workLoop (scheduler.development.js:266:34)
        at flushWork (scheduler.development.js:239:14)
        at MessagePort.performWorkUntilDeadline (scheduler.development.js:533:21)
    

    After encountering this error frequently without an apparent cause, I discovered that it was a bug in the ApexCharts library in React. The problem was resolved by upgrading to a version released in 2020. or just by putting width and height to the chart.

    Solution:

    1. Identify the bug in ApexCharts: GitHub Issue #1898

    2. Upgrade ApexCharts in your React project or add a width to the chart. This resolved the issue for me.

    Acknowledgments:

    I want to express my gratitude to @CaseyC, who helped address the initial error. and to all people who took a portion of their time to reply. Additionally, the following code snippet proved helpful in preventing the issue:

    if (!totalSalesArray.length || totalSalesArray == 0 || !totalSalesArray) {
      return null;
    }
    

    This piece of code checks if the totalSalesArray is null or undefined before attempting further operations.

    I will change the title of the question to be more accurate for those who are facing the same problem (bug) in general.

    I hope this information helps others facing a similar problem!