<Btn bgColor="green">Click me</Btn>
<Btn as="a" href="/"><Btn>
as
키워드로 해당 Styled Components 의 HTML tag 자체를 바꿀 수 있다.
const Input = styled.input.attrs({required: true})`
background: ${(props) => props.bgColor};
`;
attrs
키워드로 해당 HTML 태그의 속성을 설정해줄 수 있다.
const animation = keyframes`
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
`
const Box = styled.div`
background: ${(props) => props.bgColor};
width: 200px;
height: 200px;
animation: ${animation} 2s linear infinite;
`;
animation 속성을 keyframs 키워드를 사용해 정의해주고 styled Components 내부에서 할당하여 사용할 수 있다.
const Box = styled.div`
background: ${(props) => props.bgColor};
width: 200px;
height: 200px;
span {
font-size: 36px;
&:hover {
font-size: 50px;
}
}
`;
Styled Components 의 자식 elements 가 있다면
컴포넌트를 정의할 때 해당 elements를 Pseudo Seletor 로 선택하여 속성을 지정할 수 있다.
const Box = styled.div`
background: ${(props) => props.bgColor};
width: 200px;
height: 200px;
${Emoji} {
font-size: 36px;
&:hover {
font-size: 50px;
}
}
`;
정의된 Styled Components 의 자식 elements가 또다른 Styled Components라면
${} 내부에 컴포넌트를 명시해주는 것으로 해당 컴포넌트를 가상 선택자로 선택할 수 있다.
// index.js
import {ThemeProvider} from 'styled-components';
const darkTheme = {
bgColor: "black",
color: "white",
};
const lightTheme = {
bgColor: "white",
color: "black",
};
ReactDom.render(
<ThemeProvider theme={lightTheme}>
<App />
</ThemeProvider>
)
ThemeProvider 기능을 이용해 전역으로 관리하는 theme 을 관리할 수 있다.
Provider 내부의 컴포넌트는 모두 theme 을 참조하게 되므로 공통된 속성으로 관리할 수 있다.
Dark & Light Mode 를 만들때도 유리하다.
Mode change 를 위해서는 같은 이름의 속성을 가지고 있어야 한다.
JavaScript 는 property의 데이터 타입이 무엇인지 전혀 신경쓰지 않는다.
const plus = (a,b) => a+b;
plus(2,2) // 4 🥰
plus(2,'hi') // '2hi' 🥺
TypeScript 는 위의 함수가 실행되기 전에 미리 개발자의 실수를 예측하고 에러를 띄워준다.
const plus = (a:number,b:number) => a+b;
plus(2,2) // 4 🥰
plus(2,'hi') // error : Argument of type 'string' is not assignable 🥰
Protection 기능은 코드가 실행되기 ‘전’에 실행된다.
import Styled from 'styled-components'
styled-components 는 js를 기반으로 만들어졌기 때문에 typescript 가 이해할 수 없다.
따라서,
npm i @types/styled-components
@types/styled-components 은 해당 라이브러리의 type definition 을 저장하고 있다.
DefinitelyTyped
커뮤니티에서 정말 수많은 개발자가 열심히 Type 을 깎아놓는다고 한다. 🥰
Prop Types 는 코드의 실행 '후'에 type을 체크
TypeScript 는 코드의 실행 '전'에 type을 체크
interface CircleProps {
bgColor: string;
}
type에 대한 object 를 정의한다.
사용할 때는,
function Circle({bgColor}:CircleProps){
...
}
이런식으로 구조분해하여 사용할 수 있다.
interface PlayerShape{
name:string;
age:number;
}
const sayHello = (playerObj: PlayerShape) =>
`Hello ${playerObj.name} you are ${playerObj.age} years old`
sayHello({name:'soo', age:12})
object 의 shape을 확인한다.
💡 default props, optional propsinterface ContainerProps {
bgColor: string;
borderColor?: string;
// === borderColor : string | undefined
}
? 키워드를 사용해 해당 props를 포함하지 않아도 에러가 나지 않도록 설정해줄 수 있다.
<container bgColor={bgColor} borderColor={borderColor ?? bgColor}>
default props 를 설정해주는 것으로도 (undefined시 bgColor 종속) 설정이 가능하다.
💡 Stateconst [counter, setCounter] = useState(1);
setCounter("2"); // error : argument of type 'string' is not assignable to parameter of type
우리 친구 typescript 는 정말 똑똑해서
state의 초기값을 number 로 설정해놓으면 setAction 의 인자로 number 자료형만 받을 수 있게
보호해준다.
둘 다 사용하고 싶다면
const [value, setValue] = useState<number|string>(0);
이런식으로 typescript 에게 알려주어야 한다.
const [name, setName] = useState("");
const nameChangeHandler = (event: React.FormEvent<HTMLInputElement>) => {
setName(event.currentTarget.value);
const {
currentTarget: { value },
} = event;
setName(value);
};
const submitHandler = (event: React.FormEvent<HTMLFormElement>) => {
event.preventDefault();
console.log(name);
};
또한 우리의 까칠한 typescript는
form event 의 event 마저도 type을 명시해주어야 한다.
해당 event 는 react의 formevent의 HTMLInputElement 의 event 라고 명시.
💡 d.ts (declarations file)typescript 코드의 타입 추론을 돕는 파일.
전역 변수로 선언한 변수를 import 구문 없이 사용하는 경우
(예를들어 위의 theme provider로 사용할 props.theme.~)
해당 병수를 typescript가 인식할 수 없다.
따라서 declare 키워드로 전역에서 사용한다는 것을 명시해주어야 한다.
import "styled-components";
declare module "styled-components" {
export interface DefaultTheme {
textColor: string;
bgColor: string;
btnColor: string;
}
}
til에 결론이라고 할 것 까지는 없지만..
오랜만에 다시 강의들으면서 공부하니까 재밌는 것 같기도 하고
실전프로젝트에 도입할 기술에 관한 문제가 계속 화두됐었다.
물론 처음에 프론트엔드 팀장분께서
'다른 조들은 이러이러한 기술을 쓴다더라~'
라는 말을 듣고 솔직하게 부정적인 의문이 들었다.
프로젝트에 어떤 라이브러리나 프레임워크를 도입할 때,
그 이유가 단지 '조금 더 쉬워서' 혹은 '남들이 하니까' 뿐이라면
오히려 새로운 공부를 할 시간에 있는 코드에 대해서 조금 더 고민하는게 나을지도 모른다고 생각했다.
심지어 실전프로젝트는 기술면접이나 발표도 하게될텐데
몇년차 선배 개발자분들이 아니더라도 기술을 도입한 '급조된 이유' 정도는 누구라도 알 수 있다.
그런데 사실..
새로운 배움에 대한 욕심도 많고 타입스크립트나 리액트쿼리, 리코일 같은 기술들은
나도 정말 사용해보고 싶었다.
그도 그럴게
어제만 해도 캔버스에 들어가는 brushWidth 값이 이상해서 그림이 제대로 그려지지 않았는데,
해당 값이 number가 아니라 string으로 들어가고 있다는 사실을 자그마치 세시간이나 넘게 씨름했기 때문.
리코일 같은 경우에는 '가장 react스러운 전역상태관리 도구' 라는 평이 자자하고,
'리액트 쿼리를 사용하고는 그동안 thunk로 작업하던 암이 다 나았습니다!' 라는 말도 들어봤고
그걸 다 떠나서, 새로운 배움에 대한 욕심이 정말 컸다.
하지만 이건 말 그대로 욕심이고,
실전프로젝트는 그동안 배운 기술들을 녹여넣어서 멋진 작품을 만들어내는 것이 목표라고 할 수 있겠다.
감정을 제외하고 현실적으로 판단했을 때,
급조된 기술로 오히려 프로젝트의 퀄리티만 떨어질 수도 있겠다는 걱정을 지울 수 없었다.
그래서 팀 내에서 나온 이야기는,
마침 노마드코더에 해당 기술들을 모두 사용하는 강의가 있으니
공부도 할 겸 실제로 겪어보고 판단하자고 논의가 됐다.
단, 시간이 그렇게 많지 않으므로 다음주 월요일 저녁회의시간까지 다 듣고오기로 했다.
아주 멋진 이야기가 아닐 수 없었다.
새로운 기술에 대한 사리사욕(이라고 하면 조금 어감이 이상하긴 하지만)도 채우고,
팀 프로젝트 기술도입에 대한 서로간의 의견도 나누어 볼 수 있으니까.
누구라고 할 것 없이 만장일치로 결정됐다.
경험상,
강의 시간이 17시간이라고 해서 진짜로 17시간밖에 안걸렸던 적이 단 한번도 없으므로,
적어도 30시간은 잡고 강의를 봐야한다.
부지런히 해야 닿을 수 있으리라.