使用MUI与styled-components做响应式开发时出现过多重渲染如何解决
问题根因
你的代码产生无限重渲染的核心原因是:在组件渲染的主流程中直接调用了setfontSize状态更新方法。React中调用状态更新方法会触发组件重新渲染,而重渲染后又会再次执行if (isMedium)判断并调用setfontSize,由此形成无限循环,导致重渲染次数过多。
另外你当前场景下fontSize完全是由isMedium的返回值派生的,根本不需要单独声明为状态,完全可以通过计算直接得到,这也是你走弯路的核心原因。
修复方案
直接删除无用的useState声明和条件更新逻辑,直接计算fontSize的值即可,修正后的完整代码如下:
import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import AppBar from '@material-ui/core/AppBar'; import Toolbar from '@material-ui/core/Toolbar'; import Button from '@material-ui/core/Button'; import { Link } from 'react-router-dom'; import Logojsam from '../../assets/icons/logo-jsam.png'; import useMediaQuery from '@material-ui/core/useMediaQuery'; import { useTheme } from '@material-ui/core/styles'; import styled from 'styled-components'; const useStyles = makeStyles((theme) => ({ rightToolbar: { marginLeft: 'auto', marginRight: -10, }, logo: { width: 185, height: 185, padding: '20px 0px', }, })); const MyButton = styled(Button)({ padding: '0 14px', fontSize: (props) => props.fontSize || '20px', }); const Navbar = () => { const classes = useStyles(); const theme = useTheme(); const isMobile = useMediaQuery(theme.breakpoints.down('sm')); const isMedium = useMediaQuery(theme.breakpoints.down('md')); // 直接计算fontSize,无需状态 const fontSize = isMedium ? '45px' : '20px'; return ( <div> <AppBar position="static" elevation={0} style={{ background: 'white', }} > <Toolbar> <img className={classes.logo} src={Logojsam} alt="Bosch Logo" /> {!isMobile && ( <section className={classes.rightToolbar}> <MyButton fontSize={fontSize} component={Link} to="/"> About Us </MyButton> <MyButton fontSize={fontSize} component={Link} to="/community"> Community </MyButton> <MyButton fontSize={fontSize} component={Link} to="/community"> Activities </MyButton> <MyButton fontSize={fontSize} component={Link} to="/gallery"> Gallery </MyButton> <MyButton fontSize={fontSize} component={Link} to="/contact-us"> Contact Us </MyButton> <MyButton fontSize={fontSize} component={Link} to="/contact-us"> En </MyButton> </section> )} </Toolbar> </AppBar> </div> ); }; export default Navbar;
可选优化方案
如果你不想在js层做判断,也可以直接在styled-components中使用MUI的断点能力实现纯CSS级别的响应式,连useMediaQuery和fontSize传参都可以省略,代码更简洁:
const MyButton = styled(Button)(({ theme }) => ({ padding: '0 14px', fontSize: '20px', [theme.breakpoints.down('md')]: { fontSize: '45px' } }));
使用这个方案的话,你就不需要在Navbar组件里计算和传递fontSize属性了,所有响应式逻辑都收敛在样式定义中。
内容的提问来源于stack exchange,提问作者SpicyyRiice
相关产品推荐
相关产品推荐

