MUI5如何将makeStyles样式迁移至styled API并正确传递自定义props
MUI 5 styled自定义Typography组件props不生效解决方案
问题原因
初始代码无法获取自定义props,核心是两个机制没处理对:
- MUI 5的
styledAPI默认会过滤非DOM标准、非组件合法声明的props,既不会传入样式回调,也不会向下透传,避免DOM节点出现无效属性警告 - 未配置
shouldForwardProp区分样式专用props和需要透传的业务props,同时自定义的variant取值和MUI Typography内置的variant属性冲突,会被组件内部校验拦截
正确实现步骤
- 保留原有MUI4版本中的
variantMapping、acceptedColors常量定义,逻辑无需改动 - 初始化styled组件时传入
shouldForwardProp配置,明确标记哪些是仅用于样式计算、不需要透传到DOM的自定义属性 - 把原makeStyles中的样式计算逻辑完整迁移到styled的回调函数中,给入参加默认值兜底
- 外层组件透传props时,将自定义样式属性和MUI内置属性做区分,避免触发MUI内部的属性校验报错
完整实现代码
import React from 'react'; import PropTypes from 'prop-types'; import { styled, Typography as MuiTypography } from '@mui/material'; import Colors from 'Colors/index'; // 原有常量逻辑完全保留 const acceptedColors = [...Object.values(Colors.gray), Colors.white]; export const variantMapping = { '2xl': { element: 'h1', styles: { primary: { fontSize: 81, lineHeight: '120%', letterSpacing: '-2px' }, secondary: { fontSize: 81, lineHeight: '120%', letterSpacing: 0 }, }, }, xl: { element: 'h2', styles: { primary: { fontSize: 54, lineHeight: '120%', letterSpacing: '-1px' }, secondary: { fontSize: 54, lineHeight: '120%', letterSpacing: 0 }, }, }, lg: { element: 'h3', styles: { primary: { fontSize: 36, lineHeight: '120%', letterSpacing: '-0.75px' }, secondary: { fontSize: 36, lineHeight: '120%', letterSpacing: 0 }, }, }, md: { element: 'h4', styles: { primary: { fontSize: 24, lineHeight: '130%', letterSpacing: '-0.5px' }, secondary: { fontSize: 24, lineHeight: '140%', letterSpacing: 0 }, }, }, sm: { element: 'p', styles: { primary: { fontSize: 16, lineHeight: '140%', letterSpacing: 0 }, secondary: { fontSize: 16, lineHeight: '140%', letterSpacing: 0 }, }, }, xs: { element: 'h5', styles: { primary: { fontSize: 14, lineHeight: '140%', letterSpacing: 0 }, secondary: { fontSize: 14, lineHeight: '140%', letterSpacing: 0 }, }, }, '2xs': { element: 'h6', styles: { primary: { fontSize: 12, lineHeight: '140%', letterSpacing: 0 }, secondary: { fontSize: 12, lineHeight: '140%', letterSpacing: 0 }, }, }, }; // 配置styled组件,拦截自定义样式props const StyledMuiTypography = styled(MuiTypography, { shouldForwardProp: (prop) => !['isBold', 'customVariant', 'font', 'customColor'].includes(prop), })(({ isBold = false, font = 'primary', customVariant = 'sm', customColor = Colors.gray[500] }) => { // 基础字体样式 const baseStyles = { fontWeight: isBold || font === 'secondary' ? 700 : 'normal', fontFamily: font === 'secondary' ? '"Lora", serif' : '"Karla", sans-serif', }; // 变体兜底:非法variant默认用sm const validVariant = Object.keys(variantMapping).includes(customVariant) ? customVariant : 'sm'; const variantStyles = variantMapping[validVariant].styles[font] || variantMapping[validVariant].styles.primary; // 颜色兜底:非法颜色默认用gray[500] const validColor = acceptedColors.includes(customColor) ? customColor : Colors.gray[500]; return { ...baseStyles, ...variantStyles, color: validColor, }; }); // 外层包装组件,对齐原有API const Typography = React.forwardRef(function Typography( { children, variant, className, component, isBold, font, canWrap, color, ...props }, ref, ) { const validVariant = Object.keys(variantMapping).includes(variant) ? variant : 'sm'; return ( <StyledMuiTypography {...props} ref={ref} // 传入自定义样式props customVariant={variant} isBold={isBold} font={font} customColor={color} // 底层MUI组件配置 component={component || variantMapping[validVariant].element} className={className} noWrap={!canWrap} // 给MUI内置variant传合法值,避免校验报错 variant="body1" > {children} </StyledMuiTypography> ); }); // 原有props校验和默认值完全保留 Typography.propTypes = { children: PropTypes.node.isRequired, variant: PropTypes.oneOf(Object.keys(variantMapping)), component: PropTypes.string, className: PropTypes.string, isBold: PropTypes.bool, font: PropTypes.oneOf(['primary', 'secondary']), canWrap: PropTypes.bool, color: PropTypes.oneOf(acceptedColors), }; Typography.defaultProps = { isBold: false, component: null, className: '', font: 'primary', variant: 'sm', canWrap: true, color: Colors.gray[500], }; export default Typography;
关键注意点
- 不要把自定义的
2xl/xs这类非MUI标准的variant值直接传给底层MuiTypography,会触发控制台属性校验警告,上面代码中将自定义尺寸属性重命名为customVariant传入styled做样式计算,给MUI内置variant传固定合法值body1即可 shouldForwardProp返回true的属性会透传到DOM节点,返回false的属性仅会传入样式回调用于计算,不要把isBold这类自定义属性透传到DOM- 样式回调中的入参可以直接设置默认值,兼容未传参的场景
内容的提问来源于stack exchange,提问作者zeckdude
相关产品推荐
相关产品推荐

