【问题标题】:How to pass an URL object to material UI button without getting errors?如何将 URL 对象传递给 Material UI 按钮而不出错?
【发布时间】:2020-12-18 16:57:23
【问题描述】:

NextJS documentation 中,我了解到我们可以使用 URL 对象,它会自动格式化以创建 URL 字符串。

在功能上它没有问题,但控制台上出现以下错误:

Warning: Failed prop type: Invalid prop `href` of type `object` supplied to `ForwardRef(ButtonBase)`, expected `string`.

这是一个最小的 CodeSandbox 复制:https://codesandbox.io/s/next-materialui-objecturl-rmprr?file=/pages/index.js

// index.js
import React from "react";
import Button from "@material-ui/core/Button";
import Link from "../src/Link";

export default function Index() {
  return (
    <div>
      <Button
        component={Link}
        href={{
          pathname: "/about",
          query: { name: "test" }
        }}
        naked
        variant="contained"
      >
        Link button with url object
      </Button>
    </div>
  );
}
// Link.js
import React from 'react';
import PropTypes from 'prop-types';
import clsx from 'clsx';
import { useRouter } from 'next/router';
import NextLink from 'next/link';
import MuiLink from '@material-ui/core/Link';

const NextComposed = React.forwardRef(function NextComposed(props, ref) {
  const { as, href, ...other } = props;

  return (
    <NextLink href={href} as={as}>
      <a ref={ref} {...other} />
    </NextLink>
  );
});

NextComposed.propTypes = {
  as: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  prefetch: PropTypes.bool,
};

// A styled version of the Next.js Link component:
// https://nextjs.org/docs/#with-link
function Link(props) {
  const {
    href,
    activeClassName = 'active',
    className: classNameProps,
    innerRef,
    naked,
    ...other
  } = props;

  const router = useRouter();
  const pathname = typeof href === 'string' ? href : href.pathname;
  const className = clsx(classNameProps, {
    [activeClassName]: router.pathname === pathname && activeClassName,
  });

  if (naked) {
    return <NextComposed className={className} ref={innerRef} href={href} {...other} />;
  }

  return (
    <MuiLink component={NextComposed} className={className} ref={innerRef} href={href} {...other} />
  );
}

Link.propTypes = {
  activeClassName: PropTypes.string,
  as: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  className: PropTypes.string,
  href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
  innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
  naked: PropTypes.bool,
  onClick: PropTypes.func,
  prefetch: PropTypes.bool,
};

export default React.forwardRef((props, ref) => <Link {...props} innerRef={ref} />);

【问题讨论】:

    标签: reactjs material-ui next.js


    【解决方案1】:

    Material UI Button 组件已经有一个字符串类型的href 属性。 (https://material-ui.com/api/button/)。我认为您可以使用不同的名称传递道具。

    喜欢

    <Button nextHref={hrefAsObj} component={CustomLink}>...</Button>
    

    const CustomLink = ({ hrefAsObj }) => <NextLink href={hrefAsObj}>...</NextLink>
    

    【讨论】:

      【解决方案2】:

      我在 Material UI 存储库上打开了一个 issue 关于这个,一个 PR 将被合并以提供解决方案。

      // Link.js
      /* eslint-disable jsx-a11y/anchor-has-content */
      import React from 'react';
      import PropTypes from 'prop-types';
      import clsx from 'clsx';
      import { useRouter } from 'next/router';
      import NextLink from 'next/link';
      import MuiLink from '@material-ui/core/Link';
      
      export const NextLinkComposed = React.forwardRef(function NextComposed(
        props,
        ref
      ) {
        // eslint-disable-next-line react/prop-types
        const {
          href,
          to,
          as,
          replace,
          scroll,
          passHref,
          shallow,
          prefetch,
          ...other
        } = props;
      
        return (
          <NextLink href={to} as={as}>
            <a ref={ref} {...other} />
          </NextLink>
        );
      });
      
      NextLinkComposed.propTypes = {
        as: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
        prefetch: PropTypes.bool,
      };
      
      // A styled version of the Next.js Link component:
      // https://nextjs.org/docs/#with-link
      function Link(props) {
        const {
          href,
          activeClassName = 'active',
          className: classNameProps,
          innerRef,
          naked,
          ...other
        } = props;
      
        const router = useRouter();
        const pathname = typeof href === 'string' ? href : href.pathname;
        const className = clsx(classNameProps, {
          [activeClassName]: router.pathname === pathname && activeClassName,
        });
      
        if (naked) {
          return (
            <NextLinkComposed
              className={className}
              ref={innerRef}
              to={href}
              {...other}
            />
          );
        }
      
        return (
          <MuiLink
            component={NextLinkComposed}
            className={className}
            ref={innerRef}
            to={href}
            {...other}
          />
        );
      }
      
      Link.propTypes = {
        activeClassName: PropTypes.string,
        as: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
        className: PropTypes.string,
        href: PropTypes.oneOfType([PropTypes.string, PropTypes.object]),
        innerRef: PropTypes.oneOfType([PropTypes.func, PropTypes.object]),
        naked: PropTypes.bool,
        onClick: PropTypes.func,
        prefetch: PropTypes.bool,
      };
      
      export default React.forwardRef((props, ref) => (
        <Link {...props} innerRef={ref} />
      ));
      

      Link.js 文件现在正在导出NextLinkComposed 可以这样使用:

      // index.js
      import React from "react";
      import Button from "@material-ui/core/Button";
      import { NextLinkComposed } from "../src/Link";
      
      export default function Index() {
        return (
          <div>
            <Button
              component={NextLinkComposed}
              to={{
                pathname: "/about",
                query: { name: "test" }
              }}        
              variant="contained"
            >
              Link button with url object
            </Button>
          </div>
        );
      }
      

      注意href prop 在使用NextLinkComposed 时被重命名为to

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2020-03-09
        • 1970-01-01
        • 2019-11-02
        • 1970-01-01
        • 2011-01-30
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多