javascript - 组件每次渲染调用函数 10 次
问题描述
我正在尝试测试我的一个组件。它NavigationDrawer
来自 Material-UI,它有一个名为的道具toggleDrawer()
,它完全可以做到这一点并切换抽屉。
每次组件渲染时,它都会在toggleDrawer()
1ms - 2ms 的时间段内调用该函数 10 次。我很困惑为什么会这样做,如果可能的话,我想解决它。
这是组件:
import React from "react";
import PropTypes from "prop-types";
import { withStyles } from "@material-ui/core/styles";
import { styles } from "../styles/NavigationDrawerStyles";
import Drawer from "@material-ui/core/Drawer";
import List from "@material-ui/core/List";
import ListItem from "@material-ui/core/ListItem";
import ListItemText from "@material-ui/core/ListItemText";
import ListItemIcon from "@material-ui/core/ListItemIcon";
import Collapse from "@material-ui/core/Collapse";
import ExpandLess from "@material-ui/icons/ExpandLess";
import ExpandMore from "@material-ui/icons/ExpandMore";
import ViewListIcon from "@material-ui/icons/ViewListOutlined";
import CreateOutlinedIcon from "@material-ui/icons/CreateOutlined";
import ShuffleIcon from "@material-ui/icons/Shuffle";
import ChevronLeftIcon from "@material-ui/icons/ChevronLeft";
import HomeIcon from "@material-ui/icons/HomeOutlined";
import ContactsIcon from "@material-ui/icons/ContactsOutlined";
import BusinessIcon from "@material-ui/icons/BusinessOutlined";
import IconButton from "@material-ui/core/IconButton";
import DescriptionIcon from "@material-ui/icons/DescriptionOutlined";
import DashboardOutlinedIcon from "@material-ui/icons/DashboardOutlined";
import BookOutlinedIcon from "@material-ui/icons/BookOutlined";
import Divider from "@material-ui/core/Divider";
import { Link } from "react-router-dom";
class NavigationDrawer extends React.Component {
constructor(props) {
super(props);
this.state = {
postsOpen: false,
policiesOpen: false
};
}
handlePostsClick = () => {
this.setState(state => ({ postsOpen: !state.postsOpen }));
};
handlePoliciesClick = () => {
this.setState(state => ({ policiesOpen: !state.policiesOpen }));
};
render() {
const { classes, toggleDrawer, open } = this.props;
const { postsOpen, policiesOpen } = this.state;
return (
<React.Fragment>
<Drawer
open={open}
onClose={toggleDrawer(false)}
className={classes.drawerPaper}
>
<div
tabIndex={0}
role="button"
//onClick={toggleDrawer(false)}
//onKeyDown={toggleDrawer(false)}
className={classes.list}
>
<div className={classes.drawerHeader}>
<IconButton
className={classes.CloseIcon}
onClick={toggleDrawer(false)}
>
<ChevronLeftIcon />
</IconButton>
</div>
<Divider />
<List>
<ListItem
button
component={Link}
to="/"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<HomeIcon />
</ListItemIcon>
<ListItemText inset primary="Home" />
</ListItem>
<ListItem button onClick={this.handlePostsClick}>
<ListItemIcon>
<DashboardOutlinedIcon />
</ListItemIcon>
<ListItemText inset primary="Posts" />
{postsOpen ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={postsOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem
button
className={classes.nested}
id="posts-nested-dropdown"
component={Link}
to="/posts/"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<ViewListIcon />
</ListItemIcon>
<ListItemText inset primary="Recent Posts" />
</ListItem>
<ListItem
button
className={classes.nested}
component={Link}
to="/posts/create/"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<CreateOutlinedIcon />
</ListItemIcon>
<ListItemText inset primary="Create a Post" />
</ListItem>
<ListItem button className={classes.nested}>
<ListItemIcon>
<ShuffleIcon />
</ListItemIcon>
<ListItemText inset primary="Random Post" />
</ListItem>
</List>
</Collapse>
<ListItem
button
component={Link}
to="/about"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<BusinessIcon />
</ListItemIcon>
<ListItemText inset primary="About" />
</ListItem>
<ListItem
button
component={Link}
to="/contact"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<ContactsIcon />
</ListItemIcon>
<ListItemText inset primary="Contact" />
</ListItem>
<ListItem
button
component="a"
href="http://docs.chbresser.com"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<DescriptionIcon />
</ListItemIcon>
<ListItemText inset primary="Docs" />
</ListItem>
<Divider />
<ListItem button onClick={this.handlePoliciesClick}>
<ListItemIcon>
<BookOutlinedIcon />
</ListItemIcon>
<ListItemText inset primary="Important Policies" />
{policiesOpen ? <ExpandLess /> : <ExpandMore />}
</ListItem>
<Collapse in={policiesOpen} timeout="auto" unmountOnExit>
<List component="div" disablePadding>
<ListItem
button
className={classes.nested}
component={Link}
to="/privacy/"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<ViewListIcon />
</ListItemIcon>
<ListItemText inset primary="Privacy Policy" />
</ListItem>
<ListItem
button
className={classes.nested}
component={Link}
to="/terms/"
onClick={toggleDrawer(false)}
>
<ListItemIcon>
<ViewListIcon />
</ListItemIcon>
<ListItemText inset primary="Terms and Conditions" />
</ListItem>
</List>
</Collapse>
</List>
<div className={classes.drawerFooter}>
<i
className={`fas fa-hand-holding-heart ${classes.footerIcon}`}
/>{" "}
Made with love by the TechHorizon team.
<br />
</div>
</div>
</Drawer>
</React.Fragment>
);
}
}
NavigationDrawer.propTypes = {
classes: PropTypes.object.isRequired,
toggleDrawer: PropTypes.func.isRequired
};
export default withStyles(styles)(NavigationDrawer);
这是我到目前为止的测试:
import { createShallow } from "@material-ui/core/test-utils";
import React from "react";
import NavigationDrawer from "../components/NavigationDrawer";
import "jest-dom/extend-expect";
const toggleDrawer = jest.fn();
describe("<NavigationDrawer />", () => {
let shallow;
beforeEach(() => {
shallow = createShallow({ dive: true });
});
it("renders a Drawer", () => {
const page = shallow(<NavigationDrawer toggleDrawer={toggleDrawer} />);
expect(toggleDrawer.mock.calls.length).toEqual(0);
expect(page.find("WithStyles(Drawer)").length).toEqual(1);
});
it("renders the main List and 2 dropdown Lists", () => {
const page = shallow(<NavigationDrawer toggleDrawer={toggleDrawer} />);
expect(page.find("WithStyles(List)").length).toEqual(3);
});
it("opens posts menu on click", () => {
const page = shallow(<NavigationDrawer toggleDrawer={toggleDrawer} />);
expect(toggleDrawer.mock.calls.length).toEqual(1);
});
});
每次测试它都会调用toggleDrawer()
10 次以上。
解决方案
这条线是你的问题(它重复了 10 次):
onClick={toggleDrawer(false)}
不是将带有此参数的函数传递给 的道具,而是ListItem
调用toggleDrawer(false)
并将该函数调用的结果作为道具传递。
如果你想在事件触发时toggleDrawer()
使用参数调用,你应该将它包装在这样的函数中:false
onClick
onClick={() => toggleDrawer(false)}
或者,您可以Function.prototype.bind()
像这样使用:
onClick={toggleDrawer.bind(this, false)}
这两个都被列为React 文档中的推荐选项。
这种行为与在纯 HTML 中附加事件处理程序的方式明显不同:
HTML: <div onclick="handleEvent()" />
JSX: <div onClick={handleEvent} />
推荐阅读
- node.js - 如何让机器人在不使用命令的情况下向特定频道中的特定公会发送消息
- python - Databricks CLI 未在 Ubuntu 18.04 上安装
- python - Tensorflow Lite - ValueError:无法设置张量:尺寸不匹配
- python - 无法重新导入python tensorflow模块
- javascript - 当 AJAX 加载成功完成时做一些事情
- python - 在熊猫中分隔数据框
- flask - Flask:为使用 Openpyxl 创建的 Excel 文件创建可下载链接
- wordpress - 从除类别(WP)之外的永久链接中删除尾部斜杠
- c# - 防止 cookie 重播/cookie 被多个客户端使用
- linux - 无法从 USB 驱动器下载驱动程序