如何将材料 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,查看我帖子中的回复 新的错误告诉你所有你需要知道的;如果您使用挂钩(useState
、useEffect
等),则不能使用基于类的组件。它们仅用于功能组件。
jacob,我怎样才能在课堂上使用这些钩子呢?你能在上面的帖子中推荐我吗?您的回复将不胜感激。
不可能。 Hooks 专门用于非基于类的组件。
Jacob,为一个类实现类似任务的替代方法是什么?以上是关于如何将材料 ui 纯 reactjs 函数转换为 es6 类?的主要内容,如果未能解决你的问题,请参考以下文章
ReactJS:在现有状态转换期间无法更新(例如在 `render` 中)。渲染方法应该是 props 和 state 的纯函数
如何将此基于 ReactJS 类的组件转换为基于函数的组件?
Reactjs - 通过在自动完成组件(材料 UI)中的每个输入更改上点击 API 来更新选项
ReactJS + Material-UI:如何使用 Material-UI 的 <DatePicker> 将当前日期设置为默认值?