首页 > 解决方案 > 当变体是临时的时,样式化的 MUI 抽屉不会打开

问题描述

我创建了一个样式MuiDrawer组件,因此我可以为组件添加一些自定义样式。我想使用该temporary变体,但抽屉没有打开。当我将 Drawer 变体设置为 Drawer 时permanent,会显示。所以这可能open是导致错误的道具的传递。当我使用 MUI 中的默认 Drawer 组件时,该temporary变体确实有效:

// demo.tsx

import * as React from 'react';
// import Drawer from '@mui/material/Drawer';
import {Drawer} from './styles';
import Button from '@mui/material/Button';

export default function TemporaryDrawer() {
  const [open, setOpen] = React.useState(false);

  const toggleDrawer = () => {
    setOpen(!open);
  };

  return (
    <>
      <Button onClick={toggleDrawer}>Toggle Drawer</Button>
      <Drawer
        variant='temporary'
        open={open}
        onClose={toggleDrawer}
      >
        <p>Drawer</p>
      </Drawer>
    </>
  );
}
// styles.tsx

import {styled} from '@mui/material';
import {Theme, CSSObject} from '@mui/material/styles';
import MuiDrawer from '@mui/material/Drawer';

const drawerWidth = 240;

const openedMixin = (theme: Theme): CSSObject => ({
  backgroundColor: 'green',
  width: drawerWidth,
  transition: theme.transitions.create('width', {
    easing: theme.transitions.easing.sharp,
    duration: theme.transitions.duration.enteringScreen,
  }),
  overflowX: 'hidden',
});

const closedMixin = (theme: Theme): CSSObject => ({
  transition: theme.transitions.create('width', {
    easing: theme.transitions.easing.sharp,
    duration: theme.transitions.duration.leavingScreen,
  }),
  overflowX: 'hidden',
  width: `calc(${theme.spacing(7)} + 1px)`,
  [theme.breakpoints.up('sm')]: {
    width: `calc(${theme.spacing(8)} + 1px)`,
  },
});

export const Drawer = styled(MuiDrawer, {shouldForwardProp: (prop) => prop !== 'open'})(
  ({theme, open}) => ({
    width: drawerWidth,
    flexShrink: 0,
    whiteSpace: 'nowrap',
    boxSizing: 'border-box',
    ...(open && {
      ...openedMixin(theme),
      '& .MuiDrawer-paper': openedMixin(theme),
    }),
    ...(!open && {
      ...closedMixin(theme),
      '& .MuiDrawer-paper': closedMixin(theme),
    }),
  }),
)

https://codesandbox.io/s/temporarydrawer-material-demo-forked-zci40?file=/demo.tsx

标签: reactjsmaterial-ui

解决方案


虽然@v1s10n_4 的答案是正确的,但我会再解释一下原因。

回调的目的shouldForwardProp是防止 HOC 创建的样式 props 泄漏到 DOM 元素导致无效属性错误。你Drawer有一个open道具,它是一个已知的道具,Dialog所以你不需要担心道具在这里没有正确处理:

const Dialog = (props) => {
  // I know this open prop, so I'm gonna extract it here
  const { open, ...other } = props

  // and do some logic with the open prop

  // and make sure it is not passed to the Component
  return <Component {...other} />
}

但是,如果您传递不是来自DialogAPI的任意道具,bgcolor例如:

<Dialog bgcolor='red'

然后它将被传递给 DOM 元素:

const Dialog = (props) => {
  const { open, ...other /* other includes the bgcolor prop */ } = props

  // logic...

  return <Component {...other} />
}

当您styled用于创建样式化组件时:

const StyledDialog = styled(Dialog)(...)
<StyledDialog bgcolor='red'

它在幕后看起来像这样:

const StyledDialog = (props) => {
  const className = getStyles(props);

  return <Dialog {...props} className={className} />
}

这就是为什么您需要使用shouldForwardProp, 来过滤掉与样式相关的道具(而不是Dialog道具),这样它就不会被传递给Dialog

const StyledDialog = (props) => {
  const { bgcolor, ...other } = props;
  const className = getStyles(props);

  // bgcolor is filtered now.
  return <Dialog {...other} className={className} />
}

推荐阅读