如何将材料 ui 纯 reactjs 函数转换为 es6 类?

Posted

技术标签:

【中文标题】如何将材料 ui 纯 reactjs 函数转换为 es6 类?【英文标题】:how to convert material ui pure reactjs functions to es6 classes? 【发布时间】:2020-06-16 05:15:38 【问题描述】:

我在应用程序中使用 react Material UI,但发现我的 react 代码缺少一些逻辑。下面的代码按预期工作

import React from 'react';
import  fade,makeStyles  from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import Icon from '@material-ui/core/Icon';
import  Redirect  from "react-router-dom";
import './App.css';


/* AppBar*/
//import  fade, makeStyles  from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import InputBase from '@material-ui/core/InputBase';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import MenuIcon from '@material-ui/icons/Menu';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
/*App bar */

import  ImgMediaCard from './ImgMediaCard';

import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';

import DemoCarousel from './MCarousel'

var gridListStyle =   
  marginLeft: "40px"
;

const useStyles = makeStyles(theme => (
  grow: 
    flexGrow: 1,
  ,
  menuButton: 
    marginRight: theme.spacing(2),
  ,
  title: 
    display: 'none',
    [theme.breakpoints.up('sm')]: 
      display: 'block',
    ,
  ,
  search: 
    position: 'relative',
    borderRadius: theme.shape.borderRadius,
    backgroundColor: fade(theme.palette.common.white, 0.15),
    '&:hover': 
      backgroundColor: fade(theme.palette.common.white, 0.25),
    ,
    marginRight: theme.spacing(2),
    marginLeft: 0,
    width: '100%',
    [theme.breakpoints.up('sm')]: 
      marginLeft: theme.spacing(3),
      width: 'auto',
    ,
  ,
  searchIcon: 
    width: theme.spacing(7),
    height: '100%',
    position: 'absolute',
    pointerEvents: 'none',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  ,
  inputRoot: 
    color: 'inherit',
  ,
  inputInput: 
    padding: theme.spacing(1, 1, 1, 7),
    transition: theme.transitions.create('width'),
    width: '100%',
    [theme.breakpoints.up('md')]: 
      width: 200,
    ,
  ,
  sectionDesktop: 
    display: 'none',
    [theme.breakpoints.up('md')]: 
      display: 'flex',
    ,
  ,
  sectionMobile: 
    display: 'flex',
    [theme.breakpoints.up('md')]: 
      display: 'none',
    ,
    
));
/*end App bar work*/
const useGridStyles = makeStyles(theme => (
  root: 
    flexGrow: 1,
  ,
  paper: 
    // padding: theme.spacing(2),
    // textAlign: 'center',
    // color: theme.palette.text.secondary,
  ,
));

