需要帮助将 Gatsby 组件转换为 NextJS

Need help converting a Gatsby component to NextJS

请参阅下面的代码,因为我正在尝试将此 header 组件从 Gatsby 转换为 NextJS...我 运行 遇到的问题有两个方面:首先,您会注意到我有

import {Link, navigate} from 'gatsby'

我知道我可以只使用 'next/link' 中的 Link 而不是 Gatsby 中的 Link,但是从 gatsby 导航的替代方法是什么?

其次(也是更困难的),我在尝试使用来自@material-ui 的 makeStyles 挂钩时收到以下错误: 我完全不知道如何解决这个问题,我已经包含了下面的所有代码...请帮忙!!!

import React, { useState } from 'react'
import AppBar from '@material-ui/core/AppBar'
import Toolbar from '@material-ui/core/Toolbar'
import Typography from '@material-ui/core/Typography'
import Button from '@material-ui/core/Button'
import IconButton from '@material-ui/core/IconButton'
import Tabs from '@material-ui/core/Tabs'
import Tab from '@material-ui/core/Tab'
import { makeStyles } from '@material-ui/core/styles'
import useMediaQuery from '@material-ui/core/useMediaQuery'
import Hidden from '@material-ui/core/Hidden'
import SwipeableDrawer from '@material-ui/core/SwipeableDrawer'
import List from '@material-ui/core/List'
import ListItem from '@material-ui/core/ListItem'
import ListItemText from '@material-ui/core/ListItemText'
import { Link, navigate } from 'gatsby'
import Link from 'next/link'
import menu from '../../images/menu.svg'
import account from '../../images/account-header.svg'
import cart from '../../images/cart.svg'
import search from '../../images/search.svg'

const useStyles = makeStyles(theme => ({
  coloredIndicator: {
    backgroundColor: 'lightpurple',
  },
  logoText: {
    color: theme.palette.common.offBlack,
  },
  logoContainer: {
    [theme.breakpoints.down('md')]: {
      marginRight: 'auto',
    },
  },
  tab: {
    ...theme.typography.body1,
    fontWeight: 600,
  },
  tabs: {
    marginLeft: 'auto',
    marginRight: 'auto',
  },
  icon: {
    height: '3rem',
    width: '3rem',
  },
  drawer: {
    backgroundColor: theme.palette.primary.main,
  },
  listItemText: {
    color: theme.palette.common.white,
  },
}))

export default function Header({ categories }) {
  const classes = useStyles()
  console.log('HEADER: ', categories)
  const matchesMD = useMediaQuery(theme => theme.breakpoints.down('md'))

  const [drawerOpen, setDrawerOpen] = useState(false)

  // const iOS = process.browser && /iPad|iPhone|iPod/.test(navigator.userAgent)
  const iOS = /iPad|iPhone|iPod/.test(navigator.userAgent)

  const activeIndex = () => {
    const found = routes.indexOf(
      routes.filter(
        ({ node: { name, link } }) =>
          (link || `/${name.toLowerCase()}`) === window.location.pathname
      )[0]
    )
    return found === -1 ? false : found
  }

  const routes = [
    ...categories,
    { node: { name: 'Contact Us', strapiId: 'contact', link: '/contact' } },
  ]
  const tabs = (
    <Tabs
      value={activeIndex()}
      classes={{ indicator: classes.coloredIndicator, root: classes.tabs }}
    >
      {routes.map(route => (
        <Tab
          classes={{ root: classes.tab }}
          component={Link}
          to={route.node.link || `/${route.node.name.toLowerCase()}`}
          label={route.node.name}
          key={route.node.strapiId}
        />
      ))}
    </Tabs>
  )

  const drawer = (
    <SwipeableDrawer
      open={drawerOpen}
      onOpen={() => setDrawerOpen(true)}
      onClose={() => setDrawerOpen(false)}
      disableBackdropTransition={!iOS}
      disableDiscovery={iOS}
      classes={{ paper: classes.drawer }} // iOS only
    >
      <List disablePadding>
        {routes.map((route, i) => (
          <ListItem
            selected={activeIndex() === i}
            component={Link}
            to={route.node.link || `/${route.node.name.toLowerCase()}`}
            divider
            button
            key={route.node.strapiId}
          >
            <ListItemText
              classes={{ primary: classes.listItemText }}
              primary={route.node.name}
            />
          </ListItem>
        ))}
      </List>
    </SwipeableDrawer>
  )
  const actions = [
    {
      icon: search,
      alt: 'search',
      visible: true,
      onClick: () => console.log('search'),
    },
    {
      icon: cart,
      alt: 'cart',
      visible: true,
      link: '/cart',
    },
    {
      icon: account,
      alt: 'account',
      visible: !matchesMD,
      link: '/account',
    },
    {
      icon: menu,
      alt: 'menu',
      visible: matchesMD,
      onClick: () => setDrawerOpen(true),
    },
  ]

  return (
    <AppBar color="transparent" elevation={0}>
      <Toolbar>
        <Button
          component={Link}
          to="/"
          classes={{ root: classes.logoContainer }}
        >
          <Typography variant="h1">
            <span className={classes.logoText}>VAR</span> X
          </Typography>
        </Button>
        {matchesMD ? drawer : tabs}
        {actions.map(action => {
          if (action.visible) {
            return (
              <IconButton
                onClick={action.onClick}
                key={action.alt}
                component={action.onClick ? undefined : Link}
                to={action.onClick ? undefined : action.link}
              >
                <img
                  className={classes.icon}
                  src={action.icon}
                  alt={action.alt}
                />
              </IconButton>
            )
          }
        })}
      </Toolbar>
    </AppBar>
  )
}

Gatsby 的替代 navigate 应该代表 Next's useRouter,这不一样但是稍微调整一下你可以获得相同的功能。实例化为 const router = useRouter() 后,您可以使用:

router.push(url, as, options)

其中 url 代表您的动态导航路径。

关于您的第二个问题(破坏您的代码的问题):它与 Gatsby 或 Next 无关,而是与 React 无关,您正在破坏 rule of hooks 或者因为 React [=] 之间的版本不匹配26=]。提供更多信息或调试日志。

如果您将 useStyles 移动到组件内部,问题应该会消失,但您需要稍微清理一下组件。