1
votes

When extending a base component using styled components, is there a way to access props from the base component in the extended component?

Here's the base component and its styled component. On line 8 I pass in isOpen. In the styled component I toggle between two colors for the background colors, which are based on isOpen.

const StyledBaseComponent = styled.button`
  background-color: ${({ isOpen }) => (isOpen ? 'cyan' : 'orange')};
`
function BaseComponent(props) {
  const [isOpen, toggleOpen] = useState(false)

  return (
    <StyledBaseComponent {...props} isOpen={isOpen} onClick={() => toggleOpen(!isOpen)}>
      isOpen - {String(isOpen)}
    </StyledBaseComponent>
  )
}

Here's the extended component and its styled component. On line 2 I try to use isOpen from the parent to toggle colors but it's undefined so the color will always be yellow.

const StyledExtendedComponent = styled(BaseComponent)`
  background-color: ${({ isOpen }) => (isOpen ? 'pink' : 'yellow')};
`
function ExtendedComponent() {
  return <StyledExtendedComponent />
}

Here's a codesandbox for the issue: https://codesandbox.io/s/4q60qqx027. The left button, which is the base component, works as expected. The right button, which extends the base component, doesn't change colors.

1

1 Answers

1
votes

One solution could be to include className prop, see in the official documentation: styling-any-components. I cannot open your link to see if this will work.

A second solution would be to pass the colors as props in BaseComponent and have the default colors the ones that BaseComponent needs:

const { openColor = "cyan", closedColor = "orange" } = this.props;

return (
  <StyledBaseComponent
    isOpen={isOpen}
    onClick={() => this.toggleOpen()}
    openColor={openColor}
    closedColor={closedColor}
  >
    isOpen - {String(isOpen)}
  </StyledBaseComponent>
)

So afterwards, in ExtendedComponent

export function ExtendedComponent() {
  return <BaseComponent openColor="pink" closedColor="yellow" />;
}

example here

Another possible solution would be to pass the styled component as prop in BaseComponent. Something like:

const StyledBaseComponent = styled.button`
  background-color: ${({ isOpen }) => (isOpen ? "cyan" : "orange")};
`;

const StyledExtendedComponent = styled(StyledBaseComponent)`
  background-color: ${({ isOpen }) => (isOpen ? "pink" : "yellow")};
`;

function App() {
  return (
    <div className="App">
      <BaseComponent MyButtom={StyledBaseComponent} />
      <BaseComponent MyButtom={StyledExtendedComponent} />
    </div>
  );
}

and in BaseComponent

  render() {
    const { isOpen } = this.state;
    const { MyButtom } = this.props;

    return (
      <MyButtom isOpen={isOpen} onClick={() => this.toggleOpen()}>
        isOpen - {String(isOpen)}
      </MyButtom>
    );
  }

see an example here. You can achieve the same using hooks.