function App() 

  const Gridclasses = useGridStyles();
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null);

  const isMenuOpen = Boolean(anchorEl);
  const isMobileMenuOpen = Boolean(mobileMoreAnchorEl);

  const handleProfileMenuOpen = event => 
    setAnchorEl(event.currentTarget);
  ;

  const handleMobileMenuClose = () => 
    setMobileMoreAnchorEl(null);
  ;

  const handleMenuClose = () => 
    setAnchorEl(null);
    handleMobileMenuClose();
  ;

  const handleMobileMenuOpen = event => 
    setMobileMoreAnchorEl(event.currentTarget);
  ;

  const onRegisterClick = () => 
    debugger;
    //if(userFound)
        return  <Redirect  to="/RegisterBuyer/" />
   // 
 

  let nums = Array.from(Array(40).keys());
  const menuId = 'primary-search-account-menu';
  const renderMenu = (
    <Menu
      anchorEl=anchorEl
      anchorOrigin= vertical: 'top', horizontal: 'right' 
      id=menuId
      keepMounted
      transformOrigin= vertical: 'top', horizontal: 'right' 
      open=isMenuOpen
      onClose=handleMenuClose
    >
      <MenuItem onClick=handleMenuClose>Profile</MenuItem>
      <MenuItem onClick=handleMenuClose>My account</MenuItem>
    </Menu>
  );

  const mobileMenuId = 'primary-search-account-menu-mobile';
  const renderMobileMenu = (
    <Menu
      anchorEl=mobileMoreAnchorEl
      anchorOrigin= vertical: 'top', horizontal: 'right' 
      id=mobileMenuId
      keepMounted
      transformOrigin= vertical: 'top', horizontal: 'right' 
      open=isMobileMenuOpen
      onClose=handleMobileMenuClose
    >
      <MenuItem>   
      <Icon className="fa fa-plus-circle" />    
     </MenuItem>
      <MenuItem>     
        <IconButton aria-label="show 4 new mails" color="inherit">
          <Badge badgeContent=4 color="secondary">
            <MailIcon />
          </Badge>
        </IconButton>
        <p>Messages</p>
      </MenuItem>
      <MenuItem>
        <IconButton aria-label="show 11 new notifications" color="inherit">
          <Badge badgeContent=11 color="secondary">
            <NotificationsIcon />
          </Badge>
        </IconButton>
        <p>Notifications</p>
      </MenuItem>
      <MenuItem onClick=handleProfileMenuOpen>
        <IconButton
          aria-label="account of current user"
          aria-controls="primary-search-account-menu"
          aria-haspopup="true"
          color="inherit"
        >
          <AccountCircle />
        </IconButton>
        <p>Profile</p>
      </MenuItem>
    </Menu>
  );

  return (
    <div className=Gridclasses.root>
    <Grid container spacing=3>
      <Grid item xs=12>
        <Paper className=Gridclasses.paper>

      <div className=classes.grow>
      <AppBar position="static">
        <Toolbar>
          <IconButton
            edge="start"
            className=classes.menuButton
            color="inherit"
            aria-label="open drawer"
          >
            <MenuIcon />
          </IconButton>
          <Typography className=classes.title variant="h6" noWrap>
            Shopping Center
          </Typography>
          <div className=classes.search>
            <div className=classes.searchIcon>
              <SearchIcon />
            </div>
            <InputBase
              placeholder="Search…"
              classes=
                root: classes.inputRoot,
                input: classes.inputInput,
              
              inputProps= 'aria-label': 'search' 
            />
          </div>
          <div className=classes.grow />
          <div className=classes.sectionDesktop>          
          <IconButton  aria-label="" color="inherit" onClick=onRegisterClick> Sign Up             
            </IconButton> 
            <IconButton aria-label="show 4 new mails" color="inherit">
              <Badge badgeContent=4 color="secondary">
                <MailIcon />
              </Badge>
            </IconButton>
            <IconButton aria-label="show 17 new notifications" color="inherit">
              <Badge badgeContent=17 color="secondary">
                <NotificationsIcon />
              </Badge>
            </IconButton>
            <IconButton
              edge="end"
              aria-label="account of current user"
              aria-controls=menuId
              aria-haspopup="true"
              onClick=handleProfileMenuOpen
              color="inherit"
            >
              <AccountCircle />
            </IconButton>
          </div>
          <div className=classes.sectionMobile>
            <IconButton
              aria-label="show more"
              aria-controls=mobileMenuId
              aria-haspopup="true"
              onClick=handleMobileMenuOpen
              color="inherit"
            >
              <MoreIcon />
            </IconButton>
          </div>
        </Toolbar>
      </AppBar>
      renderMobileMenu
      renderMenu
       </div>
        </Paper>
      </Grid>     
      <GridList cols=3 style=gridListStyle cellHeight="auto">
      nums.map(n => 
        return (
          <GridListTile key=n>
            <ImgMediaCard key=n num=n />
          </GridListTile>
        );
      )
    </GridList>    

    <Grid item xs=6 sm=3>
        <Paper className=Gridclasses.paper>  <DemoCarousel />
        </Paper>
      </Grid>      

    </Grid>      
  </div>
  );


export default App;

但是当我尝试将上面的代码转换为 ES6 类时

import React from 'react';
import  fade,makeStyles  from '@material-ui/core/styles';
import Paper from '@material-ui/core/Paper';
import Grid from '@material-ui/core/Grid';
import Icon from '@material-ui/core/Icon';
import  Redirect  from "react-router-dom";
import './App.css';


