【问题标题】:How to wrap up Ant Design with Styled Components and TypeScript?如何用样式化组件和 TypeScript 包装 Ant Design?
【发布时间】:2019-03-13 06:33:31
【问题描述】:

我想用 styled-components 包装我的 ant-design 组件,我知道这是可能的 (https://gist.github.com/samuelcastro/0ff7db4fd54ce2b80cd1c34a85b40c08) 但是我在使用 TypeScript 时遇到了麻烦。

这是我目前所拥有的:

import { Button as AntButton } from 'antd';
import { ButtonProps } from 'antd/lib/button/button';
import styledComponents from 'styled-components';

interface IButtonProps extends ButtonProps {
   customProp: string;
}

export const Button = styledComponents<IButtonProps>(AntButton)`
  // any custom style here
`;

如您所见,我使用 as any 定义了我的 ant-design 按钮以使其正常工作,否则我会得到一些不兼容的类型,例如:

Argument of type 'typeof Button' is not assignable to parameter of
type 'ComponentType<IButtonProps>'.

Type 'typeof Button' is not assignable to type
'StatelessComponent<IButtonProps>'.

Types of property 'propTypes' are incompatible.

 Property 'customProp' is missing in type '{ 
    type: Requireable<string>; 
    shape: Requireable<string>; 
    size: Requireable<string>; 
    htmlType: Requireable<string>; 
    onClick: ...
    etc
 }

谢谢。

解决方案:

import { Button as AntButton } from 'antd';
import { NativeButtonProps } from 'antd/lib/button/button';
import * as React from 'react';
import styledComponents from 'styled-components';

export const Button = styledComponents<NativeButtonProps>(props => <AntButton {...props} />)`
    // custom-props
`;

【问题讨论】:

  • 如果您能更具体一点会有所帮助 - 您面临的具体问题是什么?您可以提供的信息越多(最好也显示您的代码),更多的人将能够提供帮助:)
  • @JoeClay 谢谢添加更多信息。
  • 请将您的导入添加到问题中。我猜import styledComponents from "styled-components"import { Button as AntButton } from "antd" 但我猜不出IButtonProps 来自哪里。
  • @MattMcCutchen 添加了导入。谢谢!
  • 刚试过:export const Button = styledComponents&lt;IButtonProps, any&gt;(AntButton) 好像还可以,就是不知道styledComponents&lt;IButtonProps, any&gt; 的第二个类型参数是什么意思。

标签: typescript antd styled-components


【解决方案1】:

问题的根源似乎是styled-components期望内部组件(AntButton)接受所有指定接口(@98​​7654324@)中的props,但是AntButton不接受customProp。要解决此问题,请按照文档的this section 中的最后一个示例,并在调用AntButton 之前使用无状态函数组件删除customProp

export const Button = styledComponents<IButtonProps>(
  ({ customProp, ...rest }) => <AntButton {...rest} />)`
  // any custom style here
`;

【讨论】:

  • 谢谢马特,这工作得很好,但是现在当我尝试使用我的新按钮组件时:&lt;Button onClick={prop.onChange}/&gt; Typescript 抱怨:Type '{ onClick: any; }' is not assignable to type 'Readonly&lt;ThemedOuterStyledProps&lt;WithOptionalTheme&lt;ButtonProps, ThemeInterface&gt;, ThemeInterface&gt;&gt;'. Property 'style' is missing in type '{ onClick: any; }'.
  • 好的,我解决了这个问题,从 antd 导入 NativeButtonProps 而不是 ButtonProp
【解决方案2】:

上述解决方案对我不起作用,但这解决了它。

const Button = styled((props: NativeButtonProps) => <AntButton {...props} />)``;

