Javascript 具有路由的React update API调用

Javascript 具有路由的React update API调用,javascript,reactjs,variables,components,Javascript,Reactjs,Variables,Components,我在学习如何反应。我的第一个web应用程序是一个简单的页面,它请求API Covid-19有关美国的数据,并将其分类显示。我使用react router来显示相同的卡组件,并使用dataFinal变量传递不同的数据,该变量保存API检索到的json。如果我要访问其中一个不在家的类别,例如,/positiveIncrease,我会得到一个错误: Error in /~/index.js (46:255) Cannot read property 'positiveIncrease' of unde

我在学习如何反应。我的第一个web应用程序是一个简单的页面,它请求API Covid-19有关美国的数据,并将其分类显示。我使用react router来显示相同的卡组件,并使用
dataFinal
变量传递不同的数据,该变量保存API检索到的json。如果我要访问其中一个不在家的类别,例如,
/positiveIncrease
,我会得到一个错误:

Error in /~/index.js (46:255)
Cannot read property 'positiveIncrease' of undefined
我从错误中推断,渲染发生在API从json获取数据并将其存储在对象中之前。为了解决这个问题,我尝试在卡片组件的内容部分
dataFinal.hospitalizedCurrent?中使用JSX进行条件呈现?dataFinal.HospitalizedCurrent:“正在加载…”

然而,这似乎不起作用。我还尝试创建一个布尔变量来保存API调用是否已完成,但它也不起作用

Stackblitz上的应用程序链接为:

编辑:

视图:

要显示的默认文件:index.js

  • 要复制问题,只需在菜单中导航到 与主页不同的随机类别并重新加载页面
API.js

import React from 'react';
let loaded=false;
let dataFinal;
 fetch("https://api.covidtracking.com/v1/us/current.json")
 .then(data=>data.json())
 .then(data=>{
     dataFinal=data[0]
  })



export {dataFinal}
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import { title, content } from "./Routing.js";

export default function Card(props) {
  return (
    <Card className="card">
      <CardContent>
        <Typography color="textSecondary" gutterBottom>
          {props.title}
        </Typography>
        <Typography variant="h5" component="h2">
          {props.content}
        </Typography>
      </CardContent>
      <CardActions>
        <Button
          onClick={() => {
            window.location = "https://www.cdc.gov/covid-data-tracker/#cases";
          }}
          size="small"
        >
          Learn More
        </Button>
        <br />
      </CardActions>
     { typeof props.content === "string" || props.content instanceof String ? "" : <CardContent>
        <p style={{ color: "red" }}>{repeat(props.content)}</p>
      </CardContent>}
    </Card>
  );
}
export { Content, Title };