/* AppBar*/
//import  fade, makeStyles  from '@material-ui/core/styles';
import AppBar from '@material-ui/core/AppBar';
import Toolbar from '@material-ui/core/Toolbar';
import IconButton from '@material-ui/core/IconButton';
import Typography from '@material-ui/core/Typography';
import InputBase from '@material-ui/core/InputBase';
import Badge from '@material-ui/core/Badge';
import MenuItem from '@material-ui/core/MenuItem';
import Menu from '@material-ui/core/Menu';
import MenuIcon from '@material-ui/icons/Menu';
import SearchIcon from '@material-ui/icons/Search';
import AccountCircle from '@material-ui/icons/AccountCircle';
import MailIcon from '@material-ui/icons/Mail';
import NotificationsIcon from '@material-ui/icons/Notifications';
import MoreIcon from '@material-ui/icons/MoreVert';
/*App bar */

import  ImgMediaCard from './ImgMediaCard';

import GridList from '@material-ui/core/GridList';
import GridListTile from '@material-ui/core/GridListTile';

import DemoCarousel from './MCarousel'

var gridListStyle =   
  marginLeft: "40px"
;

const useStyles = makeStyles(theme => (
  grow: 
    flexGrow: 1,
  ,
  menuButton: 
    marginRight: theme.spacing(2),
  ,
  title: 
    display: 'none',
    [theme.breakpoints.up('sm')]: 
      display: 'block',
    ,
  ,
  search: 
    position: 'relative',
    borderRadius: theme.shape.borderRadius,
    backgroundColor: fade(theme.palette.common.white, 0.15),
    '&:hover': 
      backgroundColor: fade(theme.palette.common.white, 0.25),
    ,
    marginRight: theme.spacing(2),
    marginLeft: 0,
    width: '100%',
    [theme.breakpoints.up('sm')]: 
      marginLeft: theme.spacing(3),
      width: 'auto',
    ,
  ,
  searchIcon: 
    width: theme.spacing(7),
    height: '100%',
    position: 'absolute',
    pointerEvents: 'none',
    display: 'flex',
    alignItems: 'center',
    justifyContent: 'center',
  ,
  inputRoot: 
    color: 'inherit',
  ,
  inputInput: 
    padding: theme.spacing(1, 1, 1, 7),
    transition: theme.transitions.create('width'),
    width: '100%',
    [theme.breakpoints.up('md')]: 
      width: 200,
    ,
  ,
  sectionDesktop: 
    display: 'none',
    [theme.breakpoints.up('md')]: 
      display: 'flex',
    ,
  ,
  sectionMobile: 
    display: 'flex',
    [theme.breakpoints.up('md')]: 
      display: 'none',
    ,
    
));
/*end App bar work*/
const useGridStyles = makeStyles(theme => (
  root: 
    flexGrow: 1,
  ,
  paper: 
    // padding: theme.spacing(2),
    // textAlign: 'center',
    // color: theme.palette.text.secondary,
  ,
));

const Gridclasses = useGridStyles();
const classes = useStyles();  

