如何为你的 React App 添加双主题?
双主题如今在网站中非常普遍,最常见的是浅色和深色版本,越来越多的应用程序和网站都包含此功能。对于 React 应用程序,Material UI 框架使用多个主题提供了非常有用的功能,并且它们之间的切换非常容易。
我们将创建一个简单的 React 应用程序,并使用 Switch 组件在 Dark 和 Light 主题之间切换。
创建 React 应用程序并安装模块:
第 1 步:使用以下命令创建一个 React 应用程序:
npx create-react-app gfg
第 2 步:创建项目文件夹后,即 gfg ,使用以下命令移动到该文件夹:
cd gfg
第 3 步:创建 ReactJS 应用程序后,使用以下命令安装material-ui模块:
npm install @material-ui/core
步骤 4:在src文件夹中创建以下两个新文件:
- theme.js:在这个文件中,我们将定义我们的主题对象。
- Component1.js:这是我们的示例子组件。
项目结构:它将如下所示。
useTheme 钩子:
我们可以从主题文件中导入多个主题,然后使用 Switch 组件及其处理函数在父组件中切换主题。但是问题来了,它的子组件和进一步嵌套的组件呢?
在单一主题架构中,应用程序的所有组件都可以直接从 theme.js 文件中导入主题对象并使用它。现在,既然有双重主题,他们怎么知道主题的变化?我们是否必须传递一个 prop 来分别通知每个组件“嘿,活动主题已更改”,这将是一种非常麻烦且低效的方法。
幸运的是,Material-UI 提供了一个钩子useTheme ,通过它我们可以访问 React 组件中的父主题变量。所以我们不需要单独导入主题,可以使用父组件使用的任何主题对象。因此,现在即使我们更改主题,它也会在整个组件树中发生更改。
句法:
import { useTheme } from '@material-ui/core/styles';
function Component1() {
const theme = useTheme();
}
创建深色主题对象:
尽管 Material UI 带有内置的明暗模式,但我们将单独定义暗主题对象,因为我们可以自由地更改两个主题中的每个属性,或者您甚至可以想要一个灰色主题而不是黑暗的主题。
const darkTheme = responsiveFontSizes(createMuiTheme({
spacing: 4,
}));
我们将保持 darkTheme 的字体和排版与原始字体相同。我们将背景更改为黑色,将调色板的主要/次要颜色更改为白色,如下所示。
theme.js
import { createMuiTheme, responsiveFontSizes } from '@material-ui/core/styles';
const lightTheme = responsiveFontSizes(createMuiTheme({
spacing: 4,
typography: {
fontFamily: [
'Roboto',
'Raleway',
'Open Sans',
].join(','),
h1: {
fontSize: '5rem',
fontFamily: 'Raleway',
},
h3: {
fontSize: '2.5rem',
fontFamily: 'Open Sans',
},
},
palette: {
background: {
default: '#009900'//green
},
primary: {
main: '#009900',//green
},
secondary:{
main: '#000000',//black
icons: '#009900', //white
},
text: {
primary: '#000000',//black
secondary: '#FFFFFF',//white
},
},
}));
const darkTheme = responsiveFontSizes(createMuiTheme({
spacing: 4,
typography: {
fontFamily: [
'Roboto',
'Raleway',
'Open Sans',
].join(','),
h1: {
fontSize: '5rem',
fontFamily: 'Raleway',
},
h3: {
fontSize: '2.5rem',
fontFamily: 'Open Sans',
},
},
palette: {
background: {
default: '#000000'//black
},
primary: {
main: '#FFFFFF',//white
},
secondary:{
main: '#FFFFFF', //white
icons: '#FFFFFF', //white
},
text: {
primary: '#FFFFFF',//white
secondary: '#FFFFFF',//white
},
},
}));
export default lightTheme ;
export {darkTheme} ;
Component1.js
import React, { Component } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { useTheme } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
}));
export default function Component1() {
const theme = useTheme();
const classes = useStyles(theme);
return (
This is a Child Component text.
);
}
App.js
import React, { Component } from 'react';
import './App.css';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/styles';
import { createMuiTheme } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import { AppBar, Toolbar } from '@material-ui/core';
import Switch from '@material-ui/core/Switch';
import lightTheme, { darkTheme } from './theme';
import Grid from '@material-ui/core/Grid';
import Component1 from './Component1';
function App() {
// The 'checked' state is for the status of Switch component
const [checked, setChecked] = React.useState(false);
// The 'newtheme' state tells if the new theme (i.e, dark theme)
// is to be applied or not.
const [newtheme, setTheme] = React.useState(false);
function changeTheme() {
setTheme(!newtheme);
setChecked(!checked);
}
// Conditional - if newtheme is set to true
// then set appliedTheme to dark
const appliedTheme =
createMuiTheme(newtheme ? darkTheme : lightTheme);
return (
{/* Switch position whenever
changed triggers the changeTheme() */}
{ changeTheme() }}
style={{ color: appliedTheme.palette.secondary.icons }} />
Geeks for Geeks
);
}
export default App;
组件1.js
import React, { Component } from 'react';
import { makeStyles } from '@material-ui/core/styles';
import { useTheme } from '@material-ui/core/styles';
import Typography from '@material-ui/core/Typography';
const useStyles = makeStyles((theme) => ({
root: {
flexGrow: 1,
},
}));
export default function Component1() {
const theme = useTheme();
const classes = useStyles(theme);
return (
This is a Child Component text.
);
}
应用程序.js
import React, { Component } from 'react';
import './App.css';
import CssBaseline from '@material-ui/core/CssBaseline';
import { ThemeProvider } from '@material-ui/styles';
import { createMuiTheme } from '@material-ui/core/styles';
import Container from '@material-ui/core/Container';
import Typography from '@material-ui/core/Typography';
import Button from '@material-ui/core/Button';
import { AppBar, Toolbar } from '@material-ui/core';
import Switch from '@material-ui/core/Switch';
import lightTheme, { darkTheme } from './theme';
import Grid from '@material-ui/core/Grid';
import Component1 from './Component1';
function App() {
// The 'checked' state is for the status of Switch component
const [checked, setChecked] = React.useState(false);
// The 'newtheme' state tells if the new theme (i.e, dark theme)
// is to be applied or not.
const [newtheme, setTheme] = React.useState(false);
function changeTheme() {
setTheme(!newtheme);
setChecked(!checked);
}
// Conditional - if newtheme is set to true
// then set appliedTheme to dark
const appliedTheme =
createMuiTheme(newtheme ? darkTheme : lightTheme);
return (
{/* Switch position whenever
changed triggers the changeTheme() */}
{ changeTheme() }}
style={{ color: appliedTheme.palette.secondary.icons }} />
Geeks for Geeks
);
}
export default App;
运行应用程序的步骤:从项目的根目录使用以下命令运行应用程序:
npm start
输出:现在打开浏览器并转到http://localhost:3000/ ,您将看到以下输出: