영어 문서 읽기 싫어서 한글 자료 찾아다니다가 종택님이 이상한거 보지 말고 공식문서 보라고 해서 내가 기억하려고 쓰는 TIL
토익 공부할 때보다 영어 더 많이 보는 것 같다.
스타일 컴포넌트 scss만큼 쉬울줄 알았는데 넘 어렵다
스타일 컴포넌트 초기세팅... 맘 급해서 막했다가 시간만 날리고... 그냥 차근차근 공식문서를 봐야겠다 싶었다.
리액트에서 컴포넌트 컴포넌트 컴포넌트 정말 많이 듣고 보고 쓰고 다뤘다. 그 컴포넌트에 아예 스타일을 입혀놓은 게 Styled Component. className을 알아서 안 겹치게 지어줌. Sass로 네스팅 해줘도 가끔 충돌 날 때 있어서 이럴거면 네스팅 왜 해~!~! 했었는데 얘는 그럴 일 없다 함. 개꿀👍
import styled from 'styled-components';
...
render(
<div>
<Button>Normal</Button>
<Button primary>Primary</Button>
</div>
);
const Button = styled.button`
background: ${props => props.primary ? "palevioletred" : "white"};
color: ${props => props.primary ? "white" : "palevioletred"};
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
const Button = styled.button
에서 Button
은 스타일링을 줄 컴포넌트 이름을 의미한다. 컴포넌트는 대문자로 시작함을 잊지 말자~ styled.button
은 styled
constructor로 어떤 HTML 태그에 스타일을 줄 것인지 선택하는 것인데 button 태그임을 알 수 있다.
정리하자면 HTML 태그가 button으로 렌더링되는 컴포넌트 Button을 새로 만든 것이당. 뭔말인지 모르겠다면 뚝딱 위의 샘플 코드를 렌더링하여 개발자도구 element 패널에서 해당 컴포넌트가 어떻게 그려져있는지 확인하자. 스타일 컴포넌트는 클래스/함수 컴포넌트랑은 다른 거라는거에 주의 !
styled.button
과 styled('button')
은 똑같다.
작동 원리는 document.querySelector 등으로 해당 태그명을 선택하는 그런건데 자세한건 이 유튜브 영상에 잘 나와있음.
지금 이 코드에선 Button 컴포넌트를 렌더링하고 있다. Button 컴포넌트 안에 primary가 보인다. 어디서 많이 본 형태다. props다. 아래의 부분은 props를 활용하여 조건부 스타일링한 것이다.
background: ${props => props.primary ?
"palevioletred" : "white"};
styled.button
뒤에 백틱이 보인다. 이 문법을 Tagged Template Literals라고 부른다. ES6 문법인데 스타일 컴포넌트의 핵심인듯? 여기에 설명 잘 되어있당. 템플릿 리터럴의 연장선상이라고 함. 백틱 안에서 모든 CSS 문법을 사용할 수 있다.위에서 props를 활용해 조건부 스타일링하는 것을 봤다. 스타일을 확장할 수도 있음.
render(
<div>
<Button>Normal Button</Button>
<TomatoButton>Tomato Button</TomatoButton>
</div>
);
const Button = styled.button`
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
`;
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
TomatoButton
스타일 컴포넌트는 styled
constructor로 Button
스타일 컴포넌트를 썼다. 여기다가 Tagged Template Literals로 추가 스타일링을 적었다. 이건 Button
스타일 컴포넌트를 상속받으면서 그 위에 override한다는 것임! 결론적으로 TomatoButton
스타일 컴포넌트엔 다음과 같은 속성이 적용됨.
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
color: tomato;
border-color: tomato;
한국어로는 머라고 부를까..?
render(
<div>
<Button>Normal Button</Button>
<Button as="a" href="/">Link with Button styles</Button>
<TomatoButton as="a" href="/">Link with Tomato Button styles</TomatoButton>
</div>
);
const Button = styled.button`
display: inline-block;
color: palevioletred;
font-size: 1em;
margin: 1em;
padding: 0.25em 1em;
border: 2px solid palevioletred;
border-radius: 3px;
display: block;
`;
const TomatoButton = styled(Button)`
color: tomato;
border-color: tomato;
`;
원래 Button
스타일 컴포넌트는 button 태그인데, as="a"
를 통해서 button 태그를 a태그로 사용했다. 스타일은 같게, 태그는 다르게 확장.
as로 태그 내용물도(텍스트) 바꿀 수 있다
const DiffButton = props => <Button {...props} children="내용바뀜" />
render(
<div>
<Button>Normal Button</Button>
<Button as={DiffButton}>Custom Button with Normal Button styles</Button>
</div>
);
이러면 두 번째 버튼은 첫 번째 버튼과 동일한 스타일을 가지지만 내용물 텍스트는 custom 어쩌구가 아니라 내용바뀜으로 들어간다
이건 scss랑 똑같음. & 선택자로 자기 자신을 선택하고 .으로 className을 선택한다. scss랑 거의 비슷해서 어렵진 않은데 새로웠던(?)거 🔽
const Thing = styled.div`
color: blue;
.something {
border: 1px solid;
display: block;
}
`;
<Thing>
<label htmlFor="foo-button" className="something">Mystery button</label>
<button id="foo-button">What do I do?</button>
</Thing>
이러면 Thing 컴포넌트 안의 something className에 스타일을 적용하는 것~
const Example = styled.button.attrs(props=>({
type: 'submit'}))`
~~스타일링~~
`;
render(
<>
<Example /> // => type이 submit인 button 태그
</>
);
이런거
const Input = styled.input.attrs(props => ({
type: "text",
size: props.size || "1em",
}))`
border: 2px solid palevioletred;
margin: ${props => props.size};
padding: ${props => props.size};
`;
//Input 상속받아 type만 password로 override
const PasswordInput = styled(Input).attrs({
type: "password",
})``;
render(
<>
<Input placeholder="A bigger text input" size="2em" />
<PasswordInput placeholder="A bigger password input" size="2em" />
</>
);
이런거
npm install --save styled-components
common.scss, reset.scss 대용으로 사용한다. CSS, SCSS를 사용할 때는 reset.css를 구글에서 긁어왔지만 Styled Component는 아예 제공하고 있다.
npm install --save styled-reset
으로 설치하고 GlobalStyles.js에서 import해서 다음과 같이 쓰면 됨.
import { createGlobalStyle } from 'styled-components';
import reset from 'styled-reset';
const GlobalStyles = createGlobalStyle`
${reset};
~~따로 설정하고 싶은 Common.scss를 적으면 됨~~
`;
export default GlobalStyles;
variables.scss 대용으로 사용한다. ThemeProvider를 통해 컴포넌트들에 전달되고, 사용한다. 더 잘 사용하는 방법이 있을 거 같은데 일단 모르겠다...
const calcRem = pxSize => `${pxSize / 16}rem`;
const flexSet = (just = 'center', align = 'center') => {
return `display: flex;
justify-content: ${just};
align-items: ${align};`;
};
const flexColumnSet = (just = 'center', align = 'center') => {
return `display: flex;
flex-direction: column;
justify-content: ${just};
align-items: ${align};`;
};
const colors = {
red: '#f26462',
black: 'rgb(61, 61, 61)',
primaryGray: '#3f4150',
secondaryGray: '#8c8d96',
tertiaryGray: '#b2b3b9',
border: '#EFEFEF',
selected: '#f2f2f2',
bgGray: '#f6f5f5',
};
const theme = {
colors,
calcRem,
flexSet,
flexColumnSet,
};
export default theme;
css, scss의 variables 파일처럼 자주 쓰는 컬러값들을 저장할 수 있당. 사용할 때는 theme을 props로 받아서 다음과 같이 사용한다.
px단위에 익숙하지만 반응형에 대비해 rem 단위로 작업할 건데 매번 px => rem 계산하는 귀찮음을 덜기 위해 calcRem 함수를 작성했다. 아주 좋은거 알았다 ~!
sass를 사용하면서 flex set을 Mixin으로 아주 잘 썼는데 스타일컴포넌트에서는 어떻게 쓰는지 몰라서 하루종일 삽질함 ༼;´༎ຶ ༎ຶ༽
일단 저렇게 theme안에 선언하고 아래와 같이 사용하면 아주 잘 적용된다.
저 theme.js는 다음과 같이 사용할 곳에서 props로 받아 사용하면 된다.
import React from 'react';
import styled from 'styled-components';
function Main() {
return (
<>
<CenterContainer>
<div>1</div>
<div>2</div>
<div>3</div>
</CenterContainer>
</>
);
}
const CenterContainer = styled.div`
${({ theme }) => theme.flexSet()}
font-size: ${({ theme }) => theme.calcRem(50)}
color: ${({ theme }) => theme.colors.red}
`;
export default Main;
// index.js에 요 셋을 import 시켜준다
import GlobalStyle from './styles/GlobalStyle';
import { ThemeProvider } from 'styled-components';
import Theme from './styles/Theme';
// 아래와 같이 작성한다
ReactDOM.render(
<>
<GlobalStyle />
<ThemeProvider theme={Theme}>
<Routes />
</ThemeProvider>
</>,
document.getElementById('root')
);
이러면 Router.js에서 return해주는 컴포넌트들에 전역으로 스타일 속성을 사용할 수 있게 함.
이전에 component들의 depth가 깊어지면서 depth가 너무 깊어져도 계속 props로 넘기고 넘기고 넘기며 사용하나? 하는 생각이 들어서 증조할아버지가 가진 props를 증손주에게 바로 직빵으로 쏴주는 방법 (props drilling)이 없는지 알아볼 때 Context API에 대해 들어본 적 있는데 ThemeProvider의 작동 방식도 그거라고 한다.
간단히만 이야기하자면 전역으로 상태를 사용할 수 있는 영역인 Context를 Provider를 이용해서 지정하는 것이다. Provider로 감싸진 컴포넌트들에서는 Context를 사용할 수 있음. ThemeProvider도 마찬가지이다.
ThemeProvider로 감싸진 자식 Component들은 ThemeProvider로 전달받은 theme를 props로 전달받아서 사용이 가능합니다.
이걸 의존성 주입이라고 한다고 함. Provider로 감싸진 애들이 Context를 주입 받아서 쓴다는 뜻인 것 같다(?). 처음 들었을 때 외계어 같았는데 어려우면 일단 뉘앙스만 이해하면 된다. 뉘앙스 자체는 위에서 계속 이야기했던 것과 똑같다 ! 결국 theme.어쩌고~ 속성들은 각 컴포넌트에 종속된 속성이 아니라 Theme이라는 별도의 공간에 종속된,Theme이라는 공간에 의존하는 것이기 때문에 의존성 주입이라고 이름이 붙여졌다고(?)