You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React项目生成Nivo饼图时持续出现N.map is not a function错误求助

解决React中Nivo饼图的"N.map is not a function"错误

问题描述

在React项目中尝试生成Nivo饼图,控制台日志确认finalData是包含饼图所需信息的数组,但始终出现"N.map is not a function"错误,无法正常渲染饼图。以下是涉及的两个组件代码:

Pie组件

import { Box } from "@mui/material";
import Header from "../components/Header";
import PieChart from "../components/PieChart";
import { useEffect, useState } from "react";
import { mockDistrictData } from "../data/MockData";

const Pie = () => {
    const [districts, setDistricts] = useState([]);
    const [selectedDistrict, setSelectedDistrict] = useState('');
    const [finalData, setFinalData] = useState([]);
    const lightGreenColor = "hsl(154,52%,45%)";
    const greenColor = "hsl(139,100%,83%)";
    const [isGeneratingChart, setIsGeneratingChart] = useState(false);

    // Fetch data for mechanical bikes
    const fetchMechanicalBikes = (districtName) => {
        const url = `http://localhost:8800/station_status/bikes/mechanical/${districtName}`;
        return fetch(url)
            .then(response => response.json())
            .then(data => {
                // Transform the fetched data and assign random colors
                return data.map(i => ({
                    id: `Mechanical bikes`,
                    label: `Mechanical bikes`,
                    value: i.value,
                    color: lightGreenColor
                }));
            });
    };

    // Fetch data for electronic bikes
    const fetchElectronicBikes = (districtName) => {
        const url = `http://localhost:8800/station_status/bikes/electric/${districtName}`;
        return fetch(url)
            .then(response => response.json())
            .then(data => {
                // Transform the fetched data and assign random colors
                return data.map(item => ({
                    id: `Electronic bikes`,
                    label: `Electronic bikes`,
                    value: item.value,
                    color: greenColor
                }));
            });
    };

    // Combine the fetched data for mechanical and electronic bikes
    const combineFetchedData = async (districtName) => {
        try {
            setIsGeneratingChart(true); // Set the flag to indicate chart generation in progress
            const mechanicalData = await fetchMechanicalBikes(districtName);
            const electronicData = await fetchElectronicBikes(districtName);

            // Combine the two arrays into a single array
            const combinedData = [...mechanicalData, ...electronicData];

            setTimeout(() => {
                setFinalData(combinedData);
                console.log(combinedData); // Print the combined data
                setIsGeneratingChart(false); // Set the flag to indicate chart generation completed
            }, 3000); // 3 seconds delay

            // You can use the combined data for further processing or visualization

        } catch (error) {
            console.error('Error fetching data: ', error);
            setIsGeneratingChart(false); // Set the flag to indicate chart generation completed with an error
        }
    };

    useEffect(() => {
        // Fetch districts
        const fetchDistricts = () => {
            setDistricts(mockDistrictData.map(district => district.district_name));
        };

        fetchDistricts();
    }, []);

    return (
        <Box m="20px">
            <Header title="Pie Chart" subtitle="Electric Bikes & Mechanical Bikes" />
            <Box height="75vh">
                <div>
                    <select value={selectedDistrict} onChange={e => setSelectedDistrict(e.target.value)}>
                        <option value="">Select a district</option>
                        {districts.map(district => (
                            <option key={district} value={district}>{district}</option>
                        ))}
                    </select>
                    <button disabled={isGeneratingChart} onClick={() => combineFetchedData(selectedDistrict)}>
                        {isGeneratingChart ? 'Generating...' : 'Generate Chart'}
                    </button>
                </div>
                {finalData.length > 0 && <PieChart data={finalData} />}
            </Box>
        </Box>
    );
};

export default Pie;

原始PieChart组件

import { ResponsivePie } from "@nivo/pie";
import { tokens } from "../theme";
import { useTheme } from "@mui/material";
const PieChart = (finalData) => {
    const theme = useTheme();
    const colors = tokens(theme.palette.mode);

    return (
        <ResponsivePie
            data={finalData}
            // ...其他配置
        />
    );
};

export default PieChart;

错误原因

PieChart组件的参数接收逻辑错误:React组件的第一个参数是props对象,而非直接传入的data属性。当前代码中finalData实际是包含data字段的props对象,而非数组,导致Nivo的ResponsivePie组件尝试对对象调用map方法,从而抛出错误。

修复方案

修改PieChart组件的参数接收方式,解构出data属性,或者通过props.data获取数组:

修改后的PieChart组件

import { ResponsivePie } from "@nivo/pie";
import { tokens } from "../theme";
import { useTheme } from "@mui/material";

// 解构props获取data
const PieChart = ({ data }) => {
    const theme = useTheme();
    const colors = tokens(theme.palette.mode);

    return (
        <ResponsivePie
            data={data}
            theme={{
                axis: {
                    domain: {
                        line: {
                            stroke: colors.grey[100],
                        },
                    },
                    legend: {
                        text: {
                            fill: colors.grey[100],
                        },
                    },
                    ticks: {
                        line: {
                            stroke: colors.grey[100],
                            strokeWidth: 1,
                        },
                        text: {
                            fill: colors.grey[100],
                        },
                    },
                },
                legends: {
                    text: {
                        fill: colors.grey[100],
                    },
                },
            }}
            margin={{ top: 40, right: 80, bottom: 80, left: 80 }}
            innerRadius={0.5}
            padAngle={0.7}
            cornerRadius={3}
            activeOuterRadiusOffset={8}
            borderColor={{
                from: "color",
                modifiers: [["darker", 0.2]],
            }}
            arcLinkLabelsSkipAngle={10}
            arcLinkLabelsTextColor={colors.grey[100]}
            arcLinkLabelsThickness={2}
            arcLinkLabelsColor={{ from: "color" }}
            enableArcLabels={false}
            arcLabelsRadiusOffset={0.4}
            arcLabelsSkipAngle={7}
            arcLabelsTextColor={{
                from: "color",
                modifiers: [["darker", 2]],
            }}
            defs={[
                {
                    id: "dots",
                    type: "patternDots",
                    background: "inherit",
                    color: "rgba(255, 255, 255, 0.3)",
                    size: 4,
                    padding: 1,
                    stagger: true,
                },
                {
                    id: "lines",
                    type: "patternLines",
                    background: "inherit",
                    color: "rgba(255, 255, 255, 0.3)",
                    rotation: -45,
                    lineWidth: 6,
                    spacing: 10,
                },
            ]}
            legends={[
                {
                    anchor: "bottom",
                    direction: "row",
                    justify: false,
                    translateX: 0,
                    translateY: 56,
                    itemsSpacing: 0,
                    itemWidth: 100,
                    itemHeight: 18,
                    itemTextColor: "#999",
                    itemDirection: "left-to-right",
                    itemOpacity: 1,
                    symbolSize: 18,
                    symbolShape: "circle",
                    effects: [
                        {
                            on: "hover",
                            style: {
                                itemTextColor: "#000",
                            },
                        },
                    ],
                },
            ]}
        />
    );
};

export default PieChart;

或者也可以选择另一种写法:

const PieChart = (props) => {
    const theme = useTheme();
    const colors = tokens(theme.palette.mode);

    return (
        <ResponsivePie
            data={props.data}
            // ...其他配置
        />
    );
};

验证

修改后,ResponsivePie将接收到正确的数组类型数据,即可正常渲染饼图,不会再出现map is not a function错误。

内容的提问来源于stack exchange,提问作者user19292442

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.21 06:38:09