Home > database >  Problem with separating ContextProvider from app.jsx
Problem with separating ContextProvider from app.jsx

Time:09-09

I just started using createContext/useContext and after successfuly implementing it I would like now to put it in seperate file. The problem is that i am getting error of too many re-renders and I don't really know whats the problem. Could you give me a clue what might be wrong? Below I have put context code,app.js and example of component where context is actually used.

***context***
import React, { createContext, useState } from "react";

export const DarkModeContext = createContext({
  isDarkMode: false,
  toggleIsDarkMode: () => {},
});

export const DarkModeContextProvider = ({ children }) => {
  const [isDarkMode, setIsDarkMode] = useState(false);
  const toggleIsDarkMode = setIsDarkMode((prev) => !prev);

  const value = {
    isDarkMode,
    toggleIsDarkMode,
  };

  return (
    <DarkModeContext.Provider value={value}>
      {children}
    </DarkModeContext.Provider>
  );
};
*** App.js***
import { useContext } from "react";
import { BrowserRouter as Router, Route, Routes } from "react-router-dom";
import Navbar from "../components/Navbar";
import MainSection from "../components/MainSection/MainSection";
import CountryPage from "../components/CountryPage";
import { Wrapper } from "./App.styles";
import { DarkModeContext, DarkModeContextProvider } from "./DarkModeContext";

function App() {
  const { isDarkMode } = useContext(DarkModeContext);
  return (
    <DarkModeContextProvider>
      <Router>
        <Wrapper dark={isDarkMode}>
          <Navbar />
          <Routes>
            <Route path="/" element={<MainSection />}></Route>
            <Route
              path="/country/:countryCode"
              element={<CountryPage />}
            ></Route>
          </Routes>
        </Wrapper>
      </Router>
    </DarkModeContextProvider>
  );
}

***part of component***
import {useContext} from "react"
import { DarkModeContext } from "../../App/DarkModeContext";

export default function CountryPage() {
  const { isDarkMode } = useContext(DarkModeContext);
return (
    <CountryPageWrapper dark={isDarkMode}>
      <StyledLink dark={isDarkMode} to="/">

CodePudding user response:

What I'm noticing is that in DarkModeContextProvider you are calling setIsDarkMode on every render rather than wrapping that method in another function (you should also be passing the boolean value and not a function updating it). Try updating that line to:

 const toggleIsDarkMode = () => { setIsDarkMode(!isDarkMode) };

Assuming you meant the toggler to be a function, this should prevent your re-rendering loop as the setter is only getting called when the toggle is called into action.

CodePudding user response:

You can't create a context provider and consume its value in the same component.

For example in App right now you have this:

  // ...
  const { isDarkMode } = useContext(DarkModeContext);
  return (
    <DarkModeContextProvider>
      <Router>
        <Wrapper dark={isDarkMode}>
  // ...

This doesn't work, because where is useContext(DarkModeContext) getting the value of its context from? It hasn't been rendered yet, until you render <DarkModeContextProvider> which happens after trying to get the value of isDarkMode from the context. This is backwards.

One easy way to to fix this could be to simply move your <DarkModeContextProvider> out of App and into where you render <App />. I assume you're using React DOM somewhere to render your app, so where you are using that try something like this:

ReactDOM.render((
  <DarkModeContextProvider>
    <App />
  </DarkModeContextProvider>
), document.getElementById('root'));
  • Related