简体   繁体   中英

When I update my context.provider's value, the child components don't change color

I have some trouble implementing multiple color themes into my website. I have made a button connected to a state toggle, and every time the state switches, a useEffect handler sets the value of my context.provider to dark/light theme. When I log the useEffect handler it changes the theme, however the child components are not affected by it.

This is my App.tsx:

import {
  useContext,
  useState,
  Provider,
  createContext,
  useEffect,
} from "react";
import logo from "./logo.svg";
import "./App.scss";
import Nav from "./components/ui/nav/Nav";
import Welcome from "./components/ui/welcome/Welcome";
import Section from "./components/ux/section/Section";
import Prices from "./components/ui/prices/Prices";
import { themes, ThemeContext } from "./components/theme/theme";
import Background from "./components/ui/background/Background";

function App() {
  const theme = useContext(ThemeContext);
  const [darkmode, setdarkmode] = useState(true);
  const themeMode = themes.light;
  useEffect(() => {
    const themeMode = darkmode ? themes.light : themes.dark;
    console.log(themeMode);
  }, [darkmode]);

  document.body.style.background = theme.primary;
  document.body.style.color = theme.text;
  return (
    <ThemeContext.Provider value={themeMode}>
      <button
        onClick={() => {
          setdarkmode(!darkmode);
        }}
      >
        hello
      </button>
      <Background />

      <Section content={<Welcome />} />
      <Section content={<Prices />} />
    </ThemeContext.Provider>
  );
}

export default App;

And this is one of my components that should use the updated theme:

import React, { useContext, useState } from "react";
import "./button.scss";
import { themes, ThemeContext } from "../../theme/theme";
export default function Button(props: {
  invert: boolean;
  link: string | URL;
  content: string;
}) {
  var style = {};

  const theme = useContext(ThemeContext);
  const buttonStyle = {
    color: theme.primary,
    background: theme.cta,
    border: "solid 2px " + theme.cta,
  };
  const invertStyle = {
    color: theme.cta,
    background: theme.primary,
    border: "solid 2px " + theme.cta,
  };

  props.invert ? (style = invertStyle) : (style = buttonStyle);
  const [colorStyle, setColorStyle] = useState(false);
  colorStyle
    ? props.invert
      ? (style = buttonStyle)
      : (style = invertStyle)
    : props.invert
    ? (style = invertStyle)
    : (style = buttonStyle);
  return (
    <button
      onClick={() => {
        window.location.assign(props.link);
      }}
      onMouseEnter={() => {
        setColorStyle(!colorStyle);
      }}
      onMouseLeave={() => {
        setColorStyle(!colorStyle);
      }}
      className="ux-btn"
      style={style}
    >
      {props.content}
    </button>
  );
}

You have const themeMode = themes.light; in your component. This does exactly what it says: sets the themeMode variable to be the constant themes.light .

When you attempt (I presume) to "change it" in the event handler, you're doing const themeMode = darkmode? themes.light: themes.dark; const themeMode = darkmode? themes.light: themes.dark; , but with nothing else in that function (other than a console.log ) - as this variable is only scoped to that one function, it does not change the same-named variable outside.

Even if you made it change the outer variable (by declaring the outer variable with let instead of const and not shadowing the variable inside the function but updating its value), that won't work at all well with React.

The solution is to use state instead:

  • replace const themeMode = themes.light with const [themeMode, setThemeMode] = useState(themes.light);
  • inside the event handler, replace const themeMode = darkmode? themes.light: themes.dark; const themeMode = darkmode? themes.light: themes.dark; with setThemeMode(darkmode? themes.light: themes.dark);

Making the above 2 changes will work - but you can still simplify your component quite a lot. You don't need both darkMode and themeMode in state, as one is simply calculated from the other. If you just use one state variable you also won't need a useEffect to automatically update one based on the other. But I'll leave you to sort out those problems - I hope this helps you get started, at least!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM