emotion 使用 css prop 和自定义组件

emotion use css prop with custom components

在我的应用程序中,我有一个组件,我想使用外部的 css 道具来设置样式。

function Component({css}:{css?: React.CSSProperties}) {
  // some stuff going on here
  return (
    <div
      css={{
        color: blue,
        ...css
      }}
    >
       // some stuff going on here
    </div>
  )
}

背景如下: 我想在必须根据周围布局设置容器样式的不同场景中使用 Component。例如。 flex、grid 或结合某些组件我必须添加不同的边距。

现在我希望能够从组件外部设置容器的样式,而不是为所有可能的场景引入许多道具。

例如该组件的用法可能是:

function Layout() {
  return (
    // some other components
    <Component css={{margin: 12}}/>
    // some other components
  )
}

import {css} from "@emotion/react"

const style = css({margin: 12})

function Layout() {
  return (
    // some other components
    <Component css={style}/>
    // some other components
  )
}

import {css} from "@emotion/react"

const style1 = css({margin: 12})
const style2 = css({color: 'red'})

function Layout() {
  return (
    // some other components
    <Component css={[style1, style2]}/>
    // some other components
  )
}

我有以下问题:

  1. 如果我使用 css 作为道具名称(如上例所示),则不会应用该样式。如果我将道具的名称更改为例如newCss 它按预期工作
  2. React.CSSProperties 不是处理情绪所有可能性的正确道具类型 css 道具。
  3. 如何将不同的 css 道具可能性(对象、列表)与来自 Component 的 css 道具合并?

实现此功能的正确方法是修改组件以接受额外的道具。这样,传递到组件中的 css 属性将与组件中的属性合并。

function Component({prop1, prop2, propN, ...props}) {
  // some stuff going on here
  return (
    <div
      css={{
        color: blue,
      }}
      {...props}
    >
       // some stuff going on here
    </div>
  )
}

现在您可以在您的组件上使用额外的样式,它会被正确呈现。

function Layout() {
  return (
    // some other components
    <Component css={{marginTop: "1em"}}/>
    // some other components
  )
}

此解决方案的副作用是,任何额外的 prop 都将直接传递给采用 {...props} 的组件内的 HTML 元素。

事实上,我们不需要使用额外的道具。正如 Ben Laniado 所提到的,官方文档指出

Any component or element that accepts a className prop can also use the css prop.

https://emotion.sh/docs/css-prop#use-the-css-prop

所以我们需要接受 classNamecss 作为 props 并将 className 添加到组件中。 (我们不需要组件 css 但类型需要它)

type ComponentProps = {
  css?: SerializedStyles;
  className?: string;
};
const Component: VFC<ComponentProps> = ({ className }) => {
  return (
    <div css={{ color: blue }} className={className}>
      hello world
    </div>
  );
};
export default function App() {
  return (
    <div className="App">
      <Component css={{ margin: 12 }} />
    </div>
  );
}

这是完整的工作示例。
https://codesandbox.io/s/react-component-accepting-emotion-css-prop-wskbh?file=/src/App.tsx