Home > OS >  How to access values from context in a separate functional component
How to access values from context in a separate functional component

Time:04-15

I'm trying to build a simple light mode/dark mode into my app I saw this example on Material UI for light/dark mode but I'm not sure how I can get access to the value for when the user clicks toggleColorMode in my Header component if it's being set in toggleColorMode function?

I guess my question is how can I get access to the value of light/dark mode of the context in my Header component if it's in a different function?

Here is my code.

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

import MoreVertIcon from "@mui/icons-material/MoreVert";
import DarkModeIcon from "@mui/icons-material/DarkMode";
import LightModeIcon from "@mui/icons-material/LightMode";
import Paper from "@mui/material/Paper";
import { useTheme, ThemeProvider, createTheme } from "@mui/material/styles";
import IconButton from "@mui/material/IconButton";

import Navigation from "../Navigation/Navigation";

const ColorModeContext = React.createContext({ toggleColorMode: () => {} });

export const Header = (props) => {
  const { mode } = props;
  const theme = useTheme();
  const colorMode = React.useContext(ColorModeContext);

  console.log("mode is...", mode);

  return (
    <div className="header-container">
      <Paper
        elevation={3}
        style={{ backgroundColor: "#1F1F1F", padding: "15px" }}
      >
        <div
          className="header-contents"
          style={{
            display: "flex",
            justifyContent: "space-between",
            alignItems: "center",
          }}
        >
          <div
            className="logo"
            style={{ display: "flex", alignItems: "center" }}
          >
            <img
              src="/images/header-logo.png"
              alt="URL Logo Shortener"
              width={"50px"}
            />
            <h1 style={{ color: "#ea80fc", paddingLeft: "20px" }}>
              URL Shortener
            </h1>
          </div>
          <div className="settings">
            <IconButton
              sx={{ ml: 1 }}
              onClick={colorMode.toggleColorMode}
              color="inherit"
              aria-label="dark/light mode"
            >
              {theme.palette.mode === "dark" ? (
                <DarkModeIcon
                  style={{
                    cursor: "pointer",
                    marginRight: "10px",
                  }}
                />
              ) : (
                <LightModeIcon
                  style={{
                    cursor: "pointer",
                    marginRight: "10px",
                  }}
                />
              )}
            </IconButton>
            <IconButton aria-label="settings">
              <MoreVertIcon style={{ color: "#fff", cursor: "pointer" }} />
            </IconButton>
          </div>
        </div>
      </Paper>
      {/* Navigation */}
      <Navigation />
    </div>
  );
};

export default function ToggleColorMode() {
  const [mode, setMode] = React.useState("light");
  const colorMode = React.useMemo(
    () => ({
      toggleColorMode: () => {
        setMode((prevMode) => (prevMode === "light" ? "dark" : "light"));
      },
    }),
    []
  );

  const theme = React.useMemo(
    () =>
      createTheme({
        palette: {
          mode,
        },
      }),
    [mode]
  );

  return (
    <ColorModeContext.Provider value={colorMode}>
      <ThemeProvider theme={theme}>
        <Header mode={mode} />
      </ThemeProvider>
    </ColorModeContext.Provider>
  );
}

CodePudding user response:

Read the documentation: createContext, useContext. You need to render a ContextProvider in your parent (or top-level) component, then you can get the data in any component in the tree like const { theme } = useContext(ColorModeContext);.

You don't need to pass the mode as props, put it as one of the values in the context and access it.

Here's how you would render it in your example:

<ColorModeContext.Provider value={{colorMode, theme}}>
  <Header />
</ColorModeContext.Provider>

CodePudding user response:

You can pass an object inside the value in the context provider, in other word you can pass the toggle function inside your value to be consumed in the childern. thus you gain an access to change your mode state. Note that the way changes are determined can cause some issues when passing objects as value, this might trigger unnecessary rerendering see Caveats for more info. or refer to the useContext docs

<ColorModeContext.Provider
      value={{ colorMode: colorMode, toggleColorMode: toggleColorMode }}
    >
      <ThemeProvider theme={theme}>
        <Header />
      </ThemeProvider>
    </ColorModeContext.Provider>
  • Related