反应,太多的重新渲染
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}
正在另一个组件的按钮中使用,单击时,将发送 true
。 setOpen
设置新的打开状态为true
,所以Dialog
可以弹出。同时 useEffect
正在观察 setOpening
的变化(可能这也是错误的,我试图使这项工作没有成功)。如果关闭,handleClose
被触发,现在 setOpening
等于 false
,因此 useEffect
检测到变化并执行 setOpen
到 false
。我没有看到循环,而且代码没有按预期工作。
编辑 - 添加父亲属代码
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}>
给定以下代码:
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}
正在另一个组件的按钮中使用,单击时,将发送 true
。 setOpen
设置新的打开状态为true
,所以Dialog
可以弹出。同时 useEffect
正在观察 setOpening
的变化(可能这也是错误的,我试图使这项工作没有成功)。如果关闭,handleClose
被触发,现在 setOpening
等于 false
,因此 useEffect
检测到变化并执行 setOpen
到 false
。我没有看到循环,而且代码没有按预期工作。
编辑 - 添加父亲属代码
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}>