I have a React Component named Chart. I want to render different charts in it based on the prop passed from their parent, but having the exactly same config. What is the best way to do it?
class Chart extends Component {
static propTypes = {
type: PropTypes.string.isRequired
}
state = {
chartData: {
// some data here
}
}
render(){
return(
this.props.type === 'line' ?
{ <Line
data={this.state.chartData}
options={{
title: {
display: true,
text: 'Cities I\'ve lived in',
fontSize: 25
},
legend: {
display: true,
position: 'right',
labels: {
fontColor: '#000'
}
}
}}
/> } : this.props.type === 'bar' ?
{ <Bar
//same stuff here as <Line />
/>
} : this.props.type === 'pie' ?
{ <Pie
//same stuff here as <Line />
/> }
}
);
}
}
Don't think it matters since the question is generic, but I'm using react-chartjs-2 / chart.js 2 library for rendering charts.
Note: I've tried using a variable name in place of Line/Bar/Pie, but it doesn't work if I'm using JSX or rendering a non-html tag. Better ways to solve it while using JSX and non-html tags are also welcome.
答案 0 :(得分:1)
Two things:
switch
instead of if
statements.Your new component, ...chart
are the destructured props. Read more about destructuring on MDN.
// Chart.js - new component
export const Chart = ({ type, ...chart }) => {
switch(type) {
case 'line':
return <Line {...chart} />
case 'bar':
return <Bar {...chart} />
case 'pie':
return <Pie {...chart} />
default:
return null;
}
}
Example usage
// App.js
render() {
return (
<div>
<Chart type="line" options={optionsObject} whateverProp="whatever" />
<Chart type="bar" options={optionsObject} whateverProp="whatever" />
<Chart type="pie" options={optionsObject} whateverProp="whatever" />
</div>
)
}
答案 1 :(得分:0)
import React, { Component } from 'react';
class Chart extends Component {
components = {
Line: Line,
Bar: Bar,
Pie: Pie
};
render() {
const TagName = this.components[this.props.tag || 'Line'];
return
<TagName
data={this.state.chartData}
options={{
title: {
display: true,
text: 'Cities I\'ve lived in',
fontSize: 25
},
legend: {
display: true,
position: 'right',
labels: {
fontColor: '#000'
}
}
}}
/>
}
}
export default Chart;
// Call MyComponent using prop tag with required prop Line or Bar or Pie
<Chart tag='Line' />
NOTE:- You could create it as a stateless functional component as well.
答案 2 :(得分:0)
I prefer to have each chart as a component, so you can do chart's specific configuration in that component and your code will be more close to React codes modularity goal, so for Line chart as example:
class LineChart extends Component {
const chartLegend = {
display: true,
position: 'right',
labels: {
fontColor: '#000'
}};
const chartTitle = {
display: true,
text: 'Cities I\'ve lived in',
fontSize: 25
};
const chartOptions = {
title: chartTitle ,
legend: chartLegend
}
render(){
return(
<Line
data={this.props.chartData}
options={chartOptions }
/>
);
}
}
Now for chat Component as container component you can use switch case or guard conditions as @loelsonk also said, I prefer to have guard conditions besides switch:
class Chart extends Component {
static propTypes = {
type: PropTypes.string.isRequired
}
state = {
chartData: {
// some data here
}
}
render(){
if (this.props.type === 'line')
return <LineChart chartData={...}/>;
if (this.props.type === 'bar')
return <BarChart chartData={...}/>;
if (this.props.type === 'pie')
return <PieChart chartData={...}/>;
}
}
this way you can easily replace any chart implementation any time that needed.