Get TypeError: Cannot read properties of undefined (reading 'forEach') when pass a params

Get TypeError: Cannot read properties of undefined (reading 'forEach') when pass a params

一开始params还没有任何数据(空白数组),但useEffect设置变量后会再次更新。

但是对于我的图表,它给了我这个错误。

TypeError: Cannot read properties of undefined (reading 'forEach')
 52 |   createChart();
 53 | } else {
 54 |   if (props.allowChartUpdate !== false) {
>55 |     if (!props.immutable && chartRef.current) {
    | ^  56 |       chartRef.current.update(
 57 |         props.options,
 58 |         ...(props.updateArgs || [true, true])

我搜索了一些解决方案,他们建议可以使用 allowChartUpdate={false}immutable={false} 来解决问题。在我尝试之后,是的,它确实解决了我的问题,但是我的高图在初始加载时没有显示数据。

我猜是不是params一开始传入了一个空白数组,然后第二次传入了实际值所以导致了这个问题。如果是,重新渲染highchart可以解决问题吗?我该怎么做?

Here就是link,请帮帮我吧。谢谢 muakzzz。

您可以直接将 getRouteData 函数作为初始化函数提供给 useState 挂钩以提供初始状态。只要它不是异步的,它就会为初始渲染提供初始状态,无需使用 useEffect 挂钩来填充状态 after 第一次渲染。

此外,您应该初始化 routeMapData 以默认使用 data 属性 数组,这样您就不会意外地通过未定义的 data 属性,这是您遇到的问题的一部分。

export default function App() {
  const [routeData] = useState(getRouteData()); // <-- initialize state

  const mapStation = () => {
    const routeMapData = {
      data: [], // <-- data array to push into
    };

    if (routeData.length !== 0) {
      for (let i = 0; i < routeData.length; i++) {
        const station = routeData[i].station;

        for (let j = 0; j < station.length; j++) {
          const firstStation = station[j];
          const nextStation = station[j + 1];

          if (nextStation) {
            routeMapData.data.push([ // <-- push into array
              firstStation.stationName,
              nextStation.stationName
            ]);
          }
        }
      }
    }
    return routeMapData;
  };

  const content = (key) => {
    if (key === "map") {
      return <RouteMap mapRouteData={mapStation()} />;
    }

    return null;
  };

  return <Box className="rightPaper center">{content("map")}</Box>;
}

您甚至不需要使用本地状态,因为您可以在 mapStation 效用函数中直接使用从 getRouteData 返回的数组。

export default function App() {
  const mapStation = () => {
    return {
      data: getRouteData().flatMap(({ station }) => {
        return station.reduce((segments, current, i, stations) => {
          if (stations[i + 1]) {
            segments.push([
              current.stationName,
              stations[i + 1].stationName
            ]);
          }
          return segments;
        }, []);
      })
    };
  };

  const content = (key) => {
    if (key === "map") {
      return <RouteMap mapRouteData={mapStation()} />;
    }

    return null;
  };

  return <Box className="rightPaper center">{content("map")}</Box>;
}

感谢您的帮助。我已经设法获得了我想要的输出。问题是,由于父组件中使用了 useEffect,我的父组件首先会将空白数据数组传递到我的 highchart 网络图组件中。之后,他们将另一个包含实际数据的数组传递到我的 highchart 网络图组件中。

import React, {useEffect, useState} from 'react';
import {Box} from "@mui/material";
import RouteMap from "./Content/RouteMap";
import {getRouteData} from "../../../API/RouteDataAPI"
import Timetable from "./Content/Timetable";
import _ from 'lodash';

function RightContent({contentKey}) {

    const [routeData, setRouteData] = useState([]);

    useEffect(() => {
        getRouteData().then(res => setRouteData(res));
    }, [])

    const mapStation = () => {
        let arr = [], allStation = [], routeMapData = {}

        if (routeData.length !== 0) {
            for (let i = 0; i < routeData.length; i++) {
                const station = routeData[i].station;

                for (let j = 0; j < station.length; j++) {
                    const firstStation = station[j];
                    const nextStation = station[j + 1];

                    allStation.push(firstStation.stationName)
                    if (nextStation) {
                        arr.push([firstStation.stationName, nextStation.stationName])
                    }
                }
            }
            routeMapData.data = arr;
            routeMapData.allStation = allStation;
            routeMapData.centralStation = "KL Sentral"
        }

        return routeMapData;
    }

    // const mapStation = () => {
    //     let arr = [];
    //     getRouteData().then(res => {
    //         arr.push(res.flatMap(({station}) => {
    //             return station.reduce((segments, current, i, stations) => {
    //                 if (stations[i + 1]) {
    //                     segments.push(
    //                         current.stationName,
    //                     );
    //                 }
    //                 return segments;
    //             }, []);
    //         }))
    //     })
    //     console.log(arr)
    // }


    const content = (key) => {

        const availableRoute = routeData.map(route => route.routeTitle);

        if (
            key === 'map'
            // && !_.isEmpty(mapStation())
        ){
            // console.log('here', mapRouteData)
            return <RouteMap mapRouteData={mapStation()}/>;
        }
        else if (availableRoute.includes(key)) {
            return <Timetable routeData={routeData} currentRoute={key}/>
        } else {
            return null;
        }

    }

    return (
        <Box className="rightPaper center">
            {content(contentKey)}
        </Box>
    );
}

export default RightContent;

^^^这是我的父组件。^^^ 在那里的 content 变量函数中,我有一个带有所提供要求的 if 语句。如果您尝试取消注释 if 语句中的 lodash(第二个要求),我可以获得我想要的结果。

这是我的高图网络组件。

import React, {useEffect, useRef, useState} from 'react'
import Highcharts from 'highcharts/highstock'
import HighchartsReact from 'highcharts-react-official'
import networkgraph from 'highcharts/modules/networkgraph'

require('highcharts/modules/exporting')(Highcharts);
require('highcharts/modules/export-data')(Highcharts);

if (typeof Highcharts === "object") {
    networkgraph(Highcharts);
}

const RouteMap = ({mapRouteData}) => {

    const [seriesData, setSeriesData] = useState(mapRouteData.data);
    const [centralStation, setCentralStation] = useState(mapRouteData.centralStation);
    const [allStation, setAllStation] = useState(mapRouteData.allStation);

    useEffect(() => {
        setSeriesData(mapRouteData.data);
        setCentralStation(mapRouteData.centralStation);
        setAllStation(mapRouteData.allStation);
    }, [mapRouteData])

    Highcharts.addEvent(
        Highcharts.Series,
        'afterSetOptions',
        function (e) {
            let colors = Highcharts.getOptions().colors,
                i = 0,
                nodes = {};

            if (
                this instanceof Highcharts.seriesTypes.networkgraph &&
                e.options.id === 'lang-tree' &&
                e.options.data !== undefined
            ) {
                let lastSecond = '', arry = []
                e.options.data.forEach(function (link) {

                    if (lastSecond !== link[0]) {
                        nodes[link[0]] = {
                            id: link[0],
                            color: colors[++i]
                        }
                    } else if (lastSecond === link[0]) {
                        nodes[link[0]] = {
                            id: link[0],
                            color: colors[i]
                        }
                        nodes[link[1]] = {
                            id: link[1],
                            color: colors[i]
                        }
                        arry.push(link[0])
                    }
                    lastSecond = link[1];

                });

                const exchangeStation = allStation.filter((item, index) => allStation.indexOf(item) !== index);
                i += 1;
                exchangeStation.forEach((station) => {
                    nodes[station] = {
                        id: station,
                        marker: {
                            radius: 18
                        },
                        name: 'Interchange: ' + station,
                        color: colors[i]
                    }
                })

                nodes[centralStation] = {
                    id: centralStation,
                    name: 'Sentral Station: ' + centralStation,
                    marker: {
                        radius: 25
                    },
                    color: colors[++i]
                }


                e.options.nodes = Object.keys(nodes).map(function (id) {
                    return nodes[id];
                });

            }
        }
    );

    const options = {
        chart: {
            type: 'networkgraph',
        },
        title: {
            text: 'The Route Map'
        },
        caption: {
            text: "Click the button at top right for more options."
        },
        credits: {
            enabled: false
        },
        plotOptions: {
            networkgraph: {
                keys: ['from', 'to'],
                layoutAlgorithm: {
                    enableSimulation: true,
                    // linkLength: 7
                }
            }
        },
        series: [
            {
                link: {
                    width: 4,
                },
                marker: {
                    radius: 10
                },
                dataLabels: {
                    enabled: true,
                    linkFormat: "",
                    allowOverlap: false
                },
                id: "lang-tree",
                data: seriesData
            }
        ]
    };

    return <HighchartsReact
        ref={useRef()}
        containerProps={{style: {height: "100%", width: "100%"}}}
        highcharts={Highcharts}
        options={options}
    />;
}

export default RouteMap;

抱歉,这里的代码很长。顺便说一句,请随时告诉我我可以对我的代码进行的任何改进。初接触react js项目,任重而道远

再次感谢~谢谢!

我修复了为 allowChartUpdateimmutable[= 添加 True 17=]

  <HighchartsReact
            ref={chartRef}
            highcharts={Highcharts}
            options={options}
            containerProps={containerProps}
            allowChartUpdate={true}
            immutable={true}
        />