Styled components in a hoc react component

北战南征 提交于 2021-01-28 06:16:46

问题


I am having two issues with using styled components in a hoc wrapper in react.

  1. The component is rendered, but not with the background color.
  2. The ComponentWithAddedColors is not valid typescript. Don't know why.

Anyone who can help with this?

interface IProps {
  id: string;
  left: number;
  top: number;
}

export const Node: React.FC<IProps> = ({ id, left, top }) => {
  return (
    <Container left={left} top={top}>
      {id}
    </Container>
  );
};

function withColors<T>(Component: React.ComponentType<T>) {
  const bg = "hotpink";
  const ComponentWithAddedColors = styled(Component)`
    ${bg && `background: ${bg};`}
  `;
  const result: React.FC<T> = (props) => (
    <ComponentWithAddedColors {...props} />
  );
  return result;
}

const DraggableNode = withColors(Node);
export default DraggableNode;

I have made a code sandbox to illustrate the issue: https://codesandbox.io/s/styled-hoc-xgduo?file=/src/Components/Node/Node.tsx


回答1:


Style Errors Explained

@Mosh Feu's comment pointed me in the right direction.

You can add styles to an already styled component and you can add styles to a custom component, but those two things work differently. You have a chain that goes through both types, so things are getting lost.

When you call withColors(Node) what this is doing is passing a generated className prop to Node. But your custom component Node never does anything with this prop, so the style is never applied.

The styled method works perfectly on all of your own or any third-party component, as long as they attach the passed className prop to a DOM element.

Style Errors Fixed

If we edit Node to use this className, we get the color!

export const Node: React.FC<IProps & {className?: string}> = ({ id, left, top, className}) => {
  return (
    <Container left={left} top={top} className={className}>
      {id}
    </Container>
  );
};

TS Errors Explained

As far as the typescript errors are concerned, you're getting an error about assigning your props T to the props of a styled component (ComponentWithAddedColors), which shows up as a bunch of crazy nonsense:

(props: (Pick<Pick<(PropsWithoutRef & RefAttributes<Component<T, any, any>>) | (PropsWithRef<PropsWithChildren> & {}), Exclude<...> | ... 1 more ... | Exclude<...>> & Partial<...>, Exclude<...> | ... 1 more ... | Exclude<...>> & { ...; } & { ...; }) | (Pick<...> & ... 2 more ... & { ...; })): ReactElement<...>

This is mainly because of ref forwarding through the ForwardRefExoticComponent type.

But we can work backwards to get the expected props type from the component type using a utility type:

type PropsOf<T> = T extends React.ComponentType<infer P> ? P : never;

So ComponentWithAddedColors has props PropsOf<typeof ComponentWithAddedColors>. We could use that, but we also know that ComponentWithAddedColors has type StyledComponent<React.ComponentType<T>, any, {}, never>, so we can go back a step further:

type StyledProps<InitialProps> = PropsOf<StyledComponent<React.ComponentType<InitialProps>, any, {}, never>>

So ComponentWithAddedColors has props StyledProps<T>.

TS Errors Fixed

That said, all of this is unnecessary, at least in the example you've shown. You are passing all of the props of ComponentWithAddedColors through to ComponentWithAddedColors, so result is the same thing as the component itself. Just return it directly.

function withColors<T>(Component: React.ComponentType<T>) {
  const bg = "hotpink";
  return styled(Component)`
    ${bg && `background: ${bg};`}
  `;
}


来源:https://stackoverflow.com/questions/64596282/styled-components-in-a-hoc-react-component

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!