Styled Components 와 ReactJS
Styled Components의 설정값을 변경하여 확장하여 사용하기
- 다크 모드, 라이트 모드 구현을 쉽게 도와줍니다.
-
- global.css (전역적으로 모든 페이지에 기본적으로 적용되는 CSS)
- 인라인 스타일 (html마크업의 style속성으로 직접 코딩하는 CSS)
- fileName-module.css (CSS모듈로 만들어서 해당 페이지에만 적용)
- 모듈형태는 className을 마치 오브젝트의 속성처럼 사용합니다.
- ex) <div className={styles.title}></div>
👉 모듈형태로 사용하는것이 가장 편리합니다.
- CSS 모듈 방식은 className을 랜덤하게 만들어줘서, className이 서로 충돌하지 않습니다.
...ReactJS에서 style을 작업하는 최선의 방법은 Styled-Components
입니다.
- 콘솔창에서 styled-components를 설치하고
- package.json에서 dependencies에 추가되었는지 확인합니다.
npm i styled-components
- html 마크업의 style속성에 작성합니다,
- 작성 후, 바로 이해하기 쉽고 별도 CSS파일 생성이 필요하지 않습니다.
👉 괄호를 열고 JS코드방식으로 작성해야하며, 때문에 직관적이지 않습니다.
같은 태그를 사용하면, CSS를 살펴보지 않고는 각각의 컴포넌트의 역할을 파악할 수 없습니다.
function App() {
return (
<div style={{ display: "flex" }}>
<div style={{ backgroundColor: "teal", width: 100, height: 100 }}></div>
<div style={{ backgroundColor: "tomato", width: 100, height: 100 }}></div>
</div>
);
}
export default App;
- 모든 스타일은 컴포넌트를 사용하기 전에 미리 컴포넌트에 포함시킬 수 있습니다.
- CSS 코드를 CSS 방식 그대로 사용할 수 있고,
- 작성된 컴포넌트를 보면 직관적으로 구별할 수 있습니다.
- 클래스이름이 자동으로 랜덤 텍스트로 부여됩니다.
- 클래스이름을 개발자가 만들 필요가 없습니다.
- html마크업 속성으로 style을 작성할 필요가 없습니다.
- 유효한 html태그 이름을 사용해야하며, 백틱(``) 사이에는 CSS 코드가 작성됩니다.
- 컴포넌트 끼리 공통요소가 많고, 다른부분이 적다면 중복되는 코드를 줄일 수 있습니다.
- 컴포넌트의 전체적인 영역을 style과 구현부로 나눌 수 있습니다.
- styled-components를 활용하며, 구현부 가독성이 높아졌습니다.
import styled from "styled-components";
const Fater = styled.div`
display:flex;
`;
const BoxOne = styled.div`
background-color: tomato;
width: 100px;
height: 100px;
`;
const BoxTwo = styled.div`
background-color: teal;
width: 100px;
height: 100px;
`;
const Text = styled.span`
font-weight: bold;
color:#ffffff;
font-size:30px;
`;
Function App(){
return (
<Father>
<BoxOne>
<Text>Box1</Text>
</BoxOne>
<BoxTwo>
<Text>Box2</Text>
</BoxTwo>
</Father>
);
}
export default App;
- 특정 값을 제외하고 다른 스타일이 모두 같아 중복되는 컴포넌트 작업하기
- BoxOne과 BoxTwo는 텍스트의 컬러값만 제외하고 모두 스타일이 같습니다.
- 컴포넌트에서 color값을 결정하는 것이 아닌, Props를 사용하여 Box의 설정값에서 설정합니다.
- props란 컴포넌트에 데이터를 보내는 방식을 말합니다.
- props의 이름을 작성합니다. props의 네이밍은 어느것이든 가능합니다.
- 이름을 정한 props에 값을 부여하면 prop를 보내는 작업이 완료됩니다.
- props라는 파라미터를 받는 함수를 스타일에서 적어줍니다.
- 커스텀 props를 스타일에 사용하면 styled-components가 자동으로
- className을 작성하고 style을 분류합니다.
- props를 이용하여 컴포넌트 설정이 가능합니다.
- props는 컴포넌트에 데이터를 보내는 방법입니다.
- 또한 이것이 styled-components에서 props를 받고 사용하는 방법입니다.
- props를 통해 컴포넌트를 설정하는 방법
import styled from "styled-components";
const Fater = styled.div`
display:flex;
`;
const Box = styled.div`
background-color: ${props => props.bgColor};
width: 100px;
height: 100px;
`;
Function App(){
return (
<Father>
<Box bgColor="tomato"/>
<Box bgColor="teal"/>
</Father>
);
}
export default App;
- 기존 컴포넌트의 모든 것들을 가져와 새로운 것들을 더하는 방식입니다.
- 중복되는 코드를 축소합니다.
- 컴포넌트를 확장하여 사용해야하는 이유는 중복되는 코드를 최소화하기 위함입니다.
- 특정 컴포넌트를 기존 컴포넌트에 더하는 방식입니다.
- Box의 모든 속성들을 들고 온 다음, 추가로 더할 코드에 합칩니다.
- "const circle = styled(Box)" 형식으로 기존 컴포넌트를(Box) 가져와서 더합니다.
- 괄호 안에 더하고 싶은 기존 컴포넌트를 넣어 확장시킵니다.
import styled from "styled-components";
const Fater = styled.div`
display:flex;
`;
const Box = styled.div`
background-color: ${props => props.bgColor};
width: 100px;
height: 100px;
`;
const circle = styled(Box)`
border-radius:50%;
`;
Function App(){
return (
<Father>
<Box bgColor="tomato"/>
<Circle bgColor="green"/>
</Father>
);
}
export default App;
- 컴포넌트의 태그는 바꾸고싶은데, 스타일은 변경하고 싶지 않은 경우 작업하기
- "const Link = styled(Btn)" 방식은 같은 컴포넌트를 사용하는 것이 아니라,
- 기존 스타일을 확장하는 방법입니다.
- <Btn as="a">Link</Btn> "as" props를 사용하여 스타일은 그대로 유지하고,
- 태그의 종류만 변경하여 재사용합니다.
- "as" props를 사용해서 태그의 종류를 button에서 a로 바꾸면
- 그 태그의 속성도 사용할 수 있습니다. (href="" 사용가능)
- 스타일을 추가할 계획이 없고 컴포넌트를 확장시키고 싶지 않을때,
- 태그의 종료만 변경할때, 사용합니다.
import styled from "styled-components";
const Fater = styled.div`
display:flex;
`;
const Btn = styled.button`
color: #ffffff;
background-color: pink;
border:0;
border-radius: 15px;
`;
Function App(){
return (
<Father>
<Btn>Login</Btn>
<Btn as="a" href="/">Link</Btn>
</Father>
);
}
export default App;
- html의 속성값을 설정할 수 있게 해줍니다.
- const Input = styled.input.attrs({ required:true })
- attrs로 html태그의 속성의 프로퍼티를 설정할 수 있습니다.
- const Input = styled.input.attrs({required:true, maxLength=4})
- 객체 안에 복수를 설정할 수 있습니다.
- 스타일뿐만 아니라 html속성 설정까지 컴포넌트로 작업하여 재사용이 가능합니다.
import styled from "styled-components";
const Fater = styled.div`
display:flex;
`;
const Input = styled.input.attrs({ required:true, maxLength=4 })`
border:0;
background-color:lightgray;
`;
Function App(){
return (
<Father>
<Input />
</Father>
);
}
export default App;
- helper function(keyframes)를 import합니다.
- animation에 대한 정의를하고 사용할 컴포넌트에 animation으로 변수 호출을 합니다.
- keyframes+백틱 내부에는 일반 css애니메이션 속성을 작성합니다.
- animation 정의 영역에 변수를 작성할때,
- JS의 string interpolation을 사용합니다. ${variable}
import styled, {keyframes} from "styled-components";
const rotateAnimation = keyframes`
0% {
transform:rotate(0deg);
border-radius:0%;
}
50% {
transfrom:rotate(360deg);
border-radius:50%
}
100% {
transform:rotate(0deg);
border-radius:0%;
}
`;
const Wrapper = styled.div`
display:flex;
`;
const Box = styled.div`
width:100px;
height:100px;
background-color:tomato;
animation:${rotateAnimation} 10s linear infinite;
`;
Function App(){
return (
<Wrapper>
<Box>
<span></span>
</Box>
</Wrapper>
);
}
export default App;
- 컴포넌트에서 selector를 하나 더 사용하는 방법이 있습니다.
- 컴포넌트 내부에 있는 styled-components가 아닌 요소를 타겟하는 방법
- Box style내부에 span에 대한 CSS를 작성합니다.
- 컴포넌트의 하위요소중 styled-component가 아닌것은 style내부에서
- 타겟하여 스타일을 작성할 수 있습니다.
- 모든 요소를 styled-component화 할 필요는 없지만, 대신 컴포넌트만
- styled-components 스타일처리를 하고, 다른것은 target처리 가능합니다.
import styled, {keyframes} from "styled-components";
const rotateAnimation = keyframes`
0% {
transform:rotate(0deg);
border-radius:0%;
}
50% {
transfrom:rotate(360deg);
border-radius:50%
}
100% {
transform:rotate(0deg);
border-radius:0%;
}
`;
const Wrapper = styled.div`
display:flex;
`;
const Box = styled.div`
width:100px;
height:100px;
background-color:tomato;
animation:${rotateAnimation} 10s linear infinite;
span {
font-size:60px;
}
`;
Function App(){
return (
<Wrapper>
<Box>
<span>🤔</span>
</Box>
</Wrapper>
);
}
export default App;
- styled-component "안에" 있는 것을 select하도록 도와줍니다.
- 함축된(encapsulated) 표현으로 빠르게 작업할 수 있습니다.
- ^ 나 & 처리를 해줄 수 있습니다. ex) &:hover (=pseudo selector)
- span 내부에 &hover: 와 span:hover 는 같은 기능을 합니다.
- &란 span을 호명하는 것과 같습니다. 단축키와 같아서, 더 빨리 사용할 수 있습니다.
- 마우스를 클릭하고 있는 상태가 active, 아닌상태가 inactive입니다.
- 이 방법은 tag name에 의존하고 있으므로 변경되면 적용되지 않습니다.
- tag name에 의존하고싶지 않다면, styled-component를 적용해야합니다.
const Box = styled.div`
width:100px;
height:100px;
background-color:tomato;
animation:${rotateAnimation} 10s linear infinite;
span {
font-size:60px;
&:hover {
font-size:20px;
}
&:active {
opacity:0;
}
}
/* span:hover {
font-size:20px;
}
span:active {
opacity:0;
}*/
`;
- styled-components안의 element를 선택하는 다른 방법입니다.
- 컴포넌트 안에 또 컴포넌트를 적용할 수 있습니다.
- tag name에 의존하지 않고 컴포넌트 하위 엘리먼트를 타겟팅하기위해서는,
- ${Emoji}처럼 string interpolation안에 변수를 넣습니다.
- 하위 요소를 컴포넌트 변수화하여 넣으면, tag name이 변해도 그대로 스타일이 유지됩니다.
const Emoji = styled.span`
font-size:100px;
`;
const Box = styled.div`
width:100px;
height:100px;
background-color:tomato;
animation:${rotateAnimation} 10s linear infinite;
${Emoji}{
&:hover {
font-size:20px;
}
}
/* ${Emoji}:hover {
font-size:20px;
} */
`;
Function App(){
return (
<Wrapper>
<Box>
<Emoji>🤔</Emoji>
</Box>
</Wrapper>
);
}
export default App;
- themes는 앱이 light/dark 모드를 가지게 해줍니다.
- styled-component의 Theme & Local Estate Management를
- 합쳐서 다크모드를 구현합니다.
- theme이란, 기본적으로 모든 색상들을 가지고 있는 object입니다.
- 색상을 하나의 객체에 모두 넣어놨기때문에 매우 유용합니다.
- ThemeProvider라는 것을 styled-components로부터 import합니다.
- ThemeProvider는 theme이라는 props가 필요합니다.
- darkmode와 lightmode에 대한 스타일 객체를 정의합니다.
- App.js가 ThemeProvider내부에 있기때문에 필요하면
- App.js안에서 해당 객체에 접근할 수 있습니다.
- ThemeProvider에서 가져온 색들 중 구체적인 색상을 정하고,
- ThemeProvider에 둘러싸인 모든 컴포넌트는 theme의 데이터에 접근할 수 있습니다.
- theme을 2가지 이상 만들고, 서로 같은 프로퍼티 이름을 가져야합니다.
- darkmode에서 lighttheme으로 변경해줄때 같은 프로퍼티가 필요합니다.
- 오직 theme에 대한 레퍼런스만 가질 뿐, 색상에 대한 언급은 작성하지 않습니다.
- theme의 색상은 변경되었지만 다른 컴포넌트에는 변화가 없습니다.
- 하나만 변경해도 전부 자동으로 변경됩니다.
- 프로퍼티를 몇가지 가진 theme객체만 정의되면 됩니다.
- 그 객체를 ThemeProvider에게 전달합니다.
- 그러면 ThemeProvider내부에 있는 모든 컴포넌트에서 theme오브젝트에 접근할 수 있게됩니다.
- 2개의 theme객체를 만들고, 서로 동일한 프로퍼티 이름을 갖고있으면 됩니다.
- light/dark mode를 작업하려면 서로 프로퍼티의 이름을 가져야합니다.
- 코드 하나만 바꿔주면 앱 전체에 변화가 생깁니다.
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import { ThemeProvider } from "styled-components";
const darkTheme = {
textColor: "whitesmoke",
bgColor: "#000000"
}
const lightTheme = {
textColor: "#000000",
bgColor: "whitesmoke"
}
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<ThemeProvider theme={darkTheme}>
<App />
</ThemeProvider>
</React.StrictMode>
);
mport styled from "styled-components";
const Wrapper = styled.div`
display: flex;
width:100vw;
height: 100vh;
justify-content: center;
align-items: center;
background-color: ${props => props.theme.bgColor};
`;
const Text = styled.div`
color:${props => props.theme.textColor};
font-size:100px;
font-weight:bold;
`;
function App() {
return (
<Wrapper>
<Text>Hello :)</Text>
</Wrapper>
);
}
export default App;