秘诀
在 Chakra 中使用配方编写多变量样式。
概述
¥Overview
Chakra 提供了一种编写 CSS-in-JS 的方法,具有更好的性能、开发者体验和可组合性。其主要特性之一是能够使用类型安全的运行时 API 创建多变量样式。
¥Chakra provides a way to write CSS-in-JS with better performance, developer experience, and composability. One of its key features is the ability to create multi-variant styles with a type-safe runtime API.
配方包含以下属性:
¥A recipe consists of these properties:
-
className
:要附加到组件的 className -
base
:组件的基本样式 -
variants
:组件的不同视觉样式 -
compoundVariants
:组件变体的不同组合 -
defaultVariants
:组件的默认变体值
定义配方
¥Defining the recipe
使用 defineRecipe
标识函数创建配方。
¥Use the defineRecipe
identity function to create a recipe.
button.recipe.ts
import { defineRecipe } from "@chakra-ui/react"
export const buttonRecipe = defineRecipe({
base: {
display: "flex",
},
variants: {
visual: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
})
使用配方
¥Using the recipe
在组件中,有两种方法可以使用配方:
¥There are two ways to use the recipe in a component:
-
直接在带有
useRecipe
的组件中 -
使用
chakra
工厂创建组件(推荐)
RSC 提示:由于它依赖于 React Hooks(例如 useContext
和 useInsertionEffect
),因此需要添加 "use client"
指令。
¥RSC Tip: Adding the "use client"
directive is required since it relies on
react hooks like useContext
and useInsertionEffect
under the hood.
直接在组件中
¥Directly in component
使用 useRecipe
钩子获取组件的配方。然后,使用变体属性调用配方以获取样式。
¥Use the useRecipe
hook to get the recipe for a component. Then, call the
recipe with its variant props to get the styles.
button.tsx
"use client"
import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = (props) => {
const { visual, size, ...restProps } = props
const recipe = useRecipe({ recipe: buttonRecipe })
const styles = recipe({ visual, size })
return <chakra.button css={styles} {...restProps} />
}
splitVariantProps
请注意 visual
和 size
属性是如何从要传递给配方的属性中解构出来的。更智能的方法是自动将配方属性与组件属性分离。
¥Notice how the visual
and size
props were destructured from the props to be
passed to the recipe. A smarter approach would be to automatically split the
recipe props from the component props.
为此,请使用 recipe.splitVariantProps
函数将配方属性与组件属性分离。
¥To do that, use the recipe.splitVariantProps
function to split the recipe
props from the component props.
button.tsx
"use client"
import { chakra, useRecipe } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = (props) => {
const recipe = useRecipe({ recipe: buttonRecipe })
const [recipeProps, restProps] = recipe.splitVariantProps(props)
const styles = recipe(recipeProps)
// ...
}
TypeScript
要推断配方变体属性的类型,请使用 RecipeVariantProps
类型助手。
¥To infer the recipe variant prop types, use the RecipeVariantProps
type
helper.
button.tsx
import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>
export interface ButtonProps
extends React.PropsWithChildren<ButtonVariantProps> {}
创建组件
¥Creating a component
使用 chakra
函数根据配方创建组件。
¥Use the chakra
function to create a component from a recipe.
注意:该配方也可以内联到 chakra
函数中。
button.tsx
"use client"
import { chakra } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
export const Button = chakra("button", buttonRecipe)
接下来,使用该组件并将配方属性传递给它。
¥Next, use the component and pass recipe properties to it.
app.tsx
import { Button } from "./button"
const App = () => {
return (
<Button visual="solid" size="lg">
Click Me
</Button>
)
}
默认变量
¥Default Variants
defaultVariants
属性用于设置配方的默认变量值。当你想默认应用变体时,此功能非常有用。
¥The defaultVariants
property is used to set the default variant values for the
recipe. This is useful when you want to apply a variant by default.
button.tsx
"use client"
import { chakra } from "@chakra-ui/react"
const Button = chakra("button", {
base: {
display: "flex",
},
variants: {
visual: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
defaultVariants: {
visual: "solid",
size: "lg",
},
})
复合变体
¥Compound Variants
使用 compoundVariants
属性定义一组基于其他变体组合应用的变体。
¥Use the compoundVariants
property to define a set of variants that are applied
based on a combination of other variants.
button.tsx
"use client"
import { chakra } from "@chakra-ui/react"
const button = cva({
base: {
display: "flex",
},
variants: {
visual: {
solid: { bg: "red.200", color: "white" },
outline: { borderWidth: "1px", borderColor: "red.200" },
},
size: {
sm: { padding: "4", fontSize: "12px" },
lg: { padding: "8", fontSize: "24px" },
},
},
compoundVariants: [
{
size: "small",
visual: "outline",
css: {
borderWidth: "2px",
},
},
],
})
当你同时使用 size="small"
和 visual="outline"
变体时,compoundVariants
会将 css
属性应用于组件。
¥When you use the size="small"
and visual="outline"
variants together, the
compoundVariants
will apply the css
property to the component.
app.tsx
<Button size="small" visual="outline">
Click Me
</Button>
注意事项
¥Caveat
由于设计限制,无法使用具有响应式值的 compoundVariants
。
¥Due to the design constraints, using compoundVariants
with responsive values
doesn't work.
这意味着这样的代码将无法工作:
¥This means a code like this will not work:
<Button size={{ base: "sm", md: "lg" }} visual="outline">
Click Me
</Button>
对于这些情况,我们建议使用不同的断点渲染组件的多个版本,然后根据需要隐藏/显示。
¥For this cases, we recommend rendering multiple versions of the component with different breakpoints, then hide/show as needed.
主题使用
¥Theme Usage
要以可重复使用配方的方式,请将其移至系统主题并将其添加到 theme.recipes
属性。
¥To use the recipe in a reusable manner, move it to the system theme and add it
to theme.recipes
property.
theme.ts
import { createSystem, defaultConfig, defineConfig } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
const config = defineConfig({
theme: {
recipes: {
button: buttonRecipe,
},
},
})
export default createSystem(defaultConfig, config)
TypeScript
使用 CLI 生成秘诀的类型。
¥Use the CLI to generate the types for the recipe.
npx @chakra-ui/cli typegen ./theme.ts
然后,将生成的类型导入到你的组件中。
¥Then, import the generated types in your component.
button.tsx
import type { RecipeVariantProps } from "@chakra-ui/react"
import { buttonRecipe } from "./button.recipe"
type ButtonVariantProps = RecipeVariantProps<typeof buttonRecipe>
export interface ButtonProps
extends React.PropsWithChildren<ButtonVariantProps> {}
更新代码
¥Update code
如果你直接在组件中使用配方,请更新 useRecipe
以使用 key
属性从主题中获取配方。
¥If you use the recipe directly in your component, update the useRecipe
to use
the key
property to get the recipe from the theme.
button.tsx
const Button = () => {
- const recipe = useRecipe({ recipe: buttonRecipe })
+ const recipe = useRecipe({ key: "button" })
// ...
}