class App extends React.Component 

  constructor(props) 
    super(props);
    console.log(this.props)
    this.state = 
      anchorEl: null,
      mobileMoreAnchorEl: null   
          

     const isMenuOpen = Boolean(this.state.anchorEl);
     const isMobileMenuOpen = Boolean(this.state.mobileMoreAnchorEl);  



  /*
   const Gridclasses = useGridStyles();
  const classes = useStyles();
  const [anchorEl, setAnchorEl] = React.useState(null);
  const [mobileMoreAnchorEl, setMobileMoreAnchorEl] = React.useState(null); 
  */


  render()
  


    const handleProfileMenuOpen = event => 

      this.setState( open: true, anchorEl: event.currentTarget );

    ;

    const handleMobileMenuClose = () => 

      this.setState( open: false, mobileMoreAnchorEl: null );
    ;


    const handleMenuClose = () => 

      this.setState( open: false, anchorEl: null );
      handleMobileMenuClose();
    ;

    const handleMobileMenuOpen = event => 
           this.setState( open: true, mobileMoreAnchorEl: event.currentTarget );
    ;

    const onRegisterClick = () => 
      //debugger;
      //if(userFound)
          return  <Redirect  to="/RegisterBuyer/" />
     // 
    

    let nums = Array.from(Array(40).keys());
    const menuId = 'primary-search-account-menu';
    const renderMenu = (
      <Menu
        anchorEl=this.state.anchorEl
        anchorOrigin= vertical: 'top', horizontal: 'right' 
        id=menuId
        keepMounted
        transformOrigin= vertical: 'top', horizontal: 'right' 
        open=isMenuOpen
        onClose=handleMenuClose
      >
        <MenuItem onClick=handleMenuClose>Profile</MenuItem>
        <MenuItem onClick=handleMenuClose>My account</MenuItem>
      </Menu>
    );

    const mobileMenuId = 'primary-search-account-menu-mobile';
    const renderMobileMenu = (
      <Menu
        anchorEl=this.state.mobileMoreAnchorEl
        anchorOrigin= vertical: 'top', horizontal: 'right' 
        id=mobileMenuId
        keepMounted
        transformOrigin= vertical: 'top', horizontal: 'right' 
        open=isMobileMenuOpen
        onClose=handleMobileMenuClose
      >
        <MenuItem>   
        <Icon className="fa fa-plus-circle" />    
       </MenuItem>
        <MenuItem>     
          <IconButton aria-label="show 4 new mails" color="inherit">
            <Badge badgeContent=4 color="secondary">
              <MailIcon />
            </Badge>
          </IconButton>
          <p>Messages</p>
        </MenuItem>
        <MenuItem>
          <IconButton aria-label="show 11 new notifications" color="inherit">
            <Badge badgeContent=11 color="secondary">
              <NotificationsIcon />
            </Badge>
          </IconButton>
          <p>Notifications</p>
        </MenuItem>
        <MenuItem onClick=handleProfileMenuOpen>
          <IconButton
            aria-label="account of current user"
            aria-controls="primary-search-account-menu"
            aria-haspopup="true"
            color="inherit"
          >
            <AccountCircle />
          </IconButton>
          <p>Profile</p>
        </MenuItem>
      </Menu>
    );


  return (
    <div className=Gridclasses.root>
    <Grid container spacing=3>
      <Grid item xs=12>
        <Paper className=Gridclasses.paper>

      <div className=classes.grow>
      <AppBar position="static">
        <Toolbar>
          <IconButton
            edge="start"
            className=classes.menuButton
            color="inherit"
            aria-label="open drawer"
          >
            <MenuIcon />
          </IconButton>
          <Typography className=classes.title variant="h6" noWrap>
            Shopping Center
          </Typography>
          <div className=classes.search>
            <div className=classes.searchIcon>
              <SearchIcon />
            </div>
            <InputBase
              placeholder="Search…"
              classes=
                root: classes.inputRoot,
                input: classes.inputInput,
              
              inputProps= 'aria-label': 'search' 
            />
          </div>
          <div className=classes.grow />
          <div className=classes.sectionDesktop>          
          <IconButton  aria-label="" color="inherit" onClick=onRegisterClick> Sign Up             
            </IconButton> 
            <IconButton aria-label="show 4 new mails" color="inherit">
              <Badge badgeContent=4 color="secondary">
                <MailIcon />
              </Badge>
            </IconButton>
            <IconButton aria-label="show 17 new notifications" color="inherit">
              <Badge badgeContent=17 color="secondary">
                <NotificationsIcon />
              </Badge>
            </IconButton>
            <IconButton
              edge="end"
              aria-label="account of current user"
              aria-controls=menuId
              aria-haspopup="true"
              onClick=handleProfileMenuOpen
              color="inherit"
            >
              <AccountCircle />
            </IconButton>
          </div>
          <div className=classes.sectionMobile>
            <IconButton
              aria-label="show more"
              aria-controls=mobileMenuId
              aria-haspopup="true"
              onClick=handleMobileMenuOpen
              color="inherit"
            >
              <MoreIcon />
            </IconButton>
          </div>
        </Toolbar>
      </AppBar>
      renderMobileMenu
      renderMenu
       </div>
        </Paper>
      </Grid>     
      <GridList cols=3 style=gridListStyle cellHeight="auto">
      nums.map(n => 
        return (
          <GridListTile key=n>
            <ImgMediaCard key=n num=n />
          </GridListTile>
        );
      )
    </GridList>    

    <Grid item xs=6 sm=3>
        <Paper className=Gridclasses.paper>  <DemoCarousel />
        </Paper>
      </Grid>    
    </Grid>      
  </div>
    );
  



export default App;







