问题描述
当我想从样式化组件迁移到 CSS 模块时,出现了以下问题。
假设我有以下样式组件,它接受动态参数 offset
和动态 CSS 字符串 theme
:
const Li = styled.li`
&.selected {
background-color: grey;
}
margin-left: ${({ offset }) => offset}px;
${({ theme }) => theme};
`;
在我的代码中,我会按以下方式使用它:
const Parent = () => (
<List>
{list.map((item) => (
<Item
key={item.id}
id={item.id}
selectedIds={[]}
offset={24}
theme={`
&.selected {
background-color: green;
}
`}
>
{item.name}
</Item>
))}
</List>
);
const Item = ({ id,offset = 0,theme,children }) => {
return (
<Li
theme={theme}
offset={offset}
className={selectedIds.includes(id) && 'selected'}
>
{children}
</Li>
);
};
要求:现在我真的会保留 Item
的组件 API:传递 number
偏移量和样式字符串 theme
。所以基本上 Parent
组件中的所有内容都应该保持这种方式。
如何在内部将 Item
组件转换为使用 CSS 模块而不是样式化的 Li
组件?
解决方法
这可能是一种与过去不同的思维方式,它可以工作
- 您可以使用 css 变量
style={{ [`--offset`]: `${offset}px` }}
.item {
margin-left: var(--offset);
}
- 您可以拥有一个专用于主题的 css 模块(文件)。在你的情况下,它有
withSelected
.withSelected {
&.selected {
background-color: green;
}
}
所以你可以把它作为“主题”传递
theme={themes.withSelected}
这是组件的样子
import styles from "./style.module.scss";
import themes from "./themes.module.scss";
const Parent = () => (
<ul>
{list.map((item) => (
<Item
key={item.id}
id={item.id}
selectedIds={[1]}
offset={24}
theme={themes.withSelected}
>
{item.name}
</Item>
))}
</ul>
);
const Item = ({ id,offset = 0,theme,children,selectedIds }) => {
return (
<li
className={`${styles.item} ${theme} ${
selectedIds.includes(id) && themes.selected
}`}
theme={theme}
style={{ [`--offset`]: `${offset}px` }}
>
{children}
</li>
);
};
演示:https://codesandbox.io/s/styledcomponent-to-css-modules-1kbqx
,对于 1,我同意 @Mosh 只使用 style 道具。 CSS 模块在设计上是静态的,否则没有办法做到这一点(我认为 styled-components 也使用了 style 属性,所以你不会丢失任何东西)。
对于 2,您可以利用 Sass 模块,这些模块允许您在一个地方定义主题并根据需要导入它们:
/theme/_colors.scss
$red: rgb(200,0 50);
/components/Item.module.scss
@import "../theme/colors"
.selected {
background: $red;
}
注意:如果您使用 Create React App absolute paths,您可以从 root 导入为 ~theme/colors