我是 React 路由器和状态的新手,我不知道为什么如果我使用下面的条件/步骤,我的简单 D3 图表不显示
使用 Promise.all 在应用程序上加载数据并存储在 State 中(我在这里加载数据的原因是因为我尽量避免在每个图表页面上加载数据)
使用导航从应用程序调用仪表板页面
第一次它将使用我的条形图加载仪表板页面
当我单击下一个菜单以显示条形图时,它不显示
如果我再次单击同一菜单,它将再次显示我的条形图
是因为异步函数(Promise.all)吗?如何解决?
字母表.csv 样本数据
字母,频率 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} />
}