MaterialUI:定义样式化组件的简便方法?

时间:2018-10-06 08:24:26

标签: reactjs typescript material-ui

我想找到一种使用Material-UI在我的应用中轻松定义便利组件的方法。

我从Material-UI doco for Appbar复制了一个示例,并尝试引入一些React组件以提高可读性。

我的问题是关于MenuShortcutBar函数和下面的MenuShortcutItem类之间的样板对比。

MenuShortcutBar非常简洁;但是,一旦Material-UI样式出现,我最终就需要大量样板。我必须定义一个类,一个需要扩展WithStyles的属性接口和一个构造函数。

问题是:使用Material-UI时是否有一种简洁的方法来创建样式化的React组件?如何简化MenuShortcutItem

import * as React from "react";
import {ReactNode, SyntheticEvent} from "react";
import {
  AppBar,
  Hidden,
  IconButton,
  Menu,
  MenuItem,
  SvgIcon,
  Toolbar,
  Typography,
  withStyles,
  WithStyles
} from "@material-ui/core";
import {SvgIconProps} from "@material-ui/core/SvgIcon";
import {SendMailSvg} from "component/svg-icon/SendMailSvg";

export interface MuiAppBarProps extends WithStyles<typeof styles> {

}

class MuiAppBar extends React.Component<
  MuiAppBarProps,
  { anchorEl?: HTMLElement, }
>{

  constructor(props: MuiAppBarProps, context?: any){
    super(props, context);
    this.state = {anchorEl: undefined}
  }

  handleMenu = (event:SyntheticEvent<HTMLElement>) => {
    this.setState({ anchorEl: event.currentTarget });
  };

  handleClose = () => {
    this.setState({ anchorEl: undefined });
  };

  render(){
    const { classes } = this.props;
    return <div className={classes.root}>
      <AppBar position="static" color={"default"}>
        <Toolbar variant={"dense"}>
          <IconButton className={classes.menuButton} color="inherit">
            <MenuIcon/>
          </IconButton>
          <IconButton className={classes.menuButton} color="inherit">
            <SendMailSvg width={"2em"}/>
          </IconButton>
          <MenuShortcutBar>
              <MenuShortcutItem classes={this.props.classes}>
                Keywords
              </MenuShortcutItem>
              <MenuShortcutItem classes={this.props.classes}>
                Forwarded
              </MenuShortcutItem>
              <MenuShortcutItem classes={this.props.classes}>
                Rejected
              </MenuShortcutItem>
          </MenuShortcutBar>
        </Toolbar>
      </AppBar>
    </div>
  }
}

...

function MenuShortcutBar(props:{children: ReactNode}){
  return <Hidden smDown>
    {/* Avoid shortcuts wrapping which causes AppBar to grow in height */}
    <span style={{
      display: "flex", flexWrap: "nowrap", overflow: "hidden"
    }}>
      {props.children}
    </span>
  </Hidden>
}

interface MenuShortcutItemProps extends WithStyles<typeof styles> {
  children: React.ReactNode
}
class MenuShortcutItem extends React.Component<
  MenuShortcutItemProps,
  any
>{
  constructor(props: MenuShortcutItemProps, context?: any){
    super(props, context);
  }
  render(){
    return <IconButton color="inherit"
      className={this.props.classes.menuButton}
    >
      {this.props.children}
    </IconButton>
  }
}

const styles = {
  root: {
    flexGrow: 1,
  },
  grow: {
    flexGrow: 1,
  },
  menuButton: {
    marginLeft: -12,
    marginRight: 20,
  },
};
export default withStyles(styles)(MuiAppBar);

1 个答案:

答案 0 :(得分:1)

Material-UI Typescript guide中找到了一些有助于我更好地尝试的信息。

感谢Martin Hochel的Typescript pro tips帖子,使我开始使用类型交集将nodeservice混合到Props定义中(我很想尝试使用WithStyles)。

更简洁的函数式定义:

extends

还有一个相当简洁的类样式组件定义,用于定义何时需要状态:

const MenuShortcutItem2 = withStyles(styles)((
  props:{children:ReactNode} & WithStyles<typeof styles>
) => (
  <IconButton className={props.classes.menuButton} color="inherit">
    {props.children}
  </IconButton>
));

以上问题:

  1. 重复const ScreenContainer = withStyles(style)(class extends React.Component< {children:ReactNode} & WithStyles<typeof style> >{ state = {message: "wibble"} as {message?: string}; render(){ return <main className={this.props.classes.mainLayout}> <Paper className={this.props.classes.paper}> {this.props.children} {this.state.message} </Paper> </main> } }); withStyles(styles)时出现的重复令人讨厌。

  2. 在状态定义中,属性名称也有一些重复,但这仍然比标准的构造函数安排好(无论如何,您都要复制属性名称,但至少需要三行样板)。