You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Material UI 如何在事件触发时动态更新组件样式

MUI 事件触发动态更新样式解决方案

你之前的写法用的是静态样式定义,makeStyles和withStyles本身原生支持基于组件props动态生成样式,不需要在事件回调里手动修改生成好的CSS规则,只要把触发变更的状态纳入React的状态管理流,就能实现自动的样式更新。

核心原则

不要在React的生命周期外绑定事件后直接操作DOM样式或者JSS生成的样式表,这类手动修改会被React的重渲染覆盖,还会造成状态和UI不同步的问题。所有样式变更都通过状态驱动。


方案1:Hook 写法(makeStyles)实现

makeStyles支持传入函数形式的样式规则,函数入参就是你调用useStyles时传入的参数,基于这个参数就能返回不同场景下的样式:

import * as React from 'react';
import { makeStyles } from '@mui/styles';
import Button from '@mui/material/Button';

// 样式根据入参isDarkMode动态生成
const useStyles = makeStyles({
  root: ({ isDarkMode }) => ({
    background: isDarkMode 
      ? 'linear-gradient(45deg, #1a237e 30%, #283593 90%)' 
      : 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: isDarkMode 
      ? '0 3px 5px 2px rgba(26, 35, 126, .3)'
      : '0 3px 5px 2px rgba(255, 105, 135, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
  }),
});

export default function HookButton() {
  // 初始化时读取本地存储的主题配置
  const [isDarkMode, setIsDarkMode] = React.useState(
    () => window.localStorage.getItem('theme') === 'dark'
  );

  React.useEffect(() => {
    const handleStorageChange = () => {
      // storage事件触发时只更新React状态,不直接操作样式
      setIsDarkMode(window.localStorage.getItem('theme') === 'dark');
    };
    window.addEventListener('storage', handleStorageChange);
    // 组件卸载时移除监听,避免内存泄漏
    return () => window.removeEventListener('storage', handleStorageChange);
  }, []);

  // 把状态传给useStyles,状态变更时样式会自动重算
  const classes = useStyles({ isDarkMode });
  return <Button className={classes.root}>Hook</Button>;
}

方案2:高阶组件写法(withStyles)实现

withStyles同样支持函数形式的样式规则,只需要把深色模式状态作为props传给包裹后的组件即可:

import * as React from 'react';
import PropTypes from 'prop-types';
import { withStyles } from '@mui/styles';
import Button from '@mui/material/Button';

const styles = {
  root: ({ isDarkMode }) => ({
    background: isDarkMode 
      ? 'linear-gradient(45deg, #1a237e 30%, #283593 90%)'
      : 'linear-gradient(45deg, #FE6B8B 30%, #FF8E53 90%)',
    border: 0,
    borderRadius: 3,
    boxShadow: isDarkMode 
      ? '0 3px 5px 2px rgba(26, 35, 126, .3)'
      : '0 3px 5px 2px rgba(255, 105, 135, .3)',
    color: 'white',
    height: 48,
    padding: '0 30px',
  }),
};

function HigherOrderButton({ classes }) {
  return <Button className={classes.root}>Higher-order component</Button>;
}

HigherOrderButton.propTypes = {
  classes: PropTypes.object.isRequired,
  isDarkMode: PropTypes.bool.isRequired,
};

const ThemedButton = withStyles(styles)(HigherOrderButton);

// 外层组件负责管理状态和事件监听
export default function HOCWrapper() {
  const [isDarkMode, setIsDarkMode] = React.useState(
    () => window.localStorage.getItem('theme') === 'dark'
  );

  React.useEffect(() => {
    const handleStorageChange = () => {
      setIsDarkMode(window.localStorage.getItem('theme') === 'dark');
    };
    window.addEventListener('storage', handleStorageChange);
    return () => window.removeEventListener('storage', handleStorageChange);
  }, []);

  return <ThemedButton isDarkMode={isDarkMode} />;
}

注意事项

  • storage事件只会在其他页面对localStorage做修改时触发到当前页面,如果是同页面的主题开关修改localStorage,直接在开关的回调里更新isDarkMode状态即可,不需要等storage事件。
  • 如果主题是全局配置,不需要每个组件都单独绑定storage事件,可以把isDarkMode状态放在根组件或者React Context中,所有业务组件直接读取上下文里的状态传样式参数即可。
  • 如果你用的是MUI v5及以上版本,更推荐用官方的ThemeProvider+createTheme做全局深色模式切换,不需要每个组件单独写动态样式,直接在主题里配置调色板,所有MUI组件会自动适配。

内容的提问来源于stack exchange,提问作者AG_HIHI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.29 09:57:16