反应路由器导航多页和反应滚动

React router navigation multipage and with react scroll

我正在尝试的是一个多页面反应应用程序,我可以在页面之间导航(比如从主要路线'/'到'/whitepape'或'privacyPolicy'),但我有4条不同的路线('/', 'services', 'features', 'contactUs') 在主路由 '/' 中,它使用 react-scroll 来获得在 Navbar 中添加链接的这 4 个组件之间的滚动(这部分按预期工作)。

但是在页面之间导航,比如用白皮书页面或隐私策略页面完全替换所有 4 个组件,导航栏和页脚在同一个地方,这样我就可以导航回家。

这就是我遇到的困难,感谢任何帮助我不确定我是否按照正确的方式来实现我需要的东西。我一直在 react native 中使用 React Navigation,它简单易懂且直接,希望 react-router 如此直接而不是 react-router 有点令人困惑。

App.js

function App() {
  return (
    <div className="App">
      <Navbar />
      <Switch>
        <Route path="/">
          <>
            <Hero />
            <Services />
            <Features />
            <ContactUs />
          </>
        </Route>
        <Route path="/whitepaper">
          <WhitePaper />
        </Route>
      </Switch>
      <Footer />
    </div>
  )
}

Navbar.js

import { Link } from 'react-scroll'
import { withRouter, Link as RouterLink } from 'react-router-dom'

const menuItems = [
  {
    menuTitle: 'Home',
    pageURL: '/',
    id: 'hero'
  },
  {
    menuTitle: 'Services',
    pageURL: '/services',
    id: 'services'
  },
  {
    menuTitle: 'Features',
    pageURL: '/features',
    id: 'features'
  },
  {
    menuTitle: 'Contact Us',
    pageURL: '/contactUs',
    id: 'contactUs'
  }
]

const Navbar = ({ history }) => {
  const classes = useStyles()
  const [anchorEl, setAnchorEl] = useState(null)
  const [showNav, setShowNav] = useState(false)
  const open = Boolean(anchorEl)
  const theme = useTheme()
  const isMobile = useMediaQuery(theme.breakpoints.down('sm'))
  const [isActive, setIsActive] = useState('/')

  useEffect(() => {
    setIsActive(history.location.pathname)
    window.addEventListener('scroll', () => {
      if (window.scrollY > 100) {
        setShowNav(true)
      } else {
        setShowNav(false)
      }
    })
    return () => {
      window.removeEventListener('scroll', () => setShowNav(false))
    }
  })

  const handleMenu = event => {
    setAnchorEl(event.currentTarget)
  }

  const handleMenuClick = pageURL => {
    history.push(pageURL)
    setAnchorEl(null)
  }

  const handleClose = () => {
    setAnchorEl(null)
  }

  const handleLinkClick = pageURL => {
    history.push(pageURL)
  }

  return (
    <div>
      <AppBar
        position="static"
        elevation={0}
        className={`${classes.appBar} ${
          showNav ? classes.appBarOnScroll : classes.appBar
        }`}>
        <Container>
          <Toolbar className={classes.toolbar}>
            <Link to="hero" smooth duration={1000}>
              <RouterLink to="/">
                <img src={logo} alt="Company Logo" className={classes.logo} />
              </RouterLink>
            </Link>
            {isMobile ? (
              <div>
                <IconButton
                  edge="start"
                  className={classes.menuButton}
                  color="inherit"
                  onClick={handleMenu}
                  aria-label="menu">
                  <MenuIcon />
                </IconButton>
                <Menu
                  className={classes.mobileMenu}
                  id="menu-appbar"
                  anchorEl={anchorEl}
                  anchorOrigin={{
                    vertical: 'top',
                    horizontal: 'right'
                  }}
                  keepMounted
                  transformOrigin={{
                    vertical: 'top',
                    horizontal: 'right'
                  }}
                  open={open}
                  onClose={handleClose}>
                  {menuItems.map(menuItem => {
                    const { menuTitle, pageURL, id } = menuItem
                    return (
                      <Link key={menuTitle} to={id} smooth duration={1000}>
                        <MenuItem
                          className={
                            isActive === pageURL
                              ? classes.mobileActiveMenuItem
                              : classes.mobileMenuItem
                          }
                          onClick={() => handleMenuClick(pageURL)}>
                          {menuTitle}
                        </MenuItem>
                      </Link>
                    )
                  })}
                </Menu>
              </div>
            ) : (
              <div className={classes.menu}>
                <Link
                  to="home"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/' ? classes.menuActiveLink : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/')}>
                  Home
                </Link>
                <Link
                  to="services"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/services'
                      ? classes.menuActiveLink
                      : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/services')}>
                  Services
                </Link>
                <Link
                  to="features"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/features'
                      ? classes.menuActiveLink
                      : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/features')}>
                  Features
                </Link>
                <Link
                  to="contactUs"
                  smooth
                  duration={1000}
                  className={
                    isActive === '/contactUs'
                      ? classes.menuActiveLink
                      : classes.menuLink
                  }
                  variant="contained"
                  onClick={() => handleLinkClick('/contactUs')}>
                  ContactUs
                </Link>
              </div>
            )}
          </Toolbar>
        </Container>
      </AppBar>
    </div>
  )
}

