6

嘿,我在尝试将这个示例实现到我的 React 项目中时遇到了很多麻烦。该示例与我的设置方式不同,我无法将其从他们的方式转换为我的方式。我有一个图表,但我真的希望包含渐变颜色。这是我所得到的......

import React from 'react'
import { Chart } from 'react-charts'

class GraphClub extends React.Component {
  constructor(props) {
    super(props)

    this.state = {
      chartData: [
        {
          label: 'Won',
          data: [
            [0, 0],
          ],
        },
      ],
    }
  }


  componentDidMount() {
      //Get chartData
  }

  render() {
    return (
      <>
        <Chart
          data={this.state.chartData}
          axes={[
            {
              primary: true,
              type: 'linear',
              position: 'bottom',
              show: this.props.axis,
            },
            {
              type: 'linear',
              position: 'left',
              show: this.props.axis,
            },
          ]}
          series={{ type: 'line', showPoints: false }}
          tooltip
        />
      </>
    )
  }
}

export default GraphClub

该图有效,但是当我尝试添加颜色时,我无法走得很远而不会出错。希望得到一些帮助。

谢谢

我的第一个错误是 Error: Invalid hook call. Hooks can only be called inside of the body of a function component. 这很明显,因为它是一个类组件而不是这一行的功能const [{ activeSeriesIndex, activeDatumIndex }, setState] = React.useState({

4

2 回答 2

5

前言

几点注意事项:

  • 转换为类组件更加复杂,因为 React Charts 作者似乎以非标准方式使用和创建钩子。他们要么是天才,要么滥用钩子系统将其用作美化的计算缓存。或两者。
  • 整个 React 生态系统正在转向功能组件。也许你有一个非常正当的理由使用类组件(我猜是与遗留代码互操作?),但如果你只是因为那是你学习 React 的方式而坚持使用类组件,我强烈建议你硬着头皮跑通过文档的 Hooks/Function Component 部分。不应该花很长时间去学习,它会让你的生活更轻松,而且你最终还是必须这样做。

转换为类组件

首先,从repo中的示例代码开始,而不是该页面上已经无法编译的代码段。

接下来,在添加自己的代码之前,逐个转换函数组件并验证每一步。我已将更改上传到此处的分支

useLagRadar()示例中使用的两个自定义钩子useDemoConfig()被证明要转换为类组件需要付出太多努力,因此我只是将它们添加到高阶组件中。为此,我将 MyChart 类重命名为 MyChartInner 并创建了一个名为 MyChart 的新函数组件 HOC,它使用了上面提到的钩子。

import React from "react";
import ReactDOM from "react-dom";

import { Chart } from "react-charts";

import useDemoConfig from "./useDemoConfig";
import useLagRadar from "./useLagRadar";
import ResizableBox from "./ResizableBox";
import "./styles.css";

export default class App  extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      activeSeriesIndex: -1,
      activeDatumIndex: -1,
    };
  }   
  
  
  render() {
    const {
      activeSeriesIndex, 
      activeDatumIndex,
    } = this.state;

    const setState = newState => this.setState(newState);

    return (
      <div>
        {JSON.stringify({ activeSeriesIndex, activeDatumIndex }, null, 2)}
        <MyChart
          elementType="line"
          setState={setState}
          activeDatumIndex={activeDatumIndex}
          activeSeriesIndex={activeSeriesIndex}
        />
        <MyChart
          elementType="area"
          setState={setState}
          activeDatumIndex={activeDatumIndex}
          activeSeriesIndex={activeSeriesIndex}
        />
        <MyChart
          elementType="bar"
          setState={setState}
          activeDatumIndex={activeDatumIndex}
          activeSeriesIndex={activeSeriesIndex}
        />
      </div>
    );
  }
}

const MyChart = props => {
  useLagRadar();
  // const { data, grouping, randomizeData } = useDemoConfig({
  const demoConfig = useDemoConfig({
    series: 4,
    height: 200,
    grouping: "primary",
    dataType: "ordinal",
    show: ["elementType", "grouping"]
  });
  return (
    <MyChartInner 
      {...demoConfig}
      {...props}
    />
  );
}

class MyChartInner extends React.Component {
  constructor(props) {
    super(props);
  }    

