Harry
Harry

Reputation: 31

Global variable / state in React (with React router)

I am new to React and trying to build a website with dark mode.

by changing the data-theme in CSS file when the toggle button is clicked, and the following is my file structure in App.jsx.

├── Header
│   └── DarkModeToggle
├── Content
│
└── (CSS file)

DarkModeToggle.jsx

class NightModeToggle extends React.Component {
    constructor(props) {
        super(props);
        this.state = {
            theme: 'light',
        }
        this.toggleTheme = this.toggleTheme.bind(this);
    }

    toggleTheme() {
        const theme = this.state.theme === 'dark' ? 'light' : 'dark';
        this.setState({ theme });
        document.documentElement.setAttribute("data-theme", theme);
    }

    render() {...}
}

I also use react route so that I can display different information in different URL

Content.jsx

class Content extends React.Component {
    render() {
        return (
            <div id="content">
                <BrowserRouter>
                    <Switch>
                        <Route exact path='/test' component={Test}></Route>
                        <Route exact path='/home' component={Home}></Route>
                        <Route exact path='/project' component={Project}></Route>
                    </Switch>
                </BrowserRouter>
            </div>
        );
    }
}

However, the website cannot keep the theme when I go to other URL.

For example, I change to dark mode in /home and then I go to /project, the website will back to the light mode.

How can I maintain the theme variable (or init a global variable) when I using React-Route? Thank you for your help!

Upvotes: 0

Views: 2427

Answers (3)

I unfortunately don't have an answer for you because I'm dealing with the same problem even after taking advantage of the Context API. I created a routing layer that handles my path constants through a routing object, which then uses a layout component to produce an "outlet" element. I wrapped my entire app with my theme context provider and the same issue persists. The only thing I've been able to find to solve it is that the theme state could be stored in localStorage and accessed upon rendering the theme context provider. I haven't tried it yet, because it seems like there's something wrong with the way I'm doing something, but I'll let you know if I find the fix on the way there.

EDIT: I've found an answer and the obviousness of it still pains me; I hope this is an answer for anyone will this same issue. All I needed to do was replace the anchor tags with Link tags. I presume you could probably prevent the default behavior of the anchors as well, but it seemed like better practice to just replace them with Link elements.

Upvotes: 0

Dishant Desai
Dishant Desai

Reputation: 164

You can use styled components for theming the web app.

Please refer this link for more info:

https://styled-components.com/docs/advanced#theming

Upvotes: 0

Ferin Patel
Ferin Patel

Reputation: 3978

You can use Context API from react to create global context.
Then you can wrap your app file within context you have created.
Now you can access themeMode from any file inside react render tree.


Below is example, how you can use themeMode with context API

Context

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

export const AppContext = createContext();

const AppProvider = ({ children }) => {
  const [themeMode, setThemeMode] = useState("lightTheme");

  const value = { themeMode };

  return <AppContext.Provider value={value}>{children}</AppContext.Provider>;
};

export default AppProvider;

Index


import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import AppProvider from "./AppProvider";

ReactDOM.render(
  <AppProvider>
    <App />
  </AppProvider>,
  document.getElementById("root")

App

import React, { useContext } from "react";
import { AppContext } from "./AppProvider";

const App = () => {
  const { themeMode } = useContext(AppContext);
  console.log("THEME MODE: ", themeMode);
  return <div></div>;
};

export default App;


Upvotes: 2

Related Questions