реакция-роутер-дом и материал пользовательского интерфейса: проблема forwardRef - PullRequest
0 голосов
/ 26 апреля 2020

Хотя я применил forwardRef, как упомянуто в нескольких постах и ​​в примерах веб-сайта materail-ui, у меня все еще есть предупреждение в консоли. И я действительно не понимаю, почему.

Я пытаюсь создать ящик со списком элементов, которые являются ссылками на реакцию маршрутизатора, встроенными в компонент ссылки на материал и пользовательский интерфейс. Я встроил их, чтобы извлечь выгоду из глобальной темы MUI, которую я создал

PS: это машинописный код. Ссылка на строгую типизацию - это ад; -)

ЗДЕСЬ ЯВЛЯЕТСЯ КОДЕКСОМ, ЧТОБЫ ВОССТАНОВИТЬ ВОПРОС. Убедитесь, что вы достаточно расширили страницу браузера codeandbox для отображения ящика

Компонент ссылки

import { Link as MUILink, LinkBaseProps } from "@material-ui/core";
import React from "react";
import {
  Link as LinkRouter,
  LinkProps as RouterLinkProps
} from "react-router-dom";

type RefLinkRouter =
  | ((instance: HTMLAnchorElement | null) => void)
  | React.RefObject<HTMLAnchorElement>
  | null
  | undefined;

type ILinkProps = RouterLinkProps;

const fwdLink = (props: ILinkProps, ref: RefLinkRouter): JSX.Element => (
  <LinkRouter ref={ref} {...props} />
);
const ForwardedLink = React.forwardRef<HTMLAnchorElement | null, ILinkProps>(
  fwdLink
);

const Link: React.FC<ILinkProps & LinkBaseProps> = (
  props: ILinkProps & LinkBaseProps
) => {
  return (
    <MUILink component={ForwardedLink} to={props.to} {...props}>
      {props.children}
    </MUILink>
  );
};

export { Link, ILinkProps };

Компонент выдвижного ящика

import { Link } from "./../Link";
import { List, ListItem, makeStyles } from "@material-ui/core";
import Drawer from "@material-ui/core/Drawer";
import Hidden from "@material-ui/core/Hidden";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import MailIcon from "@material-ui/icons/Mail";
import InboxIcon from "@material-ui/icons/MoveToInbox";
import React from "react";

const drawerWidth = 240;

interface IOptionsValue {
  value: string;
  label: string;
}

interface IDrawerMenuItemsProps extends IOptionsValue {
  to: string;
  iconName?: JSX.Element;
}

interface IResponsiveDrawerProps {
  container?: number;
  menuItems: Array<IDrawerMenuItemsProps>;
}

const useStyles = makeStyles({
  list: {
    backgroundColor: "blue"
  },
  drawerMenuItemList: {
    color: "white",
    backgroundColor: "blue"
  }
});

const ResponsiveDrawer: React.FC<IResponsiveDrawerProps> = (
  props: IResponsiveDrawerProps
): JSX.Element => {
  // const { container } = props;
  const { menuItems } = props;

  const classes = useStyles();
  const [mobileOpen, setMobileOpen] = React.useState(false);

  const handleDrawerToggle = () => {
    setMobileOpen(!mobileOpen);
  };

  const drawer = (
    <div>
      <div />
      <List className={classes.drawerMenuItemList}>
        {menuItems.map((menuItem: IDrawerMenuItemsProps, index: number) => {
          return (
            <ListItem
              className={classes.drawerMenuItemList}
              key={menuItem.value}
              component={Link}
              to={menuItem.to}
            >
              <ListItemIcon className={classes.drawerMenuItemList}>
                {index % 2 === 0 ? <InboxIcon /> : <MailIcon />}
              </ListItemIcon>
              <p className={classes.drawerMenuItemList}>{menuItem.label}</p>
            </ListItem>
          );
        })}
      </List>
    </div>
  );

  return (
    <>
      <Hidden smUp implementation="css">
        <Drawer
          //                    container={container}
          style={{ width: drawerWidth }}
          variant="temporary"
          anchor={"right"}
          open={mobileOpen}
          onClose={handleDrawerToggle}
          ModalProps={{
            keepMounted: true // Better open performance on mobile.
          }}
        >
          {drawer}
        </Drawer>
      </Hidden>
      <Hidden xsDown implementation="css">
        <Drawer variant="permanent" open>
          {drawer}
        </Drawer>
      </Hidden>
    </>
  );
};

export default ResponsiveDrawer;

Домашняя страница, где я вызываю ящик

import React from "react";
import ResponsiveDrawer from "./../ResponsiveDrawer";

const HomePage = () => {
  const menuItems = [
    {
      label: "Menu 1",
      value: "menu1",
      to: "/app"
    },
    {
      label: "Menu 2",
      value: "menu2",
      to: "/app"
    }
  ];

  return (
    <>
      <ResponsiveDrawer menuItems={menuItems} />
      <div>here were are</div>
    </>
  );
};

export default HomePage;

enter image description here

1 Ответ

1 голос
/ 27 апреля 2020

Согласно документации, у нас есть некоторые оговорки с использованием ссылок.

https://material-ui.com/guides/composition/#caveat -with-refs

Однако, как вы реализуете это, Я понимаю, что ваша идея состоит в том, чтобы воспользоваться преимуществом использования компонента Link пользовательского интерфейса Material-UI, имеющего емкость реагирующего маршрутизатора и использующего дочерний компонент.

В этом случае вы можете использовать " component ", но для этого вы должны использовать React.forwardRef для пересылки ссылки, чтобы компонент имел доступ к узлу DOM.

https://codesandbox.io/s/keen-banzai-o2q24

    type LinkProps = LinkBaseProps & RouterLinkProps;

    const LinkBehavior = React.forwardRef<any, ILinkProps>((props, ref) => (
       <MUILink component={LinkRouter} ref={ref} to={props.to} {...props} />
    ));

    export { LinkBehavior as Link };
    export type ILinkProps = LinkProps;
...