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

我试图添加一个快餐栏,以便在用户登录或不登录时显示一条消息。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,

variant,

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以便不多次渲染?

回答:

我怀疑问题在于您正在函数组件主体内部立即调用状态设置器,这迫使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演示以全面了解其工作原理,以及损坏的组件,您可以在两者之间进行切换。

以上是 未捕获的不变违规:重新渲染过多。React限制渲染次数以防止无限循环 的全部内容, 来源链接: utcz.com/qa/404276.html

回到顶部