我怀疑问题在于您正在函数组件主体内部立即调用状态设置器,这迫使React使用相同的道具再次重新调用您的函数,最终导致再次调用状态设置器,从而触发做出反应以再次调用您的函数……等等。
@H_502_2@ const SingInContainer = ({ message, variant}) => { const [open, setSnackBarState] = useState(false); const handleClose = (reason) => { if (reason === 'clickaway') { return; } setSnackBarState(false) }; if (variant) { setSnackBarState(true); // HERE BE DRAGONS } return ( <div> <SnackBar open={open} handleClose={handleClose} variant={variant} message={message} /> <SignInForm/> </div> ) }相反,我建议您仅使用三元有条件地设置state属性的默认值,因此最终得到:
@H_502_2@ const SingInContainer = ({ message, variant}) => { const [open, setSnackBarState] = useState(variant ? true : false); // or useState(!!variant); // or useState(Boolean(variant)); const handleClose = (reason) => { if (reason === 'clickaway') { return; } setSnackBarState(false) }; return ( <div> <SnackBar open={open} handleClose={handleClose} variant={variant} message={message} /> <SignInForm/> </div> ) } 综合演示请参阅此CodeSandbox.io演示以全面了解其工作原理,以及损坏的组件,您可以在两者之间进行切换。
解决方法我试图添加一个快餐栏,以便在用户登录或不登录时显示一条消息。SnackBar.jsx:
import React from "react"; import PropTypes from "prop-types"; import classNames from "classnames"; import CheckCircleIcon from "@material-ui/icons/CheckCircle"; import ErrorIcon from "@material-ui/icons/Error"; import CloseIcon from "@material-ui/icons/Close"; import green from "@material-ui/core/colors/green"; import IconButton from "@material-ui/core/IconButton"; import Snackbar from "@material-ui/core/Snackbar"; import SnackbarContent from "@material-ui/core/SnackbarContent"; import { withStyles } from "@material-ui/core/styles"; const variantIcon = { success: CheckCircleIcon,error: ErrorIcon }; const styles1 = theme => ({ success: { backgroundColor: green[600] },error: { backgroundColor: theme.palette.error.dark },icon: { fontSize: 20 },iconVariant: { opacity: 0.9,marginRight: theme.spacing.unit },message: { display: "flex",alignItems: "center" } }); function SnackbarContentWrapper(props) { const { classes,className,message,onClose,variant,...other } = props; const Icon = variantIcon[variant]; return ( <SnackbarContent className={classNames(classes[variant],className)} aria-describedby="client-snackbar" message={( <span className={classes.message}> <Icon className={classNames(classes.icon,classes.iconVariant)} /> {message} </span> )} action={[ <IconButton key="close" aria-label="Close" color="inherit" className={classes.close} onClick={onClose} > <CloseIcon className={classes.icon} /> </IconButton> ]} {...other} /> ); } SnackbarContentWrapper.propTypes = { classes: PropTypes.shape({ success: PropTypes.string,error: PropTypes.string,icon: PropTypes.string,iconVariant: PropTypes.string,message: PropTypes.string,}).isRequired,className: PropTypes.string.isRequired,message: PropTypes.node.isRequired,onClose: PropTypes.func.isRequired,variant: PropTypes.oneOf(["success","error"]).isRequired }; const MySnackbarContentWrapper = withStyles(styles1)(SnackbarContentWrapper); const CustomizedSnackbar = ({ open,handleClose,message }) => { return ( <div> <Snackbar anchorOrigin={{ vertical: "bottom",horizontal: "left" }} open={open} autoHideDuration={6000} onClose={handleClose} > <MySnackbarContentWrapper onClose={handleClose} variant={variant} message={message} /> </Snackbar> </div> ); }; CustomizedSnackbar.propTypes = { open: PropTypes.bool.isRequired,handleClose: PropTypes.func.isRequired,variant: PropTypes.string.isRequired,message: PropTypes.string.isRequired }; export default CustomizedSnackbar;
SignInFormContainer.jsx:
import React,{ useState } from 'react'; import PropTypes from 'prop-types'; import { connect } from 'react-redux'; import SnackBar from '../../components/SnackBar'; import SignInForm from './SignInForm'; const SingInContainer = ({ message,variant}) => { const [open,setSnackBarState] = useState(false); const handleClose = (reason) => { if (reason === 'clickaway') { return; } setSnackBarState(false) }; if (variant) { setSnackBarState(true); } return ( <div> <SnackBar open={open} handleClose={handleClose} variant={variant} message={message} /> <SignInForm/> </div> ) } SingInContainer.propTypes = { variant: PropTypes.string.isRequired,message: PropTypes.string.isRequired } const mapStateToProps = (state) => { const {variant,message } = state.snackBar; return { variant,message } } export default connect(mapStateToProps)(SingInContainer);
当我运行应用程序时,出现以下错误:
Invariant Violation: Too many re-renders. React limits the number of renders to prevent an infinite loop. at invariant (http://localhost:9000/bundle.js:34484:15) at dispatchAction (http://localhost:9000/bundle.js:47879:44) at SingInContainer (http://localhost:9000/bundle.js:79135:5) at renderWithHooks (http://localhost:9000/bundle.js:47343:18) at updateFunctionComponent (http://localhost:9000/bundle.js:49010:20) at beginWork (http://localhost:9000/bundle.js:50020:16) at performUnitOfWork (http://localhost:9000/bundle.js:53695:12) at workLoop (http://localhost:9000/bundle.js:53735:24) at HTMLUnknownElement.callCallback (http://localhost:9000/bundle.js:34578:14) at Object.invokeGuardedCallbackDev (http://localhost:9000/bundle.js:34628:16)
问题是由于SnackBar组件。我使用useState钩子来更改SnackBar的状态。我是否应该使用class和a
componentShouldUpdate以便不多次渲染?
评论列表