const repeat = num => {
  if (typeof num === "string" || num instanceof String) {
    return "";
  }
  if (num < 2000) {
    return "♥ ".repeat(num);
  } else {
    return "♥ ".repeat(2000) + " and " + (num - 2000) + " more";
  }
};
import React, { Component} from 'react';
import {render} from 'react-dom';
import './style.css';
import {dataFinal, loaded} from "./API.js"
import Routing from "./Routing.js"
import Card from "./Card.js"
import { BrowserRouter, Route, Switch } from 'react-router-dom';
class App extends Component {
    render() {
      return(
        <div> <Routing/>
        <main>
            <Switch>
             <Route exact path="/" render={()=> <Card title={''} content={"Navigate through the menus on the top left"} />}> 
                </Route>
                <Route exact path="/positive" render={()=><Card title={'Positive'} content={dataFinal.positive ? dataFinal.positive : "Loading..."} />}> 
                </Route>
                 <Route exact path="/positiveIncrease" render={()=> <Card title={'Positive increase'} content={dataFinal.positiveIncrease ? dataFinal.positiveIncrease : "Loading..."} />}> 
                </Route>
                <Route exact path="/hospitalized" render={()=> <Card title={'Hospitalized'} content={dataFinal.hospitalized ? dataFinal.hospitalized : "Loading..."}/>}> 
                </Route>
                 <Route exact path="/hospitalizedCurrently" render={()=> <Card title={'Hospitalized currently'} content={dataFinal.hospitalizedCurrently ? dataFinal.hospitalizedCurrently : "Loading..." }/>}> 
                </Route>
                  <Route exact path="/dead" render={()=> <Card title={'Total dead'} content={dataFinal.death ? dataFinal.death : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/icu" render={()=> <Card title={'Currently in intensive care unit'} content={dataFinal.inIcuCurrently ? dataFinal.inIcuCurrently : "Loading..." }/>}> 
                                 </Route>
                 <Route exact path="/culminativeicu" render={()=> <Card title={'Culminative in intensive care unit'} content={dataFinal.inIcuCumulative ? dataFinal.inIcuCumulative : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/onventillatorsculminative" render={()=> <Card title={'Culminative on ventillators'} content={dataFinal.onVentilatorCumulative ? dataFinal.onVentilatorCumulative : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/onventillatorscurrently" render={()=> <Card title={'Currently on ventillators'} content={dataFinal.onVentilatorCurrently ? dataFinal.onVentilatorCurrently : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/recovered" render={()=> <Card title={'Recovered'} content={dataFinal.recovered ? dataFinal.recovered : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/deadIncrease" render={()=> <Card title={'Dead Increase'} content={dataFinal.deathIncrease ? dataFinal.deathIncrease : "Loading..." }/>}> 
                 </Route>
                  <Route exact path="/hospitalizedIncrease" render={()=> <Card title={'Hospitalized increase'} content={dataFinal.deathIncrease ? dataFinal.deathIncrease : "Loading..." }/>}> 
                 </Route>
            </Switch>
        </main>
        </div>
        )  
    }
}


render( <BrowserRouter>
        <App /> 
    </BrowserRouter>, document.getElementById('root'));
import React from 'react';
import clsx from 'clsx';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import CssBaseline from '@material-ui/core/CssBaseline';
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 MenuIcon from '@material-ui/icons/Menu';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import {Content,Title} from "./Card.js"
import { BrowserRouter, Route, Switch,Link } from 'react-router-dom';
import ReplayIcon from '@material-ui/icons/Replay';
import Box from '@material-ui/core/Box';
import {retrieve} from "./API"
import 'fontsource-roboto';
const drawerWidth = 200;

const useStyles = makeStyles((theme) => ({
  root: {
    display: 'flex',
  },
  appBar: {
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
  },
  appBarShift: {
    width: `calc(100% - ${drawerWidth}px)`,
    marginLeft: drawerWidth,
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
  },
  menuButton: {
    marginRight: theme.spacing(2),
  },
  hide: {
    display: 'none',
  },
  drawer: {
    width: drawerWidth,
    flexShrink: 0,
  },
  drawerPaper: {
    width: drawerWidth,
  },
  drawerHeader: {
    display: 'flex',
    alignItems: 'center',
    padding: theme.spacing(0, 1),
    // necessary for content to be below app bar
    ...theme.mixins.toolbar,
    justifyContent: 'flex-end',
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
    marginLeft: -drawerWidth,
  },
  contentShift: {
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
    marginLeft: 0,
  },
}));

export default function PersistentDrawerLeft() {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(false);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <div className={classes.root}>
      <CssBaseline />
      <AppBar
        position="fixed"
        className={clsx(classes.appBar, {
          [classes.appBarShift]: open,
        })}
      >
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="Open drawer"
            onClick={handleDrawerOpen}
            edge="start"
            className={clsx(classes.menuButton, open && classes.hide)}
          >
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" noWrap>
USA Covid-19 Visualization          
</Typography>
        </Toolbar>
      </AppBar>
      <Drawer
        className={classes.drawer}
        anchor="bottom"
        open={open}
        classes={{
          paper: classes.drawerPaper,
        }}
      >
        <div className={classes.drawerHeader}>
          <IconButton onClick={handleDrawerClose}>
            {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
          </IconButton>
        </div>
        <Divider />
        <List>
        <Link onClick={()=>setOpen(false)} style={{textDecoration:"none",color:"black"}} to="/">  <ListItem  button key={"Home"}>
              <ListItemText  primary={"Home"} />
            </ListItem> </Link>
            <Divider />
          <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}} to="/positive">  <ListItem  button key={"Positive"}>
              <ListItemText  primary={"Positive"} />
            </ListItem> </Link>
             <Link onClick={()=>setOpen(false)} style={{textDecoration:"none",color:"black"}} to="/positiveIncrease">  <ListItem  button key={"PositiveIncrease"}>
              <ListItemText  primary={"Positive increase"} />
            </ListItem> </Link>
            <Divider />
         <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalized">   <ListItem  button key={"Hospitalized"}>
              <ListItemText primary={"Hospitalized culminative"} />
            </ListItem></Link>
            <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalizedCurrently">  <ListItem  button key={"hospitalizedCurrently"}>
              <ListItemText primary={"Hospitalized currently"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalizedIncrease">  <ListItem  button key={"hospitalizedIncrease"}>
              <ListItemText primary={"Hospitalized increase"} />
            </ListItem></Link>
                        <Divider />

           <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/dead">  <ListItem  button key={"Dead"}>
              <ListItemText primary={"Dead Culminative"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/deadIncrease">  <ListItem  button key={"DeadIncrease"}>
              <ListItemText primary={"Dead increase"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/icu">  <ListItem  button key={"Icu"}>
              <ListItemText primary={"Currently in ICU"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/culminativeicu">  <ListItem  button key={"culminativeIcu"}>
              <ListItemText primary={"In ICU culminative"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/onventillatorsculminative">  <ListItem  button key={"onventillatorsculminative"}>
              <ListItemText primary={"On ventillators culminative"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/onventillatorscurrently">  <ListItem  button key={"onventillatorscurrently"}>
              <ListItemText primary={"On ventillators currently"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/recovered">  <ListItem  button key={"recovered"}>
              <ListItemText primary={"Recovered"} />
            </ListItem></Link>
            <Divider />
            <center><Typography  style={{color:"grey",fontSize:"1vmax",marginTop:"1.5vmax",marginBottom:"1vmax"}} >Created by Atanas Bobev</Typography></center>
        </List>
      </Drawer>
      <main
        className={clsx(classes.content, {
          [classes.contentShift]: open,
        })}
      >
   
      </main>
    </div>
  );
  
}
h1, p {
  font-family: Lato;
}
.card{
  width:90vw;
  margin-left:5vw;
  margin-top:5vw;
}
Link{
  color:black;
  text-decoration:none;
}
Card.js

import React from 'react';
let loaded=false;
let dataFinal;
 fetch("https://api.covidtracking.com/v1/us/current.json")
 .then(data=>data.json())
 .then(data=>{
     dataFinal=data[0]
  })



export {dataFinal}
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import { title, content } from "./Routing.js";

export default function Card(props) {
  return (
    <Card className="card">
      <CardContent>
        <Typography color="textSecondary" gutterBottom>
          {props.title}
        </Typography>
        <Typography variant="h5" component="h2">
          {props.content}
        </Typography>
      </CardContent>
      <CardActions>
        <Button
          onClick={() => {
            window.location = "https://www.cdc.gov/covid-data-tracker/#cases";
          }}
          size="small"
        >
          Learn More
        </Button>
        <br />
      </CardActions>
     { typeof props.content === "string" || props.content instanceof String ? "" : <CardContent>
        <p style={{ color: "red" }}>{repeat(props.content)}</p>
      </CardContent>}
    </Card>
  );
}
export { Content, Title };

const repeat = num => {
  if (typeof num === "string" || num instanceof String) {
    return "";
  }
  if (num < 2000) {
    return "♥ ".repeat(num);
  } else {
    return "♥ ".repeat(2000) + " and " + (num - 2000) + " more";
  }
};
import React, { Component} from 'react';
import {render} from 'react-dom';
import './style.css';
import {dataFinal, loaded} from "./API.js"
import Routing from "./Routing.js"
import Card from "./Card.js"
import { BrowserRouter, Route, Switch } from 'react-router-dom';
class App extends Component {
    render() {
      return(
        <div> <Routing/>
        <main>
            <Switch>
             <Route exact path="/" render={()=> <Card title={''} content={"Navigate through the menus on the top left"} />}> 
                </Route>
                <Route exact path="/positive" render={()=><Card title={'Positive'} content={dataFinal.positive ? dataFinal.positive : "Loading..."} />}> 
                </Route>
                 <Route exact path="/positiveIncrease" render={()=> <Card title={'Positive increase'} content={dataFinal.positiveIncrease ? dataFinal.positiveIncrease : "Loading..."} />}> 
                </Route>
                <Route exact path="/hospitalized" render={()=> <Card title={'Hospitalized'} content={dataFinal.hospitalized ? dataFinal.hospitalized : "Loading..."}/>}> 
                </Route>
                 <Route exact path="/hospitalizedCurrently" render={()=> <Card title={'Hospitalized currently'} content={dataFinal.hospitalizedCurrently ? dataFinal.hospitalizedCurrently : "Loading..." }/>}> 
                </Route>
                  <Route exact path="/dead" render={()=> <Card title={'Total dead'} content={dataFinal.death ? dataFinal.death : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/icu" render={()=> <Card title={'Currently in intensive care unit'} content={dataFinal.inIcuCurrently ? dataFinal.inIcuCurrently : "Loading..." }/>}> 
                                 </Route>
                 <Route exact path="/culminativeicu" render={()=> <Card title={'Culminative in intensive care unit'} content={dataFinal.inIcuCumulative ? dataFinal.inIcuCumulative : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/onventillatorsculminative" render={()=> <Card title={'Culminative on ventillators'} content={dataFinal.onVentilatorCumulative ? dataFinal.onVentilatorCumulative : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/onventillatorscurrently" render={()=> <Card title={'Currently on ventillators'} content={dataFinal.onVentilatorCurrently ? dataFinal.onVentilatorCurrently : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/recovered" render={()=> <Card title={'Recovered'} content={dataFinal.recovered ? dataFinal.recovered : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/deadIncrease" render={()=> <Card title={'Dead Increase'} content={dataFinal.deathIncrease ? dataFinal.deathIncrease : "Loading..." }/>}> 
                 </Route>
                  <Route exact path="/hospitalizedIncrease" render={()=> <Card title={'Hospitalized increase'} content={dataFinal.deathIncrease ? dataFinal.deathIncrease : "Loading..." }/>}> 
                 </Route>
            </Switch>
        </main>
        </div>
        )  
    }
}


render( <BrowserRouter>
        <App /> 
    </BrowserRouter>, document.getElementById('root'));
import React from 'react';
import clsx from 'clsx';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import CssBaseline from '@material-ui/core/CssBaseline';
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 MenuIcon from '@material-ui/icons/Menu';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import {Content,Title} from "./Card.js"
import { BrowserRouter, Route, Switch,Link } from 'react-router-dom';
import ReplayIcon from '@material-ui/icons/Replay';
import Box from '@material-ui/core/Box';
import {retrieve} from "./API"
import 'fontsource-roboto';
const drawerWidth = 200;

const useStyles = makeStyles((theme) => ({
  root: {
    display: 'flex',
  },
  appBar: {
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
  },
  appBarShift: {
    width: `calc(100% - ${drawerWidth}px)`,
    marginLeft: drawerWidth,
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
  },
  menuButton: {
    marginRight: theme.spacing(2),
  },
  hide: {
    display: 'none',
  },
  drawer: {
    width: drawerWidth,
    flexShrink: 0,
  },
  drawerPaper: {
    width: drawerWidth,
  },
  drawerHeader: {
    display: 'flex',
    alignItems: 'center',
    padding: theme.spacing(0, 1),
    // necessary for content to be below app bar
    ...theme.mixins.toolbar,
    justifyContent: 'flex-end',
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
    marginLeft: -drawerWidth,
  },
  contentShift: {
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
    marginLeft: 0,
  },
}));

export default function PersistentDrawerLeft() {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(false);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <div className={classes.root}>
      <CssBaseline />
      <AppBar
        position="fixed"
        className={clsx(classes.appBar, {
          [classes.appBarShift]: open,
        })}
      >
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="Open drawer"
            onClick={handleDrawerOpen}
            edge="start"
            className={clsx(classes.menuButton, open && classes.hide)}
          >
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" noWrap>
USA Covid-19 Visualization          
</Typography>
        </Toolbar>
      </AppBar>
      <Drawer
        className={classes.drawer}
        anchor="bottom"
        open={open}
        classes={{
          paper: classes.drawerPaper,
        }}
      >
        <div className={classes.drawerHeader}>
          <IconButton onClick={handleDrawerClose}>
            {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
          </IconButton>
        </div>
        <Divider />
        <List>
        <Link onClick={()=>setOpen(false)} style={{textDecoration:"none",color:"black"}} to="/">  <ListItem  button key={"Home"}>
              <ListItemText  primary={"Home"} />
            </ListItem> </Link>
            <Divider />
          <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}} to="/positive">  <ListItem  button key={"Positive"}>
              <ListItemText  primary={"Positive"} />
            </ListItem> </Link>
             <Link onClick={()=>setOpen(false)} style={{textDecoration:"none",color:"black"}} to="/positiveIncrease">  <ListItem  button key={"PositiveIncrease"}>
              <ListItemText  primary={"Positive increase"} />
            </ListItem> </Link>
            <Divider />
         <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalized">   <ListItem  button key={"Hospitalized"}>
              <ListItemText primary={"Hospitalized culminative"} />
            </ListItem></Link>
            <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalizedCurrently">  <ListItem  button key={"hospitalizedCurrently"}>
              <ListItemText primary={"Hospitalized currently"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalizedIncrease">  <ListItem  button key={"hospitalizedIncrease"}>
              <ListItemText primary={"Hospitalized increase"} />
            </ListItem></Link>
                        <Divider />

           <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/dead">  <ListItem  button key={"Dead"}>
              <ListItemText primary={"Dead Culminative"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/deadIncrease">  <ListItem  button key={"DeadIncrease"}>
              <ListItemText primary={"Dead increase"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/icu">  <ListItem  button key={"Icu"}>
              <ListItemText primary={"Currently in ICU"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/culminativeicu">  <ListItem  button key={"culminativeIcu"}>
              <ListItemText primary={"In ICU culminative"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/onventillatorsculminative">  <ListItem  button key={"onventillatorsculminative"}>
              <ListItemText primary={"On ventillators culminative"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/onventillatorscurrently">  <ListItem  button key={"onventillatorscurrently"}>
              <ListItemText primary={"On ventillators currently"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/recovered">  <ListItem  button key={"recovered"}>
              <ListItemText primary={"Recovered"} />
            </ListItem></Link>
            <Divider />
            <center><Typography  style={{color:"grey",fontSize:"1vmax",marginTop:"1.5vmax",marginBottom:"1vmax"}} >Created by Atanas Bobev</Typography></center>
        </List>
      </Drawer>
      <main
        className={clsx(classes.content, {
          [classes.contentShift]: open,
        })}
      >
   
      </main>
    </div>
  );
  
}
h1, p {
  font-family: Lato;
}
.card{
  width:90vw;
  margin-left:5vw;
  margin-top:5vw;
}
Link{
  color:black;
  text-decoration:none;
}
style.css

import React from 'react';
let loaded=false;
let dataFinal;
 fetch("https://api.covidtracking.com/v1/us/current.json")
 .then(data=>data.json())
 .then(data=>{
     dataFinal=data[0]
  })



export {dataFinal}
import React from "react";
import { makeStyles } from "@material-ui/core/styles";
import Card from "@material-ui/core/Card";
import CardActions from "@material-ui/core/CardActions";
import CardContent from "@material-ui/core/CardContent";
import Button from "@material-ui/core/Button";
import Typography from "@material-ui/core/Typography";
import { title, content } from "./Routing.js";

export default function Card(props) {
  return (
    <Card className="card">
      <CardContent>
        <Typography color="textSecondary" gutterBottom>
          {props.title}
        </Typography>
        <Typography variant="h5" component="h2">
          {props.content}
        </Typography>
      </CardContent>
      <CardActions>
        <Button
          onClick={() => {
            window.location = "https://www.cdc.gov/covid-data-tracker/#cases";
          }}
          size="small"
        >
          Learn More
        </Button>
        <br />
      </CardActions>
     { typeof props.content === "string" || props.content instanceof String ? "" : <CardContent>
        <p style={{ color: "red" }}>{repeat(props.content)}</p>
      </CardContent>}
    </Card>
  );
}
export { Content, Title };

const repeat = num => {
  if (typeof num === "string" || num instanceof String) {
    return "";
  }
  if (num < 2000) {
    return "♥ ".repeat(num);
  } else {
    return "♥ ".repeat(2000) + " and " + (num - 2000) + " more";
  }
};
import React, { Component} from 'react';
import {render} from 'react-dom';
import './style.css';
import {dataFinal, loaded} from "./API.js"
import Routing from "./Routing.js"
import Card from "./Card.js"
import { BrowserRouter, Route, Switch } from 'react-router-dom';
class App extends Component {
    render() {
      return(
        <div> <Routing/>
        <main>
            <Switch>
             <Route exact path="/" render={()=> <Card title={''} content={"Navigate through the menus on the top left"} />}> 
                </Route>
                <Route exact path="/positive" render={()=><Card title={'Positive'} content={dataFinal.positive ? dataFinal.positive : "Loading..."} />}> 
                </Route>
                 <Route exact path="/positiveIncrease" render={()=> <Card title={'Positive increase'} content={dataFinal.positiveIncrease ? dataFinal.positiveIncrease : "Loading..."} />}> 
                </Route>
                <Route exact path="/hospitalized" render={()=> <Card title={'Hospitalized'} content={dataFinal.hospitalized ? dataFinal.hospitalized : "Loading..."}/>}> 
                </Route>
                 <Route exact path="/hospitalizedCurrently" render={()=> <Card title={'Hospitalized currently'} content={dataFinal.hospitalizedCurrently ? dataFinal.hospitalizedCurrently : "Loading..." }/>}> 
                </Route>
                  <Route exact path="/dead" render={()=> <Card title={'Total dead'} content={dataFinal.death ? dataFinal.death : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/icu" render={()=> <Card title={'Currently in intensive care unit'} content={dataFinal.inIcuCurrently ? dataFinal.inIcuCurrently : "Loading..." }/>}> 
                                 </Route>
                 <Route exact path="/culminativeicu" render={()=> <Card title={'Culminative in intensive care unit'} content={dataFinal.inIcuCumulative ? dataFinal.inIcuCumulative : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/onventillatorsculminative" render={()=> <Card title={'Culminative on ventillators'} content={dataFinal.onVentilatorCumulative ? dataFinal.onVentilatorCumulative : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/onventillatorscurrently" render={()=> <Card title={'Currently on ventillators'} content={dataFinal.onVentilatorCurrently ? dataFinal.onVentilatorCurrently : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/recovered" render={()=> <Card title={'Recovered'} content={dataFinal.recovered ? dataFinal.recovered : "Loading..." }/>}> 
                </Route>
                 <Route exact path="/deadIncrease" render={()=> <Card title={'Dead Increase'} content={dataFinal.deathIncrease ? dataFinal.deathIncrease : "Loading..." }/>}> 
                 </Route>
                  <Route exact path="/hospitalizedIncrease" render={()=> <Card title={'Hospitalized increase'} content={dataFinal.deathIncrease ? dataFinal.deathIncrease : "Loading..." }/>}> 
                 </Route>
            </Switch>
        </main>
        </div>
        )  
    }
}


render( <BrowserRouter>
        <App /> 
    </BrowserRouter>, document.getElementById('root'));
import React from 'react';
import clsx from 'clsx';
import { makeStyles, useTheme } from '@material-ui/core/styles';
import Drawer from '@material-ui/core/Drawer';
import CssBaseline from '@material-ui/core/CssBaseline';
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 MenuIcon from '@material-ui/icons/Menu';
import ChevronLeftIcon from '@material-ui/icons/ChevronLeft';
import ChevronRightIcon from '@material-ui/icons/ChevronRight';
import ListItem from '@material-ui/core/ListItem';
import ListItemIcon from '@material-ui/core/ListItemIcon';
import ListItemText from '@material-ui/core/ListItemText';
import {Content,Title} from "./Card.js"
import { BrowserRouter, Route, Switch,Link } from 'react-router-dom';
import ReplayIcon from '@material-ui/icons/Replay';
import Box from '@material-ui/core/Box';
import {retrieve} from "./API"
import 'fontsource-roboto';
const drawerWidth = 200;

const useStyles = makeStyles((theme) => ({
  root: {
    display: 'flex',
  },
  appBar: {
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
  },
  appBarShift: {
    width: `calc(100% - ${drawerWidth}px)`,
    marginLeft: drawerWidth,
    transition: theme.transitions.create(['margin', 'width'], {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
  },
  menuButton: {
    marginRight: theme.spacing(2),
  },
  hide: {
    display: 'none',
  },
  drawer: {
    width: drawerWidth,
    flexShrink: 0,
  },
  drawerPaper: {
    width: drawerWidth,
  },
  drawerHeader: {
    display: 'flex',
    alignItems: 'center',
    padding: theme.spacing(0, 1),
    // necessary for content to be below app bar
    ...theme.mixins.toolbar,
    justifyContent: 'flex-end',
  },
  content: {
    flexGrow: 1,
    padding: theme.spacing(3),
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.sharp,
      duration: theme.transitions.duration.leavingScreen,
    }),
    marginLeft: -drawerWidth,
  },
  contentShift: {
    transition: theme.transitions.create('margin', {
      easing: theme.transitions.easing.easeOut,
      duration: theme.transitions.duration.enteringScreen,
    }),
    marginLeft: 0,
  },
}));

export default function PersistentDrawerLeft() {
  const classes = useStyles();
  const theme = useTheme();
  const [open, setOpen] = React.useState(false);

  const handleDrawerOpen = () => {
    setOpen(true);
  };

  const handleDrawerClose = () => {
    setOpen(false);
  };

  return (
    <div className={classes.root}>
      <CssBaseline />
      <AppBar
        position="fixed"
        className={clsx(classes.appBar, {
          [classes.appBarShift]: open,
        })}
      >
        <Toolbar>
          <IconButton
            color="inherit"
            aria-label="Open drawer"
            onClick={handleDrawerOpen}
            edge="start"
            className={clsx(classes.menuButton, open && classes.hide)}
          >
            <MenuIcon />
          </IconButton>
          <Typography variant="h6" noWrap>
USA Covid-19 Visualization          
</Typography>
        </Toolbar>
      </AppBar>
      <Drawer
        className={classes.drawer}
        anchor="bottom"
        open={open}
        classes={{
          paper: classes.drawerPaper,
        }}
      >
        <div className={classes.drawerHeader}>
          <IconButton onClick={handleDrawerClose}>
            {theme.direction === 'ltr' ? <ChevronLeftIcon /> : <ChevronRightIcon />}
          </IconButton>
        </div>
        <Divider />
        <List>
        <Link onClick={()=>setOpen(false)} style={{textDecoration:"none",color:"black"}} to="/">  <ListItem  button key={"Home"}>
              <ListItemText  primary={"Home"} />
            </ListItem> </Link>
            <Divider />
          <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}} to="/positive">  <ListItem  button key={"Positive"}>
              <ListItemText  primary={"Positive"} />
            </ListItem> </Link>
             <Link onClick={()=>setOpen(false)} style={{textDecoration:"none",color:"black"}} to="/positiveIncrease">  <ListItem  button key={"PositiveIncrease"}>
              <ListItemText  primary={"Positive increase"} />
            </ListItem> </Link>
            <Divider />
         <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalized">   <ListItem  button key={"Hospitalized"}>
              <ListItemText primary={"Hospitalized culminative"} />
            </ListItem></Link>
            <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalizedCurrently">  <ListItem  button key={"hospitalizedCurrently"}>
              <ListItemText primary={"Hospitalized currently"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/hospitalizedIncrease">  <ListItem  button key={"hospitalizedIncrease"}>
              <ListItemText primary={"Hospitalized increase"} />
            </ListItem></Link>
                        <Divider />

           <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/dead">  <ListItem  button key={"Dead"}>
              <ListItemText primary={"Dead Culminative"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/deadIncrease">  <ListItem  button key={"DeadIncrease"}>
              <ListItemText primary={"Dead increase"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/icu">  <ListItem  button key={"Icu"}>
              <ListItemText primary={"Currently in ICU"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/culminativeicu">  <ListItem  button key={"culminativeIcu"}>
              <ListItemText primary={"In ICU culminative"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/onventillatorsculminative">  <ListItem  button key={"onventillatorsculminative"}>
              <ListItemText primary={"On ventillators culminative"} />
            </ListItem></Link>
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/onventillatorscurrently">  <ListItem  button key={"onventillatorscurrently"}>
              <ListItemText primary={"On ventillators currently"} />
            </ListItem></Link>
                        <Divider />
             <Link onClick={()=>setOpen(false)}  style={{textDecoration:"none",color:"black"}}  to="/recovered">  <ListItem  button key={"recovered"}>
              <ListItemText primary={"Recovered"} />
            </ListItem></Link>
            <Divider />
            <center><Typography  style={{color:"grey",fontSize:"1vmax",marginTop:"1.5vmax",marginBottom:"1vmax"}} >Created by Atanas Bobev</Typography></center>
        </List>
      </Drawer>
      <main
        className={clsx(classes.content, {
          [classes.contentShift]: open,
        })}
      >
   
      </main>
    </div>
  );
  
}
h1, p {
  font-family: Lato;
}
.card{
  width:90vw;
  margin-left:5vw;
  margin-top:5vw;
}
Link{
  color:black;
  text-decoration:none;
}
如何解决此路由(API)问题?我很高兴你能建议一些我在这个应用程序中错过的更好的实践。先谢谢你


再见,为避免出现错误,您可以执行以下操作:

<Route exact path="/positiveIncrease" render={()=> <Card title={'Positive increase'} content={dataFinal ? dataFinal.positiveIncrease ? dataFinal.positiveIncrease : "Loading..." : "Loading..."} />}> 
</Route>
  • API.js
    :您的解决方案现在只从
    API.js
    返回
    dataFinal
    。到现在为止,一直都还不错。但假设我想在每次需要时重新获取数据,使用您的解决方案是不可能的。因此,让我们用这种方式修改一下API.js:

    export default function(){
      return fetch("https://api.covidtracking.com/v1/us/current.json")
      .then(data=>data.json())
      .then(data=>{
         return data[0];
       })
    } 
    
  • 如您所见,现在API.js导出一个函数,该函数返回获取的值(而不仅仅是以前实现中获取的值)

  • this.state.dataFinal
    :好了,现在我们有了所需的所有元素。让我们继续使用App.js文件。首先,将
    dataFinal
    放入
    App.js
    状态:

    class App extends Component {
     constructor(props) {
       super(props);
       this.state = {
         dataFinal: {}
       }
     }
     ...
    
  • 然后,每次重新加载组件时,使用我们从
    API.js
    导入的函数更新
    App.js
    状态:

    componentDidMount(){
      fetchCovidData().then(data => {
        this.setState({dataFinal: data});
      })
    }
    
    就这样!现在,每次用户独立地重新加载页面时,
    dataFinal
    将被重新获取并正确显示

    在这个实现中,您还可以避免编写我之前建议的条件(因为我将
    dataFinal
    初始化为一个无效对象
    {}


    您的代码已修改。

    这部分修复了该问题。在重新加载后。。。几秒钟后加载API后,屏幕上显示的数据没有更新。Ciao@Atanas,我用一个解决方案更新了我的答案,这个解决方案可以帮助完全解决您的问题。希望你发现它比以前的答案更好。对不起,回复晚了,没问题。祝你今天愉快:)