每年十月,最大的国际 React 会议都会在印度果阿举行。是的,我说的是 React India。今年(2024 年)对我来说更加特别,因为我有机会在这场盛大的会议上发言。如果您错过了现场观看的话,这是我的演讲录音。如果您更喜欢阅读而不是观看视频,那么这个博客非常适合您!让我们深入探讨一下。
StyleX 是 Meta 的新的、可扩展的样式库,现在被用作 Facebook、Instagram 和 WhatsApp 等平台背后的主要系统。它解决了 CSS-in-JS 方法所遇到的痛点,特别是在大规模 React 应用程序中。通过提供融合原子 CSS 和静态 CSS 最佳功能的混合解决方案,StyleX 提供了高效、模块化和可扩展的替代方案。
原子 CSS 生成:StyleX 采用原子 CSS 生成,这意味着它为每个样式规则创建小型、可重用的类。这种方法不仅可以最大限度地减少最终 CSS 包中的冗余,还可以通过减小样式表的整体大小来提高性能。
CSS 重复数据删除:通过为每种样式生成唯一的类标识符,StyleX 有效地消除了重复的样式。此重复数据删除过程可确保每个属性值对仅渲染一次,进一步有助于实现更精简的 CSS 输出。
“最后应用的样式总是获胜!”:StyleX 遵循可预测的样式规则,其中最后应用的样式优先。此功能简化了调试并增强了开发人员的信心,因为它减轻了对样式规则冲突的担忧。
针对 React 进行了优化:StyleX 专为 React 应用程序设计,无缝集成到 React 生态系统中。它允许开发人员直接在其组件中定义样式,从而形成更具凝聚力的开发工作流程。
Flow 和 TypeScript 支持:StyleX 是用“Flow”(由 Meta 创建)编写的,它还为 TypeScript 提供强大的支持,为样式和主题启用类型安全的 API。这种类型安全性增强了代码的可靠性和可维护性,使管理复杂的样式场景变得更加容易。
灵活的条件样式:使用 StyleX,开发人员可以根据组件状态或 props 有条件地应用样式。这种灵活性允许动态样式适应用户交互或应用程序状态的变化。
范围样式:StyleX 的范围样式功能可确保样式仅应用于其预期的组件。这可以防止大型代码库中经常出现的意外副作用和特异性问题。
更少的运行时计算:StyleX 通过在编译时将所有样式捆绑到静态 CSS 文件中来最大限度地减少运行时计算。这种优化可以缩短渲染时间并提高性能,尤其是在大型应用程序中。
更好的代码可维护性:通过将样式与其各自的组件共置并利用原子类,StyleX 提高了代码的可维护性。开发人员可以轻松理解和修改样式,而无需筛选大量样式表。
最小 CSS 输出:使用原子 CSS 会导致最小 CSS 输出,这对性能特别有利。随着项目规模和复杂性的增加,StyleX 可确保 CSS 捆绑包在不牺牲功能的情况下保持可管理性。
适用于各种规模的项目:虽然 StyleX 适用于各种规模的项目,但它在大型应用程序中确实表现出色。其架构旨在处理广泛的样式需求的复杂性,而不影响性能或可维护性。
本文中的代码示例是用 React 编写的,我们将主要使用两个组件:App.jsx 和 Button.jsx。在添加样式之前,我们先看一下这些组件的基本结构。
import Button from "./components/Button"; const App = () => { return ( <div> <h1>StyleX by Meta</h1> <Button text="Get Started" /> </div> ); }; export default App;
// Button.jsx import PropTypes from "prop-types"; const Button = ({ text }) => { return <button>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
import PropTypes from "prop-types"; import * as stylex from "@stylexjs/stylex"; const styles = stylex.create({ base: { fontSize: 18, backgroundColor: "black", color: "white", }, }); const Button = ({ text }) => { return <button {...stylex.props(styles.base)}>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
要使用这些样式,我们需要从 styleX 包中导入它们,然后使用以对象作为参数的 stylex.create 方法定义样式。然后我们可以使用 stylex.props 方法将样式应用到组件。
在此示例中,base 是我们要应用的样式的名称。我们在 StyleX 中将它们称为 命名空间。这就是我们的按钮组件现在的样子。
import PropTypes from "prop-types"; import * as stylex from "@stylexjs/stylex"; const styles = stylex.create({ base: { fontSize: 18, backgroundColor: { default: "black", ":hover": "blue", }, color: "white", }, }); const Button = ({ text }) => { return <button {...stylex.props(styles.base)}>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
使用 StyleX,向伪类添加样式非常简单。在前面的示例中,backgroundColor 是一个字符串。在这里,我们将其转换为具有默认值和伪类的对象。
import PropTypes from "prop-types"; import * as stylex from "@stylexjs/stylex"; const styles = stylex.create({ base: { fontSize: 18, backgroundColor: { default: "black", ":hover": "blue", }, color: "white", width: { default: "100px", "@media (max-width: 476px)": "100%", }, }, }); const Button = ({ text }) => { return <button {...stylex.props(styles.base)}>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
与其他样式库相比,我们在 StyleX 中做的不同的一件事是媒体查询。在这里,我们根据需求将媒体查询应用于每个命名空间。在此示例中,我们将较大屏幕的按钮宽度定义为 100px,较小屏幕或移动设备的按钮宽度定义为 100%。
让我们扩展前面的示例,看看如何创建此按钮的不同变体。
const styles = stylex.create({ base: { fontSize: 18, backgroundColor: { default: "teal", ":hover": "blue", }, color: "white", width: { default: "100px", "@media (max-width: 476px)": "100%", }, }, highlighted: { backgroundColor: "orange", }, danger: { backgroundColor: "red", }, primary: { backgroundColor: "green", }, }); const Button = ({ text, isHighlighted, variant }) => { return ( <button {...stylex.props( styles.base, isHighlighted && styles.highlighted, // conditional styling styles[variant] )} > {text} </button> ); }; Button.propTypes = { text: PropTypes.string.isRequired, isHighlighted: PropTypes.bool, variant: PropTypes.oneOf(["danger", "primary"]), };
让我们向 stylex.create 方法添加更多命名空间,并为它们提供不同的背景颜色。此外,我们在 Button 组件中接受了 2 个新的 props。 isHighlighted 是一个布尔属性,我们用它来应用突出显示的命名空间。变量是我们用来应用主要、危险或突出显示的命名空间的道具。
// App.jsx import Button from "./components/Button"; const App = () => { return ( <div> <h1>StyleX by Meta</h1> <div {...stylex.props(styles.main)}> <Button text="Base Button" /> <Button text="Highlighted Button" isHighlighted /> <Button text="Danger Button" isHighlighted variant="danger" /> <Button text="Primary Button" variant="primary" /> </div> </div> ); }; export default App;
我们创建了几个 Button 组件的副本,并传递不同的 props。这就是我们的应用程序现在的样子。
现在,仔细看看“危险按钮”。即使我们将 isHighlighted 传入 true,突出显示的命名空间也不会应用。最后提到了危险变体,因此将应用它。因此,该按钮将具有红色背景颜色。
我们可以直接从 App.jsx 覆盖此 Button 组件的样式属性。
import Button from "./components/Button"; const App = () => { return ( <div> <h1>StyleX by Meta</h1> <Button text="Get Started" /> </div> ); }; export default App;
在此示例中,覆盖命名空间当前允许任何属性。然而,StyleX 使我们能够限制哪些属性可以被覆盖。使用 TypeScript 时,此功能变得特别有用。
// Button.jsx import PropTypes from "prop-types"; const Button = ({ text }) => { return <button>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
此限制确保只有 backgroundColor 和 color 属性可以被覆盖。
如果您向上滚动到前面的示例代码,您将看到我们已将 margin: "1rem" 样式添加到 3 个不同的命名空间 - App.jsx 中的 main、Button.jsx 中的突出显示和主要。当我们使用 Devtools 检查元素时,我们可以看到不同的组件(主容器、突出显示的按钮和主按钮)附加有相同的类名,并且只有 1 个类 x42y017 保留 margin: "1rem" 样式。
这就是 StyleX 通过使用原子类显着减小其包大小的方式。达到一定阈值后,不再生成新的类;相反,他们只是重用现有的类。
能够在粒度级别覆盖样式真是太棒了!然而,任何给定的设计系统都需要支持设计标记和主题。这就是 StyleX 的用武之地。StyleX 中主题 API 的设计直接受到 React Context API 的启发。变量的定义默认值与 React Context 的创建方式类似,并且可以创建主题来为 UI 子树的这些变量“提供”不同的值。
我们可以通过创建 x.stylex.js 文件来创建全局样式。确保遵循此命名约定。在此文件中,我们使用 stylex.defineVars,如下所示。
import PropTypes from "prop-types"; import * as stylex from "@stylexjs/stylex"; const styles = stylex.create({ base: { fontSize: 18, backgroundColor: "black", color: "white", }, }); const Button = ({ text }) => { return <button {...stylex.props(styles.base)}>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
我们指的是用户的首选主题并将其设置为常量值 - DARK。此外,让我们使用此颜色变量创建一个新主题。
import PropTypes from "prop-types"; import * as stylex from "@stylexjs/stylex"; const styles = stylex.create({ base: { fontSize: 18, backgroundColor: { default: "black", ":hover": "blue", }, color: "white", }, }); const Button = ({ text }) => { return <button {...stylex.props(styles.base)}>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
主题创建后,就可以像 StyleX 中的任何其他样式一样使用。
import PropTypes from "prop-types"; import * as stylex from "@stylexjs/stylex"; const styles = stylex.create({ base: { fontSize: 18, backgroundColor: { default: "black", ":hover": "blue", }, color: "white", width: { default: "100px", "@media (max-width: 476px)": "100%", }, }, }); const Button = ({ text }) => { return <button {...stylex.props(styles.base)}>{text}</button>; }; Button.propTypes = { text: PropTypes.string.isRequired, }; export default Button;
这就是我们如何分别在浅色和深色模式下看到与 myCustomTheme 相同的页面。
万岁!我们已经成功掌握了与 StyleX 合作的要点。感谢您阅读本文。我希望它能让您更好地理解什么是 StyleX、Meta 是如何创建它以及如何使用它。请在评论部分或 Twitter 上分享您的想法/疑问。如果您对这个博客感兴趣,如果您能给这篇文章点个赞(用您最喜欢的表情符号?),我将不胜感激。
平安✌
在 Topmate 上与我联系以进行面试准备
以上是解码 StyleX:Meta 的尖端造型系统的详细内容。更多信息请关注PHP中文网其他相关文章!