I am making a component library to use in a project of mine - I've worked quite a bit with styled-components before and it's my preferred way of applying styles to my components. What I like best about it is the ability to make my components fully functional and self-contained.
I have one problem that I haven't really been able to solve satisfactory though.
I want to do something like this, but whatever I do I can't seem to access or set the props from within the styled-component.
import React, { useState } from 'react';
import styled from 'styled-components';
const Button = ({ className }) => {
const [clicked, setClicked] = useState(false);
return (
<button className={className} clicked={clicked} onClick={() => setClicked(!clicked)}>
{this.props.children}
</button>
);
};
export default styled(Button)`
${applySomeStyle}
${props => props.clicked} {
${applySomeOtherStyle}
}
`;
I have been able to 'solve' it by doing this, but it seems incredibly redundant to create a dummy component just for this purpose. It would seem more natural to just be able to do what I do in example #1.
import React, { useState } from 'react';
import styled from 'styled-components';
const Dummy = styled.button``;
const Button = ({ className }) => {
const [clicked, setClicked] = useState(false);
return (
<Dummy className={className} clicked={clicked} onClick={() => setClicked(!clicked)}>
{this.props.children}
</Dummy>
);
};
export default styled(Button)`
${applySomeStyle}
${Dummy} {
${props => props.clicked} {
${applySomeOtherStyle}
}
}
`;
EDIT: The suggested linked issues are not applicable. The first linked issue is a person essentially asking how to pass props to his child components. The second issue is similar, but the answers are outdated because it predates the useState hook which allow us to not use Class components (The answer to the issue is basically saying that styled-components can't be used in Class components).
styled()
cannot refer to inner state. It does not matter if it's class and this.state
or function and useState
hook. The only way to handle that is splitting component into two: first to handle state changes and another one to encapsulate changes based on props.
import React, { useState } from 'react';
import styled from 'styled-components';
const InnerButton = styled(button)`
${props => props.clicked} {
${applySomeOtherStyle}
}
`;
const Button = ({ className }) => {
const [clicked, setClicked] = useState(false);
return (
<InnerButton className={className} clicked={clicked} onClick={() => setClicked(!clicked)}>
{this.props.children}
</InnerButton>
);
};
export default styled(Button)`
${applySomeStyle}
`;
Have you tried using the hook to conditionally set the className? Something like this...
import React, { useState } from 'react';
import styled from 'styled-components';
const ButtonStyled = styled('button')`
.className {
color: red;
}
`
export const Button = () => {
const [clicked, setClicked] = useState(false);
return (
<ButtonStyled className={clicked ? 'className' : ''} clicked={clicked} onClick={() => setClicked(!clicked)}>
{this.props.children}
</ButtonStyled>
)}
Or, if you import the css
property from styled-components, you can do something like this....
import React, { useState } from 'react';
import styled, { css } from 'styled-components'
const ButtonStyled = styled('button')`
${({ clicked }) =>
clicked &&
css`
color: red;
}
`
export const Button = () => {
const [clicked, setClicked] = useState(false);
return (
<ButtonStyled clicked={clicked} onClick={() => setClicked(!clicked)}>
{this.props.children}
</ButtonStyled>
)}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With