export default withRouter(Navbar)

Footer.js

import { Link } from 'react-scroll'
import { Link as RouterLink } from 'react-router-dom'

const Footer = () => {
  const classes = useStyles()
  const icons = [
    {
      img: linkedin,
      alt: 'linkedin',
      url: 'https://www.linkedin.com/company/company'
    },
    {
      img: twitter,
      alt: 'twitter',
      url: 'https://twitter.com/company'
    },
    {
      img: instagram,
      alt: 'instagram',
      url: 'https://www.instagram.com/company/'
    },
    {
      img: facebook,
      alt: 'facebook',
      url: 'https://www.facebook.com/company/'
    }
  ]
  return (
    <div className={classes.footer}>
      <Container className={classes.container}>
        <Grid container spacing={4}>
          <Grid item md={3} xs={12}>
            <div className={classes.column}>
              <Link to="hero" smooth duration={1000}>
                <RouterLink to="/">
                  <img className={classes.logo} src={logo} alt="Company Logo" />
                </RouterLink>
              </Link>
            </div>
          </Grid>
          <Grid item md={3} xs={12}>
            <div className={classes.column}>
              <div>
                <Grid item>
                  <span className={classes.linksTitle}>USEFUL LINKS</span>
                </Grid>
                <Grid item className={classes.links}>
                  <RouterLink to="/whitepaper" replace className={classes.link}>
                    <span className={classes.span}>White Paper</span>
                  </RouterLink>
                </Grid>
                <Grid item className={classes.links}>
                  <a
                    href="mailto:xyz@comapmy.com"
                    className={classes.link}>
                    <span className={classes.span}>Email Our CEO</span>
                  </a>
                </Grid>
                <Grid item className={classes.links}>
                  <RouterLink to="/" className={classes.link}>
                    <span className={classes.span}>Privacy Policy</span>
                  </RouterLink>
                </Grid>
              </div>
            </div>
          </Grid>
          <Grid item md={3} xs={12}>
            <div className={classes.column}>
              {icons.map(icon => {
                return (
                  <a href={icon.url} key={icon.alt}>
                    <img
                      className={classes.icon}
                      src={icon.img}
                      alt={icon.alt}
                    />
                  </a>
                )
              })}
            </div>
          </Grid>
          <Grid item md={3} xs={12}>
            <div className={classes.top}>
              <Link to="hero" smooth duration={1000}>
                <RouterLink to="/">
                  <div>
                    <img src={top} alt="back to top" />
                    <p>Back To Top</p>
                  </div>
                </RouterLink>
              </Link>
            </div>
          </Grid>
        </Grid>
        <Grid container>
          <Grid item xs={12}>
            <div className={classes.footerBottom}>
              <p className={classes.copyright}>
                © 2021 Copyrights •{' '}
                <Link to="hero" smooth duration={1000}>
                  <RouterLink to="/" className={classes.company}>
                    <span>company.com</span>
                  </RouterLink>
                </Link>
              </p>
            </div>
          </Grid>
        </Grid>
      </Container>
    </div>
  )
}

export default Footer

Switch 中,组件路径顺序和特异性很重要。不过,这并不是他们的文档中公开提到的细节。您想要在 较不具体的路径之前订购更具体的路径。将 path 视为更多的前缀,您会看到“/”是 all 路径的路径前缀。

Switch returns 并呈现它在其子项中找到的第一个匹配路径。

只需颠倒路径的顺序,使 "/whitepaper" 列在更 general/less 具体的 "/" 路径之前。

function App() {
  return (
    <div className="App">
      <Navbar />
      <Switch>
        <Route path="/whitepaper">
          <WhitePaper />
        </Route>
        <Route path="/">
          <>
            <Hero />
            <Services />
            <Features />
            <ContactUs />
          </>
        </Route>
      </Switch>
      <Footer />
    </div>
  )
}