如何在React组件中正确传递makeStyles生成的样式作为Prop

如何在React组件中正确传递makeStyles生成的样式作为Prop

在使用Material-ui的makeStyles或useStyles钩子定义组件样式时,一个常见的误解是将其返回的类名对象直接作为内联样式(style prop)传递。本文旨在澄清,makeStyles生成的是css类名字符串,而非css属性对象。因此,当将这些样式作为props传递给子组件时,应始终使用className prop来应用它们,以确保样式能够正确渲染和继承Material-UI的主题能力。

理解makeStyles与CSS类名

Material-UI的makeStyles(或函数组件中的useStyles)是其JSS(JavaScript in CSS)解决方案的一部分。它的核心作用是将你在JavaScript对象中定义的样式规则转换为唯一的CSS类名,并注入到文档的

中。当你在组件中调用useStyles()时,它会返回一个包含这些生成的CSS类名字符串的对象。

例如,如果你定义了一个样式对象:

const useStyles = makeStyles((theme) => ({     fieldShape: {         marginTop: "16px",         [theme.breakpoints.up("md")]: {             width: "625px",         },     }, }));

当你在组件中调用 const classes = useStyles(); 后,classes.fieldShape的值将是一个类似于 “MuiBox-root-123” 的字符串,而不是一个包含 { marginTop: “16px”, … } 的JavaScript对象。这个字符串就是你的CSS类名。

错误的传递与应用方式

许多开发者在尝试将makeStyles定义的样式传递给子组件时,可能会误以为classes.fieldShape是一个可以直接赋值给style prop的内联样式对象,如下所示:

// 父组件中 import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import MyComponent from './MyComponent'; // 假设这是你的子组件  const useStyles = makeStyles((theme) => ({     fieldShape: {         marginTop: "16px",         [theme.breakpoints.up("md")]: {             width: "625px",         },     }, }));  function ParentComponent() {     const classes = useStyles();     return (              ); }  // MyComponent.js (子组件中) import React from 'react'; import { TextField } from '@material-ui/core';  function MyComponent(props) {     const { styling } = props;     // 错误用法:将类名字符串赋值给style prop     return (               ); }

这种做法是错误的,因为TextField的style prop期望接收一个JavaScript对象,其中键是CSS属性名,值是对应的属性值(例如 { marginTop: ’16px’ })。而我们传递的styling(即classes.fieldShape)是一个字符串,因此不会产生预期的样式效果。

正确的传递与应用方式

要正确地将makeStyles生成的样式传递给子组件,你需要将该类名字符串赋值给子组件的className prop。这样,浏览器会为该组件元素添加对应的CSS类,从而应用预定义的样式。

以下是修正后的示例代码:

// ParentComponent.js (父组件中) import React from 'react'; import { makeStyles } from '@material-ui/core/styles'; import MyComponent from './MyComponent'; // 导入子组件  // 定义样式 const useStyles = makeStyles((theme) => ({     fieldShape: {         marginTop: "16px",         [theme.breakpoints.up("md")]: {             width: "625px",         },         padding: '8px',         border: '1px solid blue',     },     anotherStyle: {         color: 'red',         fontSize: '1.2rem',     } }));  function ParentComponent() {     const classes = useStyles(); // 获取类名对象      return (         <div>             <h2>父组件</h2>             {/* 将生成的类名字符串作为prop传递 */}             <MyComponent customClass={classes.fieldShape} />             <MyComponent customClass={classes.anotherStyle} />             {/* 也可以直接传递多个类名,但通常建议合并或使用clsx库 */}             <MyComponent customClass={`${classes.fieldShape} ${classes.anotherStyle}`} />         </div>     ); }  export default ParentComponent;  // MyComponent.js (子组件中) import React from 'react'; import { TextField } from '@material-ui/core';  function MyComponent(props) {     // 从props中解构出传递的类名     const { customClass } = props;      return (         // 正确用法:将类名字符串赋值给className prop         // TextField组件本身支持className prop来应用外部CSS类         <TextField              className={customClass}              label="输入框"              variant="outlined"              fullWidth              margin="normal"          />     ); }  export default MyComponent;

在这个修正后的例子中,ParentComponent通过customClass prop将classes.fieldShape这个类名字符串传递给MyComponent。在MyComponent内部,TextField组件通过className={customClass}正确地应用了这个CSS类,从而使样式生效。

注意事项

  1. style vs. className: 这是一个核心区别。style prop用于设置元素的内联样式,它期望一个JavaScript对象,其键值对直接映射到CSS属性和值。而className prop则用于指定一个或多个CSS类名,这些类名会从样式表中查找并应用对应的CSS规则。
  2. makeStyles的优势: 使用makeStyles不仅能生成唯一的类名避免样式冲突,还能自动处理前缀、响应式断点(如示例中的theme.breakpoints.up(“md”))以及与Material-UI主题的集成。直接使用内联样式则无法享受这些高级特性。
  3. 合并类名: 如果需要为一个组件应用多个makeStyles生成的类名,或者需要合并外部类名和内部类名,可以使用模板字符串或更推荐的clsx库来合并它们。例如:className={clsx(classes.baseStyle, props.externalClass)}。
  4. 组件库的兼容性: 大多数React组件库(包括Material-UI的组件)都支持通过className prop来扩展或覆盖其默认样式。因此,这种传递类名的方式是通用且推荐的。

总结

当使用Material-UI的makeStyles或useStyles来管理组件样式时,请牢记它们返回的是CSS类名字符串,而非内联样式对象。在将这些样式作为props传递给子组件时,务必使用className prop来接收和应用它们。遵循这一原则,将确保你的Material-UI样式能够正确地在组件之间传递和生效,同时充分利用JSS和Material-UI主题的强大功能。

© 版权声明
THE END
喜欢就支持一下吧
点赞12 分享