未捕获的不变违规:重新渲染过多React限制渲染次数以防止无限循环

【字号: 日期:2024-04-19浏览:24作者:雯心
(adsbygoogle = window.adsbygoogle || []).push({}); 如何解决未捕获的不变违规:重新渲染过多React限制渲染次数以防止无限循环?

我怀疑问题在于您正在函数组件主体内部立即调用状态设置器,这迫使React使用相同的道具再次重新调用您的函数,最终导致再次调用状态设置器,从而触发做出反应以再次调用您的函数……等等。

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属性的默认值,因此最终得到:

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> <SnackbaranchorOrigin={{ 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和acomponentShouldUpdate以便不多次渲染?

相关文章: