Search code examples
reactjsreact-propsrecharts

Pass props from a parent component to a child component to control the background color in recharts


I am using Recharts to render four area charts in my react project. I have a separate file to render one area chart and then I export it to my main component to be rendered four times with different gradient backgrounds. Here is how I drew my chart :

import React from 'react';
import {
    AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer,
} from 'recharts';

const ResponsiveAreaContainer = (props) => {

    const { backgroundColor, strokeColor } = props;

    const data = [
        {
            name: 'January', uv: 4000, pv: 2400, amt: 2400,
        },
        {
            name: 'February', uv: 3000, pv: 1398, amt: 2210,
        },
        {
            name: 'March', uv: 2000, pv: 9800, amt: 2290,
        },
        {
            name: 'April', uv: 2780, pv: 3908, amt: 2000,
        },
        {
            name: 'May', uv: 1890, pv: 4800, amt: 2181,
        },
        {
            name: 'June', uv: 2390, pv: 3800, amt: 2500,
        },
        {
            name: 'July', uv: 3490, pv: 4300, amt: 2100,
        },
    ];

    const ResponsiveArea = () => (
        <ResponsiveContainer width="100%" height={200}>
            <AreaChart
                data={data}
                margin={{
                    top: 10, right: 30, left: 0, bottom: 0,
                }}
                fontSize={12}
            >
                <defs>
                    <linearGradient id="colorUv" x1="0" y1="0" x2="0" y2="1">
                        <stop offset="5%" stopColor={backgroundColor} stopOpacity={0.8} />
                        <stop offset="95%" stopColor={backgroundColor} stopOpacity={0} />
                    </linearGradient>
                </defs>
                <XAxis dataKey="name" axisLine={false} />
                <YAxis axisLine={false} />
                <Tooltip />
                <Area type="linear" strokeWidth={3} dataKey="uv" stroke={strokeColor} fillOpacity={1} fill="url(#colorUv)" />
            </AreaChart>
        </ResponsiveContainer>
    );

    return (<ResponsiveArea />)
}

export default ResponsiveAreaContainer; 

And, here is my main file where the four charts are rendered :

import React from "react";
import "./styles.css";
import ResponsiveAreaChart from "./areaChart";

export default function App() {
  return (
    <div className="App">
      <h1>Hello CodeSandbox</h1>
      <h2>Start editing to see some magic happen!</h2>
      <div className="branches-charts-container">
        <div className="branches-charts-wrapper">
          <div className="chart-title-wrapper">
            <h3>Total Sales</h3>
          </div>
          <div className="area-chart-wrapper">
            <ResponsiveAreaChart
              backgroundColor="#8884d8"
              strokeColor="#3749A6"
            />
          </div>
        </div>
        <div className="branches-charts-wrapper">
          <div className="chart-title-wrapper">
            <h3>Completed Orders</h3>
          </div>
          <div className="area-chart-wrapper">
            <ResponsiveAreaChart
              backgroundColor="#89F674"
              strokeColor="#00D50E"
            />
          </div>
        </div>
        <div className="branches-charts-wrapper">
          <div className="chart-title-wrapper">
            <h3>Delayed Orders</h3>
          </div>
          <div className="area-chart-wrapper">
            <ResponsiveAreaChart
              backgroundColor="#FFDA9A"
              strokeColor="#FFBF50"
            />
          </div>
        </div>
        <div className="branches-charts-wrapper">
          <div className="chart-title-wrapper">
            <h3>Delayed Orders</h3>
          </div>
          <div className="area-chart-wrapper">
            <ResponsiveAreaChart
              backgroundColor="#FD9C9C"
              strokeColor="#FC5A5A"
            />
          </div>
        </div>
      </div>
    </div>
  );
}

As you can see, I am passing two props from the parent component to the area chart component, the strokeColor and also the backgroundColor. The thing is, when the four charts are rendered, only the strokeColor applied and they all have different colors while the background color doesn't work at all. Why could this happen and how to fix this? Any ideas?

Here is also a link to codesandbox where you can find the project there : https://codesandbox.io/s/modern-cache-m1xln?file=/src/App.js:0-1751

