简单实用的React主题色切换

815 阅读2分钟

现在的应用一般都支持主题切换的功能,包括暗黑模式和亮色模式,那么使用 React 框架怎么能快速的实现这一功能呢,本文就将通过 React Context 来实现它。

首先通过 vite 新建一个 React 项目

1.npm create vite@latest
2.输入项目名后使用 vscode 或者 webstorm 打开项目
3.因为 vite 没有下载依赖,所以需要打开项目后运行 npm install 安装所有的依赖
4.依赖安装完成后,可以运行 npm run dev,这里 vite 默认不会自动打开网页,可以通过在 package.json 里配置: 

    "scripts": {
      "dev": "vite --open",
      "build": "tsc && vite build",
      "preview": "vite preview"
    },

接下来就可以开始写代码了,在 src 目录下创建 ContextProvider.tsx 文件,首先在文件中创建两个类型用于约束 Context

// 主题模式
type TMode = "Light" | "Dark";
// StateContext 的类型
type TStateContext = {
  // 当前的主题
  currentMode: TMode;
  // 设置主题
  setMode: (mode: TMode) => void;
};

通过 React createContext API 创建 Context 对象,并将这个对象放到 useContext 这个 hook 中并导出,方便后续使用

const StateContext = createContext<TStateContext>({
  currentMode: "Light",
  setMode: () => {},
});

export const useStateContext = () => useContext(StateContext);

创建 ContextProvider 组件用来包裹子组件,使所有的子组件都能接收到 state context 的变化,并将 currentMode 和 修改主题的函数 setMode 传递下去

export const ContextProvider = ({ children }: any) => {
  const [currentMode, setCurrentMode] = useState<TMode>("Light");

  const setMode = (mode: TMode) => {
    setCurrentMode(mode);
  };

  return (
    <StateContext.Provider value={{ currentMode, setMode }}>
      {children}
    </StateContext.Provider>
  );
};

接下来要找到根目录下的 main.tsx 将 App 组件用 ContextProvider 组件包裹

ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
  <React.StrictMode>
      <ContextProvider>
          <App />
      </ContextProvider>
  </React.StrictMode>
)

接着就可以在 App.tsx 组件中使用刚刚创建的 Context 了,然后可以通过解构出来的 currentMode 和 setMode 来完成主题色的切换

import {Button} from "antd";
import {useStateContext} from "./ContextProvider";

function App() {

    // 引入 useStateContext,解构出 currentMode, setMode 方法
    const {currentMode, setMode} = useStateContext()

    return (
        <div style={currentMode == 'Light' ? {
            backgroundColor: 'white',
            display: 'flex',
            alignItems: 'center',
            flexDirection: 'column',
            height: '100vh'
        } : {
            backgroundColor: 'black',
            display: 'flex',
            alignItems: 'center',
            flexDirection: 'column',
            height: '100vh'
        }}>
            <h1 style={currentMode == 'Light' ? {color: 'black'} : {color: 'white'}}>Hello App</h1>
            <div style={{width: 500, height: 300, border: '1px solid #eee', borderRadius: '5px', padding: '10px'}}>
                <div style={{display: 'flex', alignItems: 'center'}}>
                    <span style={currentMode == 'Light' ? {color: 'black'} : {color: 'white'}}>当前主题色</span>
                    <div style={currentMode == 'Light' ? {
                        backgroundColor: 'white',
                        width: 100,
                        height: 40,
                        borderRadius: '5px',
                        border: '1px solid #eee',
                        marginLeft: 10
                    } : {
                        backgroundColor: 'black',
                        width: 100,
                        height: 40,
                        borderRadius: '5px',
                        border: '1px solid #eee',
                        marginLeft: 10
                    }}/>
                </div>

                <div style={{marginTop: 10}}>
                    <Button onClick={() => setMode('Dark')}>更改成暗黑色</Button>
                    <Button onClick={() => setMode('Light')} style={{marginLeft: 10}}>更改成亮白色</Button>
                </div>
            </div>
        </div>
    )
}

export default App

最终的效果如下:

CPT2211192011-522x322.gif

总结: 通过使用 React Context 还是很容易实现主题切换这种功能的,React Context 比较适合放的数据就是各层子组件都有可能会使用到的数据,比如这种颜色主题,相当于透传给各个子组件了。