简体   繁体   中英

React.js: How to implement dark/light mode in body toggling with useContext?

I am trying to create a background theme which will switch on onClick . On onClick it must change the background color of body in react app . I've managed to implement useContext , and now it toggles and changes the list items color in Header component . How to set it to body as well? Any help will be appreciated.

Here is my useContext color component

import React from 'react'

export const themes = {
  light: {
    foreground: '#ffffff',
  },
  blue: {
    foreground: 'blue',
  },
}

export default React.createContext({
  theme: themes.light,
  switchTheme: () => {},
})

onClick Button component

import React, { useContext } from 'react'
import ThemeContext from './context'

import './ThemedButton.scss'

const ThemedButton = () => {
  const { switchTheme } = useContext(ThemeContext)

  return (
    <>
      <button className="btn" onClick={switchTheme}>
        Switch
      </button>
    </>
  )
}

export default ThemedButton 

App.js

import React, { useState } from 'react'

import SearchBar from './components/SearchBar';
import useCountries from './Hooks/useCountries';
import MainTable from './components/MainTable';
import ThemeButton from './useContext/ThemedButton';
import ThemeContext from './useContext/context';

import { searchProps } from './types';
import { themes } from './useContext/context';
import Routes from './Routes';


import './App.scss'

export default function App() {
  const [search, setSearch] = useState('')
  const [data] = useCountries(search)
  const [context, setContext] = useState({
    theme: themes.light,
    switchTheme: () => {
      setContext((current) => ({
        ...current,
        theme: current.theme === themes.light ? themes.blue : themes.light,
      }))
    },
  })

  const handleChange: React.ReactEventHandler<HTMLInputElement> = (e): void => {
    setSearch(e.currentTarget.value)
  }

  return (
    <div className="App">
      <SearchBar handleChange={handleChange} search={search as searchProps} />

      <ThemeContext.Provider value={context}>
        <ThemeButton />
        <MainTable countries={data} />
      </ThemeContext.Provider>

      <Routes />
    </div>
  )
}

Header component

import React, { useContext } from 'react'

import ThemeContext from '../../useContext/context'


import './Header.scss'

export default function Header() {
  const { theme } = useContext(ThemeContext)

  return (
    <div className="header">
      <ul className="HeadtableRow" style={{ color: theme.foreground }}> // here it's set to change list items color
        <li>Flag</li>
        <li>Name</li>
        <li>Language</li>
        <li>Population</li>
        <li>Region</li>

      </ul>
    </div>
  )
}

If you want to change your body tag in your application you need to modify DOM and you can add this code to your Header.js (or any other file under your context) file:

useEffect(() => {
    const body = document.getElementsByTagName("body");
    body[0].style.backgroundColor = theme.foreground
  },[])

*** Don't forget to import useEffect

*** Inline style like below is a better approach than modifying DOM directly

<div className="App" style={{backgroundColor: context.theme.foreground}}> 
     //For under context files just use theme.foreground
      <SearchBar handleChange={handleChange} search={search as searchProps} />
      <ThemeContext.Provider value={context}>
        <ThemeButton />
        <MainTable countries={data} />
      </ThemeContext.Provider>

      <Routes />
    </div>

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