  render() {
    const {
      elementType,
      activeDatumIndex,
      activeSeriesIndex,
      setState
    } = this.props; 

    //useLagRadar();

    
    const { data, grouping, randomizeData } = this.props;
  

    const series = {
      type: elementType
    };

    const axes = [
      {
        primary: true,
        type: "ordinal",
        position: "bottom"
      },
      {
        type: "linear",
        position: "left",
        stacked: true
      }
    ];

    const getSeriesStyle = 
      series => ({
        color: `url(#${series.index % 4})`,
        opacity:
          activeSeriesIndex > -1
            ? series.index === activeSeriesIndex
              ? 1
              : 0.3
            : 1
      });

    const getDatumStyle = 
      datum => ({
        r:
          activeDatumIndex === datum.index &&
          activeSeriesIndex === datum.seriesIndex
            ? 7
            : activeDatumIndex === datum.index
            ? 5
            : datum.series.index === activeSeriesIndex
            ? 3
            : datum.otherHovered
            ? 2
            : 2
      });

    const onFocus = 
      focused =>
        setState({
          activeSeriesIndex: focused ? focused.series.id : -1,
          activeDatumIndex: focused ? focused.index : -1
        });

    return (
      <>
        <button onClick={randomizeData}>Randomize Data</button>
        <br />
        <br />
        <ResizableBox>
          <Chart
            data={data}
            grouping={grouping}
            series={series}
            axes={axes}
            getSeriesStyle={getSeriesStyle}
            getDatumStyle={getDatumStyle}
            onFocus={onFocus}
            tooltip
            renderSVG={() => (
              <defs>
                <linearGradient id="0" x1="0" x2="0" y1="1" y2="0">
                  <stop offset="0%" stopColor="#17EAD9" />
                  <stop offset="100%" stopColor="#6078EA" />
                </linearGradient>
                <linearGradient id="1" x1="0" x2="0" y1="1" y2="0">
                  <stop offset="0%" stopColor="#FCE38A" />
                  <stop offset="100%" stopColor="#F38181" />
                </linearGradient>
                <linearGradient id="2" x1="0" x2="0" y1="1" y2="0">
                  <stop offset="0%" stopColor="#42E695" />
                  <stop offset="100%" stopColor="#3BB2B8" />
                </linearGradient>
                <linearGradient id="3" x1="0" x2="0" y1="1" y2="0">
                  <stop offset="0%" stopColor="#F4Ea0A" />
                  <stop offset="100%" stopColor="#df4081" />
                </linearGradient>
              </defs>
            )}
          />
        </ResizableBox>
      </>
    );
  }
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

跑步:

# Clone the repo and checkout the branch
git clone --branch stackoverflow-q68091135 https://github.com/codebling/react-charts.git

# Switch to the "custom-styles" example directory
cd react-charts/examples/custom-styles/

# Install the dependencies
npm i 

# Run the demo
npm start
于 2021-06-25T07:20:05.617 回答
3

希望这就是你要找的。这是从这里获取的,乍一看与第一条评论相同,但简化了它们的版本并且只采用了绘制渐变线所需的一些东西。

这是codesandbox中的示例

import React from "react";
import ReactDOM from "react-dom";

import { Chart } from "react-charts";

import jsonData from "./data.json";

class GraphClub extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      data: jsonData,
      axes: [
        {
          primary: true,
          type: "ordinal",
          position: "bottom"
        },
        {
          type: "linear",
          position: "left",
          stacked: true
        }
      ]
    };
  }

  getSeriesStyle(series) {
    return {
      color: `url(#${series.index % 4})`,
      opacity: 1
    };
  }

  render() {
    const { data, axes } = this.state;
    return (
      <div style={{ width: "500px", height: "300px" }}>
        <Chart
          data={data}
          axes={axes}
          getSeriesStyle={this.getSeriesStyle}
          tooltip
          renderSVG={() => (
            <defs>
              <linearGradient id="0" x1="0" x2="0" y1="1" y2="0">
                <stop offset="0%" stopColor="#df4081" />
                <stop offset="100%" stopColor="#42E695" />
              </linearGradient>
              <linearGradient id="1" x1="0" x2="0" y1="1" y2="0">
                <stop offset="0%" stopColor="#df4081" />
                <stop offset="100%" stopColor="#42E695" />
              </linearGradient>
              <linearGradient id="2" x1="0" x2="0" y1="1" y2="0">
                <stop offset="0%" stopColor="#df4081" />
                <stop offset="100%" stopColor="#42E695" />
              </linearGradient>
              <linearGradient id="3" x1="0" x2="0" y1="1" y2="0">
                <stop offset="0%" stopColor="#df4081" />
                <stop offset="100%" stopColor="#42E695" />
              </linearGradient>
            </defs>
          )}
        />
      </div>
    );
  }
}

export default function App() {
  return <GraphClub />;
}

const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);

你可以data.json在codesandbox中找到

让我知道这是否适合您。

编辑:将其转换为类组件并在沙箱中,我没有收到任何错误

于 2021-07-01T15:11:19.833 回答