simon sjöö
simon sjöö

Reputation: 395

React - Toggle theme from another component

I am working on a project on react but I have ran into an issue.

The issue I am having is that I need to be able to toggle my "dark" and "light" theme from a icon that is in a different component. This icon exists in my BottomNavigation but the function for switching the theme exists in my app.js.

Did some research on my own and found that I need to "lift the state up". Issue is that I need to lift it twice as my files look like this:

./Components
  ./Home.js
    - (components gets added here)
  ./Navigation
    ./BottomNavigation.js

app.js
(/home is added here)

My app.js looks like:

function App() {
  const [theme, setTheme] = useState("light");

  const themeToggler = () => {
    theme === "light" ? setTheme("dark") : setTheme("light");
  };

  return (
    <ThemeProvider theme={theme === "light" ? lightTheme : darkTheme}>
      <GlobalStyles />
      <Router>
        <Route exact path="/">
          <Home />
        </Route>
        <Route exact path="/account">
          <Account />
        </Route>
      </Router>
    </ThemeProvider>
  );
}

My Home.js looks like:

const Home = (props) => {
  const [showingState, setIsShowing] = useState(false);

  return (
    <div>
      <TopNavigation isShowing={(showingState) => setIsShowing(showingState)} />
      <BottomNavigation />
      <ImageSlider />
      <Grid />
      {showingState && (
        <CurrencyPopup
          isShowing={(showingState) => setIsShowing(showingState)}
        />
      )}
      <BestSeller />
      <CollectionPromo />
      <Instagram />
      <Footer />
    </div>
  );
};

My BottomNavigation.js looks like (only took the part with the icon):

<div className={classes.options_container}>
  <IconApp className={classes.icon_container}>
    <span className={classes.cart_sum}>$0.00</span>
    <Cart className={classes.icon} />
  </IconApp>
  <IconApp className={classes.icon_container}>
    <Heart className={classes.icon} />
  </IconApp>
  <IconApp className={classes.icon_container}>
    <Visibility
      onClick={() => props.setTheme("")} //This icon shall switch the theme
      className={classes.icon}
    />
  </IconApp>
  <IconApp className={classes.icon_container}>
    <a href="/account">
      <User className={classes.icon} />
    </a>
  </IconApp>
</div>

If you have any ideas or need something more from the code, let me know!

Upvotes: 0

Views: 604

Answers (2)

Matthew Kwong
Matthew Kwong

Reputation: 2947

For best practice, you have a few options:

  1. Use React Context.
  2. Use a state management library like Redux and MobX.

You definitely don't want to life state up in your case, because the two components are too far away from each other in the hierarchy.

Upvotes: 1

promet99
promet99

Reputation: 522

Lifting state up would be solution that does not require any additional knowledge. However, its excessive use (over three or more component) is a bad practice, since it makes code dirty

Using RecoilJS would be easiest, since its api is nearly identical to that of useState, and there is less work for you to do

Sticking to vanilla ReactJS, try React Context

Upvotes: 0

Related Questions