【讨论】:

    【解决方案3】:

    index.tsx(按钮组件)

    import { Button as AntButton } from 'antd'
    import { NativeButtonProps } from 'antd/lib/button/button'
    import 'antd/lib/button/style/css'
    import * as React from 'react'
    import styledComponents from 'styled-components'
    import * as colours from '../colours'
    
    const getColour = (props: any) =>
      props.status === 'green'
        ? colours.STATUS_GREEN
        : props.status === 'red'
          ? colours.STATUS_RED
          : props.type === 'primary'
            ? colours.PRIMARY
            : colours.WHITE
    
    export interface ButtonProps extends NativeButtonProps {
      status?: string
    }
    
    export default styledComponents((props: ButtonProps) => <AntButton {...props} />)`
      &:focus,
      &:hover
      & {
        background-color: ${getColour};
        border-color: ${getColour};
      }
    `
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.5.2/umd/react.production.min.js"></script>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.5.2/umd/react-dom.production.min.js"></script>

    import React from 'react'
    import Button, { ButtonProps } from './index'
    
    interface ButtonAsyncSingleSuccessProps extends ButtonProps {
      clickFunc: any, // (...args: any[]) => Promise<any>
      labelLoading: string,
      labelReady: string,
      labelSuccess: string,
    }
    
    interface ButtonAsyncSingleSuccessState {
      label: string,
      loading: boolean,
      status: string
    }
    
    export default class ButtonAsyncSingleSuccess extends React.Component<
      ButtonAsyncSingleSuccessProps,
      ButtonAsyncSingleSuccessState
    > {
      constructor (props: any) {
        super(props)
        this.state = {
          label: props.labelReady,
          loading: false,
          status: ''
        }
      }
      public clickHandler (event: any) {
        const { labelLoading, labelReady, labelSuccess, clickFunc } = this.props
        this.setState({
          label: labelLoading,
          loading: true,
          status: ''
        })
        clickFunc(event)
          .then(() => {
            this.setState({
              label: labelSuccess,
              loading: false,
              status: 'green'
            })
          })
          .catch(() => {
            this.setState({
              label: labelReady,
              loading: false,
              status: 'red'
            })
          })
      }
      public render () {
        const {
          labelLoading,
          labelReady,
          labelSuccess,
          clickFunc,
          ...props
        } = this.props
        const { label, loading, status } = this.state
        if (status === 'red') {
          setTimeout(() => this.setState({ status: '' }), 1000) // flash red
        }
        return (
          <Button
            {...props}
            loading={loading}
            status={status}
            onClick={(e) => this.clickHandler(e)}
          >
            {label}
          </Button>
        )
      }
    }

    【讨论】:

    • 如果我想让 AntdButton 可重用并在每种情况下传递不同的样式怎么办?
    • 我认为您可以通过传递不同的样式名称道具轻松做到这一点。
    【解决方案4】:

    我发现了这个古老的问题并尝试以一种简单的方式解决:

    import React from 'react';
    import styled from 'styled-components';
    import { Card } from 'antd';
    import { CardProps } from 'antd/lib/card';
    
    export const NewCard: React.FunctionComponent<CardProps> = styled(Card)`
      margin-bottom: 24px;
    `;
    

    没有渲染道具:D

    如果你只需要将一个组件包装为函数组件,那没关系。但是你会丢失类组件的属性,例如Card.Meta

    有一个解决方法:

    import React from 'react';
    import styled from 'styled-components';
    import { Card } from 'antd';
    import { CardProps } from 'antd/lib/card';
    
    export const NewCard: typeof Card = styled(Card)<CardProps>`
      margin-bottom: 24px;
    ` as any;
    

    一切(也许...... XD)都作为原始 Antd 组件工作;)

    【讨论】:

      【解决方案5】:

      我的代码在这里。这是工作。

      
      import React from 'react';
      import { Button as AntButton } from 'antd';
      import { ButtonProps } from 'antd/lib/button/button';
      import styled from 'styled-components';
      
      const Container = styled.div`
        font-size: 20px;
      `;
      
      
      const Button: React.FunctionComponent<ButtonProps> = styled(AntButton)`
        margin-top: 24px;
        margin-left: 30px;
      `;
      
      export default function Home() {
        return (
          <Container>
            Hello World
            <Button type="primary">test</Button>
          </Container>
        );
      }
      
      
      
      

      【讨论】:

        猜你喜欢
        • 2020-09-13
        • 2021-04-13
        • 2020-02-17
        • 2019-04-19
        • 2018-09-05
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多