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

React18中Nivo ResponsiveBar图表渲染异常问题求助

原因分析

  1. React 18并发渲染适配问题:Nivo的ResponsiveBar组件尚未完全适配React 18的并发渲染机制,组件初始化时无法正确获取容器尺寸,导致布局计算错误。
  2. 响应式尺寸计算时机偏差:Responsive组件依赖容器宽高渲染,首次加载或路由切换后,容器尺寸未稳定就触发渲染,导致条形图布局异常。
  3. 热更新同步渲染特性:修改代码触发热更新时,组件处于同步渲染模式,尺寸计算时机准确,因此图表能正常显示。

修复方案

方案1:强制同步渲染

利用useSyncExternalStore强制组件以同步模式渲染,避开React 18并发特性带来的兼容性问题:

import { useSyncExternalStore } from 'react';
import { ResponsiveBar } from '@nivo/bar';

const data = [/* 保持原有数据 */];

const FPPTBarChart = () => {
  // 强制同步渲染,确保尺寸计算时机正确
  useSyncExternalStore(() => () => {}, () => null);

  return (
    <ResponsiveBar 
      // 保留原有所有props
      data={data}
      keys={["degress"]}
      indexBy="day"
      margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
      padding={0.4}
      valueScale={{ type: "linear" }}
      colors="#3182CE"
      animate={true}
      enableLabel={false}
      axisTop={null}
      axisRight={null}
      axisLeft={{
        tickSize: 5,
        tickPadding: 5,
        tickRotation: 0,
        legend: "degrees",
        legendPosition: "middle",
        legendOffset: -40
      }}
    />
  );
};

export default FPPTBarChart;

方案2:手动触发重渲染

监听路由切换或窗口 resize 事件,通过修改组件key触发重渲染,确保尺寸计算正确:

import { useEffect, useState } from 'react';
import { useLocation } from 'react-router-dom';
import { ResponsiveBar } from '@nivo/bar';

const data = [/* 保持原有数据 */];

const FPPTBarChart = () => {
  const [renderKey, setRenderKey] = useState(0);
  const location = useLocation();

  // 路由切换时触发重渲染
  useEffect(() => {
    setRenderKey(prev => prev + 1);
  }, [location.pathname]);

  // 可选:监听窗口尺寸变化
  useEffect(() => {
    const handleResize = () => setRenderKey(prev => prev + 1);
    window.addEventListener('resize', handleResize);
    return () => window.removeEventListener('resize', handleResize);
  }, []);

  return (
    <div key={renderKey}>
      <ResponsiveBar 
        // 保留原有所有props
        data={data}
        keys={["degress"]}
        indexBy="day"
        margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
        padding={0.4}
        valueScale={{ type: "linear" }}
        colors="#3182CE"
        animate={true}
        enableLabel={false}
        axisTop={null}
        axisRight={null}
        axisLeft={{
          tickSize: 5,
          tickPadding: 5,
          tickRotation: 0,
          legend: "degrees",
          legendPosition: "middle",
          legendOffset: -40
        }}
      />
    </div>
  );
};

export default FPPTBarChart;

方案3:使用固定尺寸的Bar组件

如果不需要完全响应式,直接使用非Responsive版本的Bar组件,手动指定宽高:

import { Bar } from '@nivo/bar';

const data = [/* 保持原有数据 */];

const FPPTBarChart = () => {
  return (
    <Bar 
      width={800}
      height={500}
      // 保留原有所有props
      data={data}
      keys={["degress"]}
      indexBy="day"
      margin={{ top: 50, right: 130, bottom: 50, left: 60 }}
      padding={0.4}
      valueScale={{ type: "linear" }}
      colors="#3182CE"
      animate={true}
      enableLabel={false}
      axisTop={null}
      axisRight={null}
      axisLeft={{
        tickSize: 5,
        tickPadding: 5,
        tickRotation: 0,
        legend: "degrees",
        legendPosition: "middle",
        legendOffset: -40
      }}
    />
  );
};

export default FPPTBarChart;

是否需要更换替代库?

优先尝试上述修复方案,因为你已经在使用其他Nivo组件,保持技术栈一致性能降低维护成本。

如果修复后仍存在兼容性问题,再考虑更换:

  • react-chart-js-2:基于Chart.js,生态成熟,React 18兼容性好,但API风格与Nivo差异较大,需要重新学习
  • Recharts:轻量型React图表库,适配React 18,API设计简洁,迁移成本较低

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.23 06:18:20