I am doing a web application with react and I am getting this warning:
Warning: Cannot update a component (`ContextProvider`) while rendering a different component (`NavBar`). To locate the bad setState() call inside `NavBar`, follow the stack trace as described in https://reactjs.org/link/setstate-in-render
I have been looking for a solution but I haven't been able to fix the problem.
This is my code:
Main.jsx
ReactDOM.createRoot(document.getElementById('root')).render(
<React.StrictMode>
<BrowserRouter>
<AuthProvider>
<Routes>
<Route path="/*" element={<App />} />
</Routes>
</AuthProvider>
</BrowserRouter>
</React.StrictMode>
)
App.jsx
Here, I separate the routes that require authentication. The ... means that there are some more routes there.
function App() {
return (
<Routes>
<Route path='/' element={<Layout />}>
{/* public routes */}
<Route element={<RequireNoAuth />}>
<Route path='/login' element={<Login />} />
<Route path='/register' element={<Register />} />
</Route>
{/* protected routes */}
<Route element={<RequireAuth />}>
<Route path='/' element={<Home />} />
...
</Route>
</Route>
</Routes>
)
}
Home.jsx
This is the file where the error occurs, specifically in the component AdministrationLayout
, which I call the Contextprovider
.
const Home = () => {
return (
<AdministrationLayout>
<Container fluid>
<Row>
<Col>
<h3>{i18n.t("dashboard.title")}</h3>
</Col>
</Row>
</Container>
</AdministrationLayout>
)
}
AdministrationLayout.jsx
const AdministrationLayout = ({ children }) => {
return (
<div className='cms-container'>
<ContextProvider>
<NavBar />
<ContentContainer>
{ children }
</ContentContainer>
</ContextProvider>
</div>
)
}
Finally, this is my contextProvider:
export const ContextProvider = ({ children }) => {
const [showMenu, setShowMenu] = useState(true);
const [activeMenu, setActiveMenu] = useState(readActiveMenu());
const [screenSize, setScreenSize] = useState(undefined);
const handleMenuClick = (menuSection) => {
setActiveMenu(menuSection);
saveActiveMenu(menuSection);
}
return (
<StateContext.Provider
value={{ showMenu, setShowMenu, activeMenu, setActiveMenu, screenSize, setScreenSize}}
>
{ children }
</StateContext.Provider>
);
}
NavBar.jsx
const NavBar = () => {
const auth = useAuth();
const navigate = useNavigate();
const location = useLocation();
const from = location.state?.from?.pathname || "/";
const { showMenu, setShowMenu, setActiveMenu } = useStateContext();
const [showNotificationsOptions, setShowNotificationsOptions] = useState(false);
const [showUserOptions, setShowUserOptions] = useState(false);
const handleLogout = () => {
setActiveMenu("dashboard");
auth.logout();
navigate(from, { replace: true });
}
const toogleNotificationsOptions = () => {
setShowNotificationsOptions((prevState) => !prevState);
}
const toogleUserOptions = () => {
setShowUserOptions((prevState) => !prevState);
}
return (
<div className='navbar-container'>
<div className='top-bar-container'>
<div className='button-menu-container'>
<NavBarButton customFunction={setShowMenu((prevState) => !prevState)} icon={<FaBars />} classStyle='button-menu' />
<div className='title'>
<span>TEJIDOS</span>
<span>PULIDO</span>
</div>
</div>
<div className='session-menu-container'>
<NavBarButton customFunction={toogleNotificationsOptions} icon={<FaBell />} classStyle='button-menu' />
<div className='session-container'>
<div className='session-name'>{auth.token}</div>
<div className='session-button' onClick={toogleUserOptions}>
<FaUserAlt />
<FaChevronDown />
{(showUserOptions)
? <div className='user-options-contianer'>
<div onClick={handleLogout}>{i18n.t("shared.logout")}</div>
</div>
: null
}
</div>
</div>
</div>
</div>
</div>
)
}