反应,太多的重新渲染

React, Too many rerenders

给定以下代码:

export default function CrearContacto({setOpening}) {
    
      const [open, setOpen] = useState(false);
      setOpen(setOpening);
    
      useEffect(() => {
        console.log(setOpening);
        setOpen(setOpening);
      }, [setOpening]); 
    
      const handleClose = () =>{setOpening=false};
    
      return (
        <div>
          <Dialog open={open} onClose={handleClose}>
//code continues

我遇到了“重新渲染太多”错误,但是我无法查看这里的循环在哪里。 {setOpening} 正在另一个组件的按钮中使用,单击时,将发送 truesetOpen设置新的打开状态为true,所以Dialog可以弹出。同时 useEffect 正在观察 setOpening 的变化(可能这也是错误的,我试图使这项工作没有成功)。如果关闭,handleClose 被触发,现在 setOpening 等于 false,因此 useEffect 检测到变化并执行 setOpenfalse。我没有看到循环,而且代码没有按预期工作。

编辑 - 添加父亲属代码

function Agenda() {
 const MiContexto = useOutletContext();
 return (<CrearContacto setOpening={MiContexto.modalState}/>
//code continues

主布局class:

 import Navbar from "./Navbar"
    import Topbar from "./Topbar"
    import React, {useReducer} from "react";
    import { Outlet, useOutletContext } from "react-router-dom";
    
    export const MainContexto = React.createContext({modalState:false});
    
    const initialState=false;
    
    const estadosPosiblesModal = (state, action) =>{
      switch(action){
        case false:
          return false;
        case true:
          return true;
        default: 
          return state;
      }
    }
    const MainLayout = ()=> {
    const [EstadoModal, dispatch] = useReducer(estadosPosiblesModal,initialState);
    
      return (
        <MainContexto.Provider value={{modalState:EstadoModal,modalDispatch:dispatch}}>
          <div className="mainlayout">
            <Navbar/>
            <main className="mainlayout_topPlusContent">
              <Topbar className="TopBar" prueba={EstadoModal}/>
              <Outlet context={{modalState:EstadoModal,modalDispatch:dispatch}}/>
            </main>
          </div>
        </MainContexto.Provider>
      );
        
    };
    
      export default MainLayout;

我不得不同时使用自定义上下文和路由器出口上下文,因为我的上下文没有通过出口。

顶栏包含:

  const micontext = useContext(MainContexto);
...
        <Button variant="contained" onClick={()=>micontext.modalDispatch(true)}>

您的问题是您在组件级别 CrearContacto 上调用 setOpen(setOpening),这导致该组件出现无限 re-renderings。你可以想象这个循环:state update (setOpen(setOpening)) > re-rendering > 再次调用state update > ...

还有一个问题就是不能直接设置setOpening=false,需要在父组件中设置状态setter。

export default function CrearContacto({setOpening}) {
      
      const [open, setOpen] = useState(setOpening);
      //setOpen(setOpening); //remove this part

      useEffect(() => {
         setOpen(setOpening)
      },[setOpening])
    
      const handleClose = () =>{setOpen(false)}; //set `open` state internally instead
    
      return (
        <div>
          <Dialog open={open} onClose={handleClose}>
        </div>)
}

如果你想更新父组件的状态,你应该将状态 setter 和状态值传递给你的子组件,它也是 CrearContacto

我假设你在父组件上有这个状态

const [opening, setOpening] = useState(false);

请注意 setOpening 遵循州 setter 的命名约定,所以我更愿意这样做

您可以尝试像下面这样修改您的组件

export default function CrearContacto({setOpening, opening}) {
      
      const [open, setOpen] = useState(opening);
      //setOpen(setOpening); //remove this part

      useEffect(() => {
         setOpen(opening)
      },[opening])
    
    
      const handleClose = () =>{setOpening(false)};
    
      return (
        <div>
          <Dialog open={open} onClose={handleClose}>
        </div>)
}

如果您只对 Dialog 使用 open 状态,您也可以删除该状态声明

export default function CrearContacto({setOpening, opening}) {
    
      const handleClose = () =>{setOpening(false)};
    
      return (
        <div>
          <Dialog open={opening} onClose={handleClose}>
        </div>)
}

扩展我的评论:

  • 从内部(或子)组件,您可以使用状态更改 open 值,因此调用 setOpen 函数。
  • 从父组件中,您可以通过更改属性 setOpening 来更改 open 的值(重命名此属性,因为它听起来像是一个函数),因此您将拥有:
export default function CrearContacto({setOpening}) {
    
      const [open, setOpen] = useState(setOpening);
    
      useEffect(() => {
        console.log(setOpening);
        setOpen(setOpening);
      }, [setOpening]); 
    
      const handleClose = () =>{setOpen(false)};
    
      return (
        <div>
          <Dialog open={open} onClose={handleClose}>