**const isMenuOpen = Boolean(this.state.anchorEl);
const isMobileMenuOpen = Boolean(this.state.mobileMoreAnchorEl);**
<Menu
        anchorEl=this.state.anchorEl
        anchorOrigin= vertical: 'top', horizontal: 'right' 
        id=menuId
        keepMounted
        transformOrigin= vertical: 'top', horizontal: 'right' 
        **open=isMenuOpen**
        onClose=handleMenuClose
      >

 <Menu
        anchorEl=this.state.mobileMoreAnchorEl
        anchorOrigin= vertical: 'top', horizontal: 'right' 
        id=mobileMenuId
        keepMounted
        transformOrigin= vertical: 'top', horizontal: 'right' 
        **open=isMobileMenuOpen**
        onClose=handleMobileMenuClose
      >

行显示以下错误消息:

'isMobileMenuOpen' is assigned a value but never used.
'isMenuOpen' is assigned a value but never used.
'isMenuOpen' is not defined.
'isMobileMenuOpen' is not defined.

我是 react 新手。我应该在我的代码中做什么?

我从这里获取了菜单和卡片的示例代码:https://material-ui.com

使用构建的应用程序


  "react": "16.12.0", 
  "react-dom": "^16.12.0", 
  "react-redux": "^7.1.3",
  "redux": "^4.0.4"
  "@material-ui/core": "^4.7.2"

容器使用react组件,就是重复一张卡片。

输出:菜单、应用栏和卡片应该可以完美运行。

我尝试按照指南查找示例实现,但无法解决问题。

谢谢Jacob,我已经试过了。代码编译成功,但还有一些其他错误。 现在查看错误。 错误:无效的挂钩调用。 Hooks 只能在函数组件的主体内部调用。这可能由于以下原因之一而发生: 1. React 和渲染器的版本可能不匹配(例如 React DOM) 2. 你可能违反了 Hooks 规则 3. 你可能在同一个应用程序中拥有多个 React 副本 有关如何调试和修复此问题的提示,请参阅 react-invalid-hook-call。 4 个堆栈帧被折叠。

【问题讨论】:

你为什么要把它转换成一个类? 代码不会告诉我为什么你要这样做。 @maifs 你不应该努力将功能组件转换为类组件。与类组件相比,函数式组件在性能方面更加明智,并且函数式组件更易于使用。 @maifs 函数式组件是编写组件的一种非常合适的方式,您真的不需要将它们转换为类组件。 ES6 类不是编写正确的 React 代码的新方法。函数组件为the preferred approach for new React code。 【参考方案1】:

正如大家所说,您不需要转换为班级。但是,要回答您关于错误的问题,它们与 React 并没有真正的关系,只是简单的 javascript。请注意,您在类 constructor 函数中定义常量:

constructor() 
  // ...
  const isMenuOpen = Boolean(this.state.anchorEl);
  const isMobileMenuOpen = Boolean(this.state.mobileMoreAnchorEl);  

...但是那些没有在构造函数中使用(因此您会收到 linting 警告)。它们在render() 函数中被引用,但由于它们没有在该范围内声明,因此这些变量将是未定义的。在一个函数中声明的变量不会在对等函数中看到,即使在构造函数中声明也是如此。

您需要将变量声明移至渲染函数。

【讨论】:

jacob,查看我帖子中的回复 新的错误告诉你所有你需要知道的;如果您使用挂钩(useStateuseEffect 等),则不能使用基于类的组件。它们仅用于功能组件。 jacob,我怎样才能在课堂上使用这些钩子呢?你能在上面的帖子中推荐我吗?您的回复将不胜感激。 不可能。 Hooks 专门用于非基于类的组件。 Jacob,为一个类实现类似任务的替代方法是什么?

以上是关于如何将材料 ui 纯 reactjs 函数转换为 es6 类?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用获取的变量作为材料 UI 日期选择器的初始状态?

ReactJS:在现有状态转换期间无法更新(例如在 `render` 中)。渲染方法应该是 props 和 state 的纯函数

如何将此基于 ReactJS 类的组件转换为基于函数的组件?

创建组件后,reactJS 材料 ui 中的平滑崩溃损坏

Reactjs - 通过在自动完成组件(材料 UI)中的每个输入更改上点击 API 来更新选项

ReactJS + Material-UI:如何使用 Material-UI 的 <DatePicker> 将当前日期设置为默认值?