微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

javascript-未捕获的不变违规:重新渲染过多. 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,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组件.我使用useStatehooks来更改SnackBar的状态.我是否应该使用一个类和一个componentShouldUpdate以便不多次渲染?

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

const SingInContainer = ({ message,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,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 demo,以获取有关其工作原理的全面演示,以及损坏的组件,您可以在两者之间进行切换.

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