StyledCompnent를 응용하여 다이나믹한 스타일링과 스타일을 재사용하는 방법들을 정리하려한다.
다이나믹 스타일링
크기를 조절하는 size, 둥근 모양을 지정하는 round라는 Prop을 추가해 버튼 컴포넌트의 크기와 모양을 조절하는 예시를 보며 그 과정을 통해 다이나믹한 스타일링을 하는 법에 대해 알아보자.
Button.js
import styled from 'styled-components';
const SIZES = {
large: 24,
medium: 20,
small: 16,
};
const Button = styled.button`
background-color: #6750a4;
border: none;
border-radius: ${({ round }) => round ? `9999px` : `3px`};
color: #ffffff;
font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
padding: 16px;
&:hover,
&:active {
background-color: #463770;
}
`;
export default Button;
App.js
import styled from 'styled-components';
import Button from './Button';
const Container = styled.div`
${Button} {
margin: 10px;
}
`;
function App() {
return (
<Container>
<h1>기본 버튼</h1>
<Button size="small">small</Button>
<Button size="medium">medium</Button>
<Button size="large">large</Button>
<h1>둥근 버튼</h1>
<Button size="small" round>
round small
</Button>
<Button size="medium" round>
round medium
</Button>
<Button size="large" round>
round large
</Button>
</Container>
);
}
export default App;
${ … } 안에 함수, 값(변수) 사용하기
Prop에 따라 스타일을 다르게 적용하는 함수를 넣으려고 하는데 함수의 파라미터로는 Props를 받고, 리턴 값으로는 스타일 코드를 리턴하면 된다. 참고로 이건 템플릿 리터럴의 기능이 아니라 Styled Components가 내부적으로 처리해 주는 것이다.
const SIZES = {
large: 24,
medium: 20,
small: 16
};
const Button = styled.button`
...
font-size: ${(props) => SIZES[props.size]}px;
`;
만약 구조 분해(Destructuring)하면 아래처럼!
font-size: ${({ size }) => SIZES[size]}px;
그런데 여기서 size Prop이 값이 없거나 잘못된 값이면? Styled Components에서는 undefined 값을 빈 문자열로 처리해 주기 때문에 font-size: px 같은 잘못된 CSS 코드가 된다. 그래서 가능하면 기본 값을 정해주는 것이 좋다.
아래와 같은 식으로 널 병합 연산자(Nullish coalescing operator)를 사용하면 좋다.
font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
함수를 사용할 때 많이 사용하는 패턴 중 하나는 논리 연산자를 사용하는 것이다. 예를 들어, round라는 Prop이 참일 때 컴포넌트의 모서리를 둥글게 만드는 예제를 살펴보자.
const Button = styled.button`
...
${({ round }) => round && `
border-radius: 9999px;
`}
`;
round 값이 참이면 그 뒤에 값까지 계산하기 때문에 border-radius: 9999px이라는 문자열이 리턴돼서 적용된다. 반대로, round 값이 거짓이면 그냥 false가 리턴돼서 아무런 값도 적용되지 않는다. React에서 JSX로 조건부 렌더링 하는 것과 비슷하다.
삼항 연산자 사용하기
마찬가지로 자주 쓰는 패턴으로, round 가 참이면 완전히 둥근 모서리를 보여주고, 거짓이면 3px 정도로 살짝 부드럽게 깎인 모서리를 보여주고 싶다면 아래와 같이 삼항 연산자로 쓸 수 있다.
border-radius: ${({ round }) => round ? `9999px` : `3px`};
스타일 재사용하기
1. 상속
HTML 태그에 스타일링하는 건 styled.tagname을 사용해서 할 수 있었다. 그런데, JSX 문법으로 직접 만든 컴포넌트나, Styled Components를 사용해 이미 만들어진 다른 컴포넌트에 스타일을 입히려면 어떻게 해야 할까? 이런 상황에서는 상속을 사용하면 된다.
styled() 함수
Styled Components로 만들어진 컴포넌트를 상속하려면 styled() 함수를 사용하면 된다.
Button.js
import styled from 'styled-components';
const SIZES = {
large: 24,
medium: 20,
small: 16,
};
const Button = styled.button`
background-color: #6750a4;
border: none;
color: #ffffff;
font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
padding: 16px;
${({ round }) =>
round
? `
border-radius: 9999px;
`
: `
border-radius: 3px;
`}
&:hover,
&:active {
background-color: #463770;
}
`;
export default Button;
App.js
import styled from 'styled-components';
import Button from './Button';
const SubmitButton = styled(Button)`
background-color: #de117d;
display: block;
margin: 0 auto;
width: 200px;
&:hover {
background-color: #f5070f;
}
`;
function App() {
return (
<div>
<SubmitButton>계속하기</SubmitButton>
</div>
);
}
export default App;
JSX로 직접 만든 컴포넌트에 styled() 사용하기
styled.tagname으로 만든 컴포넌트는 바로 styled() 함수를 사용할 수 있지만, 그렇지 않은 컴포넌트는 따로 처리가 필요하다. 예를 들어, 약관을 보여주는 TermsOfService라는 컴포넌트가 있다고 하면
TermsOfService.js
function TermsOfService({className}) {
return (
<div className={className}>
<h1>㈜코드잇 서비스 이용약관</h1>
<p>
환영합니다.
<br />
Codeit이 제공하는 서비스를 이용해주셔서 감사합니다. 서비스를
이용하시거나 회원으로 가입하실 경우 본 약관에 동의하시게 되므로, 잠시
시간을 내셔서 주의 깊게 살펴봐 주시기 바랍니다.
</p>
<h2>제 1 조 (목적)</h2>
<p>
본 약관은 ㈜코드잇이 운영하는 기밀문서 관리 프로그램인 Codeit에서
제공하는 서비스를 이용함에 있어 이용자의 권리, 의무 및 책임사항을
규정함을 목적으로 합니다.
</p>
</div>
);
}
export default TermsOfService;
TermsOfService는 JSX 문법을 직접 사용해서 바로 컴포넌트가 만들어졌는데, 이 컴포넌트를 styled() 함수로 감싸보면
App.js
import styled from 'styled-components';
import Button from './Button';
import TermsOfService from './TermsOfService';
const StyledTermsOfService = styled(TermsOfService)`
background-color: #ededed;
border-radius: 8px;
padding: 16px;
margin: 40px auto;
width: 400px;
`;
const SubmitButton = styled(Button)`
background-color: #de117d;
display: block;
margin: 0 auto;
width: 200px;
&:hover {
background-color: #f5070f;
}
`;
function App() {
return (
<div>
<StyledTermsOfService />
<SubmitButton>계속하기</SubmitButton>
</div>
);
}
export default App;
정리하자면, 스타일 상속을 하려면 styled() 함수를 사용하면 되는데, styled.tagname으로 만든 컴포넌트는 styled() 함수로 바로 상속하면 되고, Styled Components를 사용하지 않고 직접 만든 컴포넌트에는 클래스 이름을 내려준 후에 styled() 함수로 상속해야 한다.
3. CSS함수
가끔 중복되는 CSS 코드들을 변수처럼 저장해서 여러 번 다시 사용하고 싶을 때가 있다. 그런 상황에서 주로 사용되는 css 함수에 대해 배워보자.
Button 컴포넌트와 Input 컴포넌트에 같은 글자 크기를 갖도록 하는 상황을 생각해 보자면. size라는 Prop으로 small, medium, large 각각에 지정된 크기를 전달하면 16, 20, 24 픽셀로 글자 크기를 지정하려 한다.
단순한 방법은 아래처럼 두 번 작성하는 형태지만,
import styled from 'styled-components';
const SIZES = {
large: 24,
medium: 20,
small: 16
};
const Button = styled.button`
...
font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
`;
const Input = styled.input`
...
font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
`;
반복되는 코드는 이렇게 css함수를 사용하여 한 곳에 저장하고 활용하는 것이 바람직하다.
import styled, { css } from 'styled-components';
const SIZES = {
large: 24,
medium: 20,
small: 16
};
const fontSize = css`
font-size: ${({ size }) => SIZES[size] ?? SIZES['medium']}px;
`;
const Button = styled.button`
...
${fontSize}
`;
const Input = styled.input`
...
${fontSize}
`;
'react' 카테고리의 다른 글
[StyledComponent] Nesting 문법 (0) | 2024.07.08 |
---|---|
[React] StyledComponent (0) | 2024.07.05 |
리액트 생명주기(life cycle) (0) | 2024.07.01 |
React Hook (0) | 2024.06.25 |