programing

적발되지 않은 불변 위반:리렌더가 너무 많아무한 루프를 방지하기 위해 리액트는 렌더링 수를 제한합니다.

lastmemo 2023. 3. 2. 21:56
반응형

적발되지 않은 불변 위반:리렌더가 너무 많아무한 루프를 방지하기 위해 리액트는 렌더링 수를 제한합니다.

사용자가 로그인하거나 로그인하지 않을 때마다 메시지를 표시하기 위해 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)

이 문제는 스낵바의 컴포넌트에 기인합니다. 용 the the the를 .useState★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★와 A를 요?componentShouldUpdate러러 번번 더더??? ????

이 문제는 함수 컴포넌트 본체 내에서 상태 설정기를 바로 호출하고 있다는 데 있습니다.이 경우 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>
    )
}

대신 3진수를 사용하여 상태 속성의 기본값을 조건부로 설정하면 다음과 같은 결과를 얻을 수 있습니다.

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 데모에서는 동작에 관한 포괄적인 데모와 고장난 컴포넌트를 소개하고 있습니다.이 데모에서는, 2개의 컴포넌트를 전환할 수 있습니다.

»SnackbarContentWrapper 가 있다

<IconButton
  key="close"
  aria-label="Close"
  color="inherit"
  className={classes.close}
  onClick={onClose} // change this
>

로.

<IconButton
  key="close"
  aria-label="Close"
  color="inherit"
  className={classes.close}
  onClick={() => onClose()} // to this
>

클릭할 때만 액션이 실행되도록 합니다.

그냥 카레를 .handleCloseSignInContainer 접속합니다.

const handleClose = () => (reason) => {
  if (reason === 'clickaway') {
    return;
  }
  setSnackBarState(false)
};

마찬가지다.

onClick에서 이벤트를 링크해야 합니다.또한 클릭 기능은 이벤트를 수신해야 합니다.예를 참조해 주세요.

export default function Component(props) {

    function clickEvent (event, variable){
        console.log(variable);
    }

    return (
        <div>
            <IconButton
                key="close"
                aria-label="Close"
                color="inherit"
                onClick={e => clickEvent(e, 10)}
            >
        </div>
    )
}

함수를 호출하는 동안 이렇게 이벤트를 추가합니다.

전에

 <button onClick={ decrementCount() }>-</button>

끝나고

 <button onClick={ () => decrementCount() }>-</button>

다음과 같이 핸들을 호출하기 전에 이벤트를 추가해야 합니다.

function SingInContainer() {
..
..
handleClose = () => {
}

return (
    <SnackBar
        open={open}
        handleClose={() => handleClose}
        variant={variant}
        message={message}
        />
    <SignInForm/>
  )
}

내가 들은 바로는, 우리가 많은 함수를 호출할 때 에러가 발생하는 것 같다.

★★★★★★★★★★★★★★★★★.setState()

하기 위한 한 가지 은 " " " 함수를 입니다.setState by directly에 의해onClick예를들면.

이와 같은 상태를 많이 사용하면 리액션이 여러 번 반복되어 이 오류가 발생할 수 있습니다.

괄호가 있는 함수를 전달한 경우 컴포넌트가 렌더링될 때마다 함수가 실행됩니다.하기 위해 '이렇게'를 하겠습니다.()=>기능을 사용할 수 있습니다.

또한 동일한 문제가 있습니다. 해결 방법은 이벤트가 onClick에서 바인딩되지 않았기 때문에 처음 렌더링되고 데이터가 많아지면 상태 설정기를 다시 호출하게 되고, 이 경우 React가 기능을 다시 호출하게 됩니다.

export default function Component(props) {

function clickEvent (event, variable){
    console.log(variable);
}

return (
    <div>
        <IconButton
            key="close"
            aria-label="Close"
            color="inherit"
            onClick={e => clickEvent(e, 10)} // or you can call like this:onClick={() => clickEvent(10)} 
        >
    </div>
)
}

함수 내부에서 후크를 사용하여 이 오류를 방지할 수 있습니다.

나의 경우 잘못된 원인으로 인한 것이다.attribute이름.onblur={setFieldTouched('firstName')} -->onBlur={()=>setFieldTouched('firstName')}. Atribute name 오류 수정 후 사라짐

할 수 있을 것 같아.저희 집에서는 문제없이 동작합니다.

const handleClose = (reason) => {
  if (reason === 'clickaway') {
    return;
  }
  setSnackBarState(false);
};
<SnackBar
    open={open}
    handleClose={()=>handleClose(r)}
    variant={variant}
    message={message}
    />

prevent Default()가 포함되어 있는지 여부를 참조하십시오.저 같은 경우에는 그것을 사용하는 것을 잊어버리고 나중에 그 실수를 발견하게 됩니다.

저도 비슷한 문제가 있었는데 시나리오가 달랐어요. useEffect(()=>{},[])이 에러로부터 나를 구했다.

setState를 전달하면 바로 호출할 수 있습니다.이것을 다음과 같이 설정하지 말아 주세요.

변수={setState()}

대신, 그렇게 하세요:

변수={setState()}

함수에 setState가 있고 함수를 전달할 때 함수를 직접 호출하는 경우가 있습니다.이 때문에 이 문제가 발생합니다.

이 오류는 함수 이름 뒤에 parantesis를 사용하여 반환하기 때문입니다.

import React, { useState } from "react";

const 개수 = ( ) = > { const [num, setnum] = useState(0)

const increment = () => {
    setnum((prev) => {
        return prev + 1
    })
    setnum((prev) => {
        return prev + 1
    })

}

const decrement = () => {
    setnum(num - 1)
}

return (
    <div>
        <button onClick={increment}>+</button>
        {num}
        <button onClick={decrement}>-</button>
    </div>
)

} 내보내기 기본 수;

사용 안 함 :: 반환 섹션의 onClick= {click()} 또는 onClick= {clickment()}

언급URL : https://stackoverflow.com/questions/55265604/uncaught-invariant-violation-too-many-re-renders-react-limits-the-number-of-re

반응형