Как передать объект URL в материальную кнопку пользовательского интерфейса без ошибок?

Из документации NextJS я узнал, что мы можем использовать объект 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} />);

Массив зависимостей в React
Массив зависимостей в React
Все о массиве Dependency и его связи с useEffect.
Что такое компоненты React? Введение в компоненты | Типы компонентов
Что такое компоненты React? Введение в компоненты | Типы компонентов
Компонент - это независимый, многократно используемый фрагмент кода, который делит пользовательский интерфейс на более мелкие части. Например, если мы...
Введение в одну из самых важных концепций в React - функциональное программирование.
Введение в одну из самых важных концепций в React - функциональное программирование.
React разработан с использованием концепции функционального программирования, поэтому понимание функционального программирования важно для изучения...
Руководство спасателя React по созданию масштабируемых приложений
Руководство спасателя React по созданию масштабируемых приложений
А, React. Это одна из самых популярных библиотек JavaScript. Ее любят за гибкость, простоту использования и, будем честны, за то, что она позволяет...
0
0
1 553
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Компонент Material UI Button уже имеет свойство href со строковым типом. (https://material-ui.com/api/button/). Я думаю, вы можете передать реквизит с другим именем.

Нравиться

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

И

const CustomLink = ({ hrefAsObj }) => <NextLink href = {hrefAsObj}>...</NextLink>
Ответ принят как подходящий

Я открыл вопрос об этом в репозитории Material UI, 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 переименовывается в to при использовании NextLinkComposed.

Другие вопросы по теме

Использование нескольких имен правил CSS со стилизованным API в пользовательском интерфейсе материалов
Переход на новый экран, не покидая родительский экран
React.js создает div, который может перемещать объекты влево и вправо
Пользовательский компонент ввода React admin с базовым стилем ввода текста
Как показать разделенный заголовок в таблице материалов с вложенной группой данных в angular
Реагировать. Как я могу вставить сетку в TabPanel без предупреждений?
Как я могу визуализировать сетку пользовательского интерфейса материала с помощью React без предупреждения об уникальном ключе
Как разместить объект над CardActionArea
Фон компонента Drawer блокирует взаимодействие пользователей со страницей, если она открыта
Как я могу изменить стиль всех компонентов типографики Material UI в одном компоненте реакции, не применяя класс к каждому элементу?