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项目,任重而道远
再次感谢~谢谢!
我修复了为 allowChartUpdate 和 immutable[= 添加 True 17=]
<HighchartsReact
ref={chartRef}
highcharts={Highcharts}
options={options}
containerProps={containerProps}
allowChartUpdate={true}
immutable={true}
/>
一开始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项目,任重而道远
再次感谢~谢谢!
我修复了为 allowChartUpdate 和 immutable[= 添加 True 17=]
<HighchartsReact
ref={chartRef}
highcharts={Highcharts}
options={options}
containerProps={containerProps}
allowChartUpdate={true}
immutable={true}
/>