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