React.js:如何通过useContext扩展实现body的明暗主题切换
Hey there! Looks like you're almost there with your theme toggle—great job getting the Header text color working already! To extend this functionality to change the body's background color when clicking the switch button, we just need to make a few small tweaks to your context setup and add a way to sync theme changes to the body element. Here's a step-by-step solution:
Step 1: Update Your Theme Definitions with Background Colors
First, let's expand your themes object to include a background property for each theme—this will give us the consistent value we need to apply to the body:
// useContext颜色组件 import React from 'react' export const themes = { light: { foreground: '#ffffff', background: '#f5f5f5', // Light gray background for light theme }, blue: { foreground: 'blue', background: '#e6f2ff', // Soft blue background for blue theme }, } export default React.createContext({ theme: themes.light, switchTheme: () => {}, })
Step 2: Sync Theme Changes to the Body Element
In your App.js, we'll use React's useEffect hook to listen for changes to the theme state and update the body's background color whenever the theme switches. This works because the body is a top-level DOM element outside your React component tree, so we need to modify it directly with vanilla JS:
// App.js import React, { useState, useEffect } 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, })) }, }) // Sync theme changes to body background useEffect(() => { document.body.style.backgroundColor = context.theme.background; // Cleanup: Reset body background if component unmounts return () => { document.body.style.backgroundColor = ''; }; }, [context.theme]); 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> ) }
Step 3: Verify and Adjust (Optional)
The useEffect will run automatically on component mount, so the body will get the light theme's background right when the app loads. You can tweak the background values in the themes object to match your desired color scheme—for example, use #1a73e8 for a deeper blue background if that fits your design.
Why This Works
- We added
backgroundproperties to your theme definitions to keep styling consistent across components and the body. - The
useEffecthook reacts to changes incontext.theme—every time the button is clicked and the theme switches, it updates the body'sbackgroundColorstyle directly. - The cleanup function in
useEffectresets the body's background when the App component unmounts, which is a good practice to avoid leaving unintended styles in the DOM.
内容的提问来源于stack exchange,提问作者Greg

