Reputation: 161
Currently in the process of learning React and D3. I have the following code:
App.js
import React, {useRef, useEffect, useState, Component} from 'react';
// import logo from './logo.svg';
import './App.css';
import ChartWrapper from './ChartWrapper'
class App extends Component() {
render() {
return (
<div id="app">
<ChartWrapper data = {[10, 13, 9.5, 11, 12, 14, 8, 13, 15, 14]}/>
</div>
)
}
}
export default App;
ChartWrapper.js
import React, {Component, useEffect, useState} from 'react';
import { useRef } from 'react';
import LineChart from './LineChart'
function ChartWrapper(props) {
const [data, setData] = useState(props.data);
const svgRef = useRef();
//let data = [10, 13, 9.5, 11, 12, 14, 8, 13, 15, 14];
console.log("works");
useEffect( () => {
const chart = new LineChart(svgRef, data);
console.log(data);
}, [data]);
function updateChart(value) {
data.push(value);
}
return (
<div>
<svg ref={svgRef} height = {300} width = {500}></svg>
<button onClick={() => setData(data.map(value => value + 5))}>Update Data</button>
</div>
);
}
export default ChartWrapper;
LineChart.js
import React, {Component} from 'react'
import {line, select, selectAll, axisBottom, ScaleLinear, scaleLinear} from 'd3';
class LineChart {
constructor (parent, data) {
this.svg = select(parent.current);
this.data = data;
this.line = this.getLine();
this.xScale = this.getXScale();
this.yScale = this.getYScale();
// Plot the chart
this.plot();
}
getLine() {
return line()
.x((value, index) => this.xScale(index))
.y(value => this.yScale(value));
}
getXScale() {
return scaleLinear()
.domain([0, this.data.length - 1])
.range([0, this.svg.attr('width')]);
}
getYScale() {
return scaleLinear()
.domain([0, 20])
.range([this.svg.attr('height'), 0]);
}
plot() {
this.svg.selectAll('path')
.data([this.data])
.join('path')
.attr('d', value => this.line(value))
.attr('fill', 'none')
.attr('stroke', 'purple');
}
}
export default LineChart;
I was wondering whether it is possible to somehow call the updateChart() function in 'ChartWrapper.js' from say 'App.js' file since I would like to have the ability to update the chart values on the go (not render the whole page again)?
Say you get live values from a server and need to update the chart realtime, what would be the best way to create a flexible chart component?
Upvotes: 1
Views: 67
Reputation: 399
You can define both the state hook and updateChart
in App.js
, and then pass them down to ChartWrapper.js
as props:
// App.js
import React, { useState } from 'react';
import './App.css';
import ChartWrapper from './ChartWrapper'
const App = () => {
const [data, setData] = useState([10, 13, 9.5, 11, 12, 14, 8, 13, 15, 14]);
function updateChart() {
setData(data.map(value => value + 5));
}
return (
<div id="app">
<ChartWrapper data={data} updateChart={() => updateChart()}/>
</div>
)
}
export default App;
// ChartWrapper.js
import React, { useEffect, useRef } from 'react';
import LineChart from './LineChart'
function ChartWrapper({ data, updateChart }) {
const svgRef = useRef();
//let data = [10, 13, 9.5, 11, 12, 14, 8, 13, 15, 14];
console.log("works");
useEffect( () => {
const chart = new LineChart(svgRef, data);
console.log(data);
}, [data]);
return (
<div>
<svg ref={svgRef} height = {300} width = {500}></svg>
<button onClick={() => updateChart()}>Update Data</button>
</div>
);
}
export default ChartWrapper;
Also note that you should not use .push
on the data
array as you're doing in updateChart
at the moment, but rather use setData
like you're doing in the onClick
callback.
Hope this helps. Good luck!
Upvotes: 2