Thanks in advance.


Solution

  • the problem is in the id of gradient definition: id="colorUv", you should pass the id in the props to have a dynamic gradient definition. You should do like this :

    import React from "react";
    import "./styles.css";
    import ResponsiveAreaChart from "./areaChart";
    
    export default function App() {
      return (
        <div className="App">
          <h1>Hello CodeSandbox</h1>
          <h2>Start editing to see some magic happen!</h2>
          <div className="branches-charts-container">
            <div className="branches-charts-wrapper">
              <div className="chart-title-wrapper">
                <h3>Total Sales</h3>
              </div>
              <div className="area-chart-wrapper">
                <ResponsiveAreaChart
                  backgroundColor="#8884d8"
                  strokeColor="#3749A6"
                  id='1'
                />
              </div>
            </div>
            <div className="branches-charts-wrapper">
              <div className="chart-title-wrapper">
                <h3>Completed Orders</h3>
              </div>
              <div className="area-chart-wrapper">
                <ResponsiveAreaChart
                  backgroundColor="#89F674"
                  strokeColor="#00D50E"
                  id='2'
                />
              </div>
            </div>
            <div className="branches-charts-wrapper">
              <div className="chart-title-wrapper">
                <h3>Delayed Orders</h3>
              </div>
              <div className="area-chart-wrapper">
                <ResponsiveAreaChart
                  backgroundColor="#FFDA9A"
                  strokeColor="#FFBF50"
                  id='3'
                />
              </div>
            </div>
            <div className="branches-charts-wrapper">
              <div className="chart-title-wrapper">
                <h3>Delayed Orders</h3>
              </div>
              <div className="area-chart-wrapper">
                <ResponsiveAreaChart
                  backgroundColor="#FD9C9C"
                  strokeColor="#FC5A5A"
                  id='4'
                />
              </div>
            </div>
          </div>
        </div>
      );
    }
    

    and

    import React from 'react';
    import {
        AreaChart, Area, XAxis, YAxis, CartesianGrid, Tooltip, ResponsiveContainer,
    } from 'recharts';
    
    const ResponsiveAreaContainer = (props) => {
    
        const { backgroundColor, strokeColor,id } = props;
    
        const data = [
            {
                name: 'January', uv: 4000, pv: 2400, amt: 2400,
            },
            {
                name: 'February', uv: 3000, pv: 1398, amt: 2210,
            },
            {
                name: 'March', uv: 2000, pv: 9800, amt: 2290,
            },
            {
                name: 'April', uv: 2780, pv: 3908, amt: 2000,
            },
            {
                name: 'May', uv: 1890, pv: 4800, amt: 2181,
            },
            {
                name: 'June', uv: 2390, pv: 3800, amt: 2500,
            },
            {
                name: 'July', uv: 3490, pv: 4300, amt: 2100,
            },
        ];
       const backgroundId = `url(#${id})` ;
        const ResponsiveArea = () => (
            <ResponsiveContainer width="100%" height={200}>
                <AreaChart
                    data={data}
                    margin={{
                        top: 10, right: 30, left: 0, bottom: 0,
                    }}
                    fontSize={12}
                >
                    <defs>
                        <linearGradient id={id} x1="0" y1="0" x2="0" y2="1">
                            <stop offset="5%" stopColor={backgroundColor} stopOpacity={0.8} />
                            <stop offset="95%" stopColor={backgroundColor} stopOpacity={0} />
                        </linearGradient>
                    </defs>
                    <XAxis dataKey="name" axisLine={false} />
                    <YAxis axisLine={false} />
                    <Tooltip />
                    <Area type="linear" strokeWidth={3} dataKey="uv" stroke={strokeColor} fillOpacity={1} fill={backgroundId}/>
                </AreaChart>
            </ResponsiveContainer>
        );
    
        return (<ResponsiveArea />)
    }
    
    export default ResponsiveAreaContainer; 
    

    here is the result: https://codesandbox.io/s/crimson-dawn-7vsdc?fontsize=14&hidenavigation=1&theme=dark