Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convert react-charts funtion component example to class component

Hey I'm having a lot of trouble trying to implement this example into my React project. The example is different to how I've set mine up and I can't convert it from their way to my way. I have a graph but I really would like the gradient colors to be included. This is as far as I got....

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

The graph works but when I try and add the colors I can't get very far without getting errors. Would love some help.

Thanks

My first error is Error: Invalid hook call. Hooks can only be called inside of the body of a function component. Which is obvious seeing as it's a class component and not a functional on this line const [{ activeSeriesIndex, activeDatumIndex }, setState] = React.useState({

like image 702
MomasVII Avatar asked Jun 22 '21 21:06

MomasVII


People also ask

Can I use React query in class component?

A HOC Utility tool built for react-query, through this you can use react-query hooks to fetch and pass data in your React class based components.

How to convert a function component to a class component in react?

If we want to convert a function component to a class component then we need to make the following major changes. Step 1: Create a React application using the following command: Step 2: After creating your project folder i.e. foldername, move to it using the following command: Project Structure: It will look like the following.

How do you extend a component in react?

If you need to extend a component In Javascript, classes can extend other classes, thus inheriting the parent's prototype. In fact, if you're creating a class component, you have to extend the base component from React. This is more or less not possible with function components, so I wouldn't bother trying

What is the difference between functional components and react functions?

Function components are far less verbose, and require less boilerplate. They're (in my opinion) a bit more flexible with hooks and custom hooks, and they are (usually) a bit more performant. Note: in the examples below, I've shown how to import `React` and `Component`.

What is the difference between props and class components in react?

They both do exactly the same thing. Both components take a prop (name) and render `Hello, {name} `. It's an extremely simple example but already we can see some of the differences. The class component needs to extend the React Component class, and must specify a render method.


Video Answer


2 Answers

Preface

A couple of notes:

  • The conversion to Class Component was more complicated because the React Charts author seems to use and create hooks in a non-standard way. Either they are a genius or they are abusing the the hook system to use it as a glorified computational cache. Or both.
  • The whole React ecosystem is moving to Function Components. Maybe you have a very valid reason to use Class Components (interop with legacy code, I guess?), but if you're only sticking with Class Components simply because that's how you learned React, I strongly suggest that you bite the bullet and run through the Hooks/Function Component sections of the docs. Shouldn't take you long to learn, it will make your life easier, and you will have to do it eventually anyway.

Conversion to Class Component

First, start from the example code in the repo, not the snippet on that page, which already fails to compile.

Next, convert the Function Components one by one and verify each step of the way before you add your own code. I've uploaded my changes to a branch here.

The two custom hooks useLagRadar() and useDemoConfig() used by the example proved to be far too much effort to convert into Class Components, so I simply added them to a Higher-Order Component. To do this, I renamed the MyChart class to MyChartInner and made a new Function Component HOC called MyChart which uses the hooks mentioned above.

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);

To run:

# 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
like image 115
Codebling Avatar answered Oct 20 '22 07:10

Codebling


Hope this is what you were looking for. This is taken from here, as by first glance same as a first comment, but simplifying their version and taking only a few things that are needed for drawing gradient lines.

Here is example in 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);

You can find data.json in codesandbox

Let me know if this works for you.

Edit: Convert it to class component and in a sandbox, I do not get any error

like image 3
pavlovic265 Avatar answered Oct 20 '22 06:10

pavlovic265