Reputation: 7624
I'm playing with styled-components
for the first time, and I'm having an issue with ´react` passing on props only used by the styled component itself.
Here's my component:
import { Link } from 'react-router-dom';
const CtaButton = styled(Link)`
background: ${props => props.primary ? 'red' : 'yellow'}
color: white;
display: inline-block;
padding: 0.5em 1em;
`;
When I invoke this with the primary
prop, I get a warning from react
that I'm applying the primary
prop to the <a />
element. I understand why this happens - but how can I stop it?
I can of course create a wrapper around react-router
's Link
component that strips this prop - but that would be kind of clumsy. I'm sure it's just me not being a pro in this lib's API yet - so can somebody please point me in the right direction?
For some reason I don't have this issue when I create DOM component directly (styled.a
for instance).
Upvotes: 2
Views: 1342
Reputation: 7624
Looks like this is a known limitation of styled-components
. The reason this doesn't work is because the library strips props when applied to DOM-elements (based on a white list). This can't really be done the same way with components, since a random component does not really have a predictable API.
While the authors and contributors are fixing this, this is the work-around I came up with:
import React from 'react';
import { Link } from 'react-router-dom';
const StyledLink = ({ primary, ...rest }) => <Link {...rest} />;
export const CtaButton = styled(StyledLink)`
background: ${props => props.primary ? 'red' : 'yellow'}
color: white;
display: inline-block;
padding: 0.5em 1em;
`;
In other words, wrapping the component with another component that strips whatever styled component specific props and then re-applies the remaining props. It's not pretty, but as far as I can see it's the simplest solution there is.
You could also create a HOC that would do this for you:
const withStrippedProps = propsToRemove => TargetComponent => (props) => {
const strippedProps = Object.entries(props)
.filter(([key]) => !propsToRemove.includes(key))
.reduce((stripped, [key, value]) => ({ ...stripped, [key]: value }), {});
return <TargetComponent {...strippedProps} />
};
const StyledLink = withoutProps(['primary'])(Link);
const CtaButton = styled(StyledLink)`
// css goes here
`;
I'm accepting this as the answer for now, but if there are any other approaches that doesn't create a wrapper component / function like this, I'll be open to accepting another answer.
Upvotes: 3