I am a newbie in React Router and State, i don't know why that my simple D3 Chart not show if i use condition/steps below
Load data on Apps using Promise.all and store in State (the reason i load data in here is because i try to avoid to load data on each chart page)
Call Dashboard page from App with Navigation
First time it will Load the Dashboard page with my BarChart
When i click on next menu to display the BarChart, it does not show
If i click again on the same menu, it will show again my BarChart
Is it because of Async function (Promise.all) ? How to resolve it?
alphabet.csv sample data
letter,frequency A,0.08167
B,0.01492
C,0.02782
D,0.04253
E,0.12702
import React, { useState, useEffect } from 'react';
import * as d3 from 'd3';
import { Route, BrowserRouter as Router } from 'react-router-dom';
import Dashboard from './components/Dashboard';
import Dashboard1 from './components/Dashboard1';
export default function App() {
const [result, setResult] = useState([])
const mydata = () => {
const data = Promise.all([
d3.csv("alphabet.csv", d3.autoType),
]).then((result) => {
setResult([result]);
})
return data
}
useEffect(() => mydata(), []);
return (
<Router>
<Route path="/" exact render={(props) => <Dashboard {...props} data={result} />} />
<Route path="/Dashboard" render={(props) => <Dashboard {...props} data={result} />} />
<Route path="/Dashboard1" render={(props) => <Dashboard {...props} data={result} />} />
</Router>
)
}
import React from 'react';
import clsx from 'clsx';
import { makeStyles } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import Grid from '@material-ui/core/Grid';
import Paper from '@material-ui/core/Paper';
import Toolbar from '@material-ui/core/Toolbar';
import Navigation from './Navigation';
import BarChart from './BarChart';
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
title: {
flexGrow: 1,
},
content: {
flexGrow: 1,
height: '100vh',
overflow: 'auto',
},
container: {
paddingLeft: theme.spacing(2),
paddingTop: theme.spacing(2),
paddingBottom: theme.spacing(2),
paddingRight: theme.spacing(2),
},
paper: {
padding: theme.spacing(2),
display: 'flex',
overflow: 'auto',
flexDirection: 'column',
},
fixedHeight: {
height: 350,
},
}));
export default function Dashboard(props) {
const classes = useStyles();
const fixedHeightPaper = clsx(classes.paper, classes.fixedHeight);
return (
<div className={classes.root}>
<Navigation />
<main className={classes.content}>
<Toolbar />
<div className={classes.appBarSpacer} />
<Container maxWidth="lg" className={classes.container}>
<Grid container spacing={3}>
<Grid item xs={12} md={8} lg={9}>
<Paper className={fixedHeightPaper}>
Dashboard<BarChart data={props.data} />
</Paper>
</Grid>
</Grid>
</Container>
</main>
</div>
)
}
import React from 'react';
import clsx from 'clsx';
import { Link } from 'react-router-dom';
import { makeStyles } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import List from '@material-ui/core/List';
import Typography from '@material-ui/core/Typography';
import Divider from '@material-ui/core/Divider';
import IconButton from '@material-ui/core/IconButton';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import DashboardIcon from '@material-ui/icons/Dashboard';
import BarChartIcon from '@material-ui/icons/BarChart';
const drawerWidth = 55;
const useStyles = makeStyles((theme) => ({
root: {
display: 'flex',
},
toolbar: {
paddingRight: 24, // keep right padding when drawer closed
},
toolbarIcon: {
display: 'flex',
alignItems: 'center',
justifyContent: 'flex-end',
padding: '0 8px',
...theme.mixins.toolbar,
},
appBar: {
zIndex: theme.zIndex.drawer + 1,
transition: theme.transitions.create(['width', 'margin'], {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
},
menuButton: {
marginRight: 36,
},
menuButtonHidden: {
display: 'none',
},
title: {
flexGrow: 1,
},
drawerPaper: {
position: 'relative',
whiteSpace: 'nowrap',
width: drawerWidth,
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.enteringScreen,
}),
},
drawerPaperClose: {
overflowX: 'hidden',
transition: theme.transitions.create('width', {
easing: theme.transitions.easing.sharp,
duration: theme.transitions.duration.leavingScreen,
}),
width: theme.spacing(7),
[theme.breakpoints.up('sm')]: {
width: theme.spacing(7),
},
},
appBarSpacer: theme.mixins.toolbar,
}));
export default function Navigation() {
const classes = useStyles();
return (
<div className={classes.root}>
<AppBar position="absolute" className={clsx(classes.appBar)}>
<Toolbar className={classes.toolbar}>
<Typography component="h1" variant="h6" color="inherit" noWrap className={classes.title}>
Testing
</Typography>
</Toolbar>
</AppBar>
<Drawer
variant="permanent"
classes={{
paper: clsx(classes.drawerPaper, classes.drawerPaperClose),
}}
>
<div className={classes.toolbarIcon}>
<IconButton>
<ChevronLeftIcon />
</IconButton>
</div>
<Divider />
<List>
<ListItem button>
<ListItemIcon>
<Link to='/Dashboard'><DashboardIcon /></Link>
</ListItemIcon>
<ListItemText primary="Dashboard" />
</ListItem>
<ListItem button>
<ListItemIcon>
<Link to='/Dashboard1'><BarChartIcon /></Link>
</ListItemIcon>
<ListItemText primary="Dashboard1" />
</ListItem>
</List>
</Drawer>
</div >
)
}
import React, { useRef } from 'react';
import * as d3 from 'd3';
export default function BarChart(props) {
const ref = useRef();
const pdata = props.data;
const margin = ({ top: 30, right: 30, bottom: 60, left: 100 });
const width = window.innerWidth - margin.right - margin.left;
const height = window.innerHeight - margin.top - margin.bottom + 100;
const color = "steelblue";
if (pdata.length > 0) {
const data = pdata[0];
const x = d3.scaleBand()
.domain(d3.range(data[0].length))
.range([margin.left, width - margin.right])
.padding(0.1);
const xAxis = g => g
.attr("transform", `translate(0,${height - margin.bottom})`)
.call(d3.axisBottom(x).tickFormat(i => data[0][i].letter).tickSizeOuter(0))
.attr('font-size', '18px')
.call(g => g.append("text")
.attr("x", width / 2)
.attr("y", margin.bottom)
.attr("fill", "currentColor")
.text("Letter"));
const y = d3.scaleLinear()
.domain([0, d3.max(data[0], d => d.frequency)]).nice()
.range([height - margin.bottom, margin.top]);
const yAxis = g => g
.attr("transform", `translate(${margin.left},0)`)
.call(d3.axisLeft(y).ticks(20, data.format))
.attr('font-size', '18px')
.call(g => g.append("text")
.attr("transform", "rotate(-90)")
.attr("x", -height / 2)
.attr("y", -margin.left)
.attr("fill", "currentColor")
.text("Frequency"));
const svg = d3.select(ref.current)
.attr("viewBox", [0, 0, width, height]);
svg.append("g")
.call(xAxis);
svg.append("g")
.call(yAxis);
svg.append("g")
.attr("fill", color)
.selectAll("rect")
.data(data[0])
.join("rect")
.attr("x", (d, i) => x(i))
.attr("y", d => y(d.frequency))
.attr("height", d => y(0) - y(d.frequency))
.attr("width", x.bandwidth());
}
return <svg ref={ref} />
}
Not sure if this was answered, but this line
could be the culprit. Is the result already an array? If yes, then just do
because you might not be mapping over the correct data.