11.14.2024(목) TIL
1. 새롭게 배운 점은? (Learned)
"프론트엔드는 클린 코드보다 중요한 게 정확한 기능구현과 정확한 퍼블리싱" 라는 강사님 말씀이 인상깊었습니다. 그래서 오늘은 보다 정확한 퍼블리싱을 구현하도록 고민하고 시멘틱 태그를 다시 한 번 고민을 하는 시간을 가졌어요. 더 나아가서는 테일윈드 css 와 grid로 코드짜는 것에 익숙해지는 시간을 가졌습니다. 아래 내용은 새롭게 안 내용과 고민입니다.
분석과 고민
1. search-bar.tsx 파일 분석
1-1. 조건부 렌더를 쉽게 작성하려고 만든 cn 유틸 함수
search-bar는 내부적으로 cn함수를 사용하는 데 살펴보니 utils 폴더 내부에 있는 사용자 정의함수이고 이는 조건부 렌더를 쉽게 작성하기 위해 만든 함수라고 합니다.
//utils>index.ts
import { clsx, type ClassValue } from 'clsx';
import { twMerge } from 'tailwind-merge';
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs));
}
1-1-1. clsx 라이브러리
clsx 라이브러리는 클래스명 문자열을 조건부로 구성하기 위한 작은 유틸리티입니다. 스타일을 여러 조건부로 나눠 처리하고 싶을 때 조건식을 객체화시켜서 사용하는 방식이네요.
function Button () {
const [isClick,setIsClick] =useState(false);
const handleClick = () =>{
setIsClick(!isClick);
}
return(
<button
onClick={handleClick}
className = {clsx(`w-full h-5 `,{'bg-red-200': isClick})}
>
</button>
)
}
1-1-2. tailwind-merge 라이브러리
tailwind-merge 라이브러리는 "스타일 충돌 없이 JS에서 Tailwind CSS 클래스를 효율적으로 병합하는 유틸리티"입니다. 여기서 중요한 점이 CSS 캐스케이딩(cascading:스타일 규칙 및 선언이 어떻게 적용되는지에 대한 규칙 및 우선 순위를 정의하는 프로세스)라는 개념인데 className 에 들어가는 클래스명의 순서는 의미가 없다는 점입니다. 만약 " default style이 p-4(padding:8px)인 버튼 컴포넌트를 특정 케이스에만 p-2 로 바꾸고 싶다" 라고 가정해봅시다. 그러면 className 에 p-4가 있는 상태에서 p-2 를 추가로 넣으면 p-2 는 무시되기 때문에 기존 p-4 클래스를 삭제하고 p-2를 넣어야하는 조건부 렌더링을 해야 한다는 것입니다. 어제 테일윈드를 쓰다가 해당 내용을 몰라 어 이게 왜 동작을 안하지 싶었는 데 이해되는 순간이네요.(야호)
이러한 이유 때문에 테일윈드로 스타일 분기처리를 하려면 덮어 쓸 수 없고 조건부 렌더링을 해야하는 데 tailwind-merge 에 twMerge 함수를 사용하면 충돌하는 클래스들을 같이 써도 원하는 데로 덮어쓸 수 있다는 것입니다.
1-2. forwardRef
forwardRef()를 호출하면 컴포넌트가 ref를 받아 하위 컴포넌트로 전달합니다. forwardRef 는 jsx 에서 렌더링할 수 있는 React 컴포넌트를 반환하고 일반함수로 정의된 React 컴포넌트와 다르게 forwardRef가 반환하는 컴포넌트는 ref props도 받을 수 있다고 하네요.
import { forwardRef } from 'react';
const MyInput = forwardRef(function MyInput(props, ref) {
// ...
});
forwarRef는 해당 컴포넌트가 ref.를 사용하여 부모 컴포넌트의 DOM 노드를 노출할 수 있습니다. 말이 좀 어려운데요. 아래 코드를 보니 이해가 됐습니다. 아하 외부 컴포넌트 동작에 의해 특정 컴포넌트 동작(input)을 활성화 되게 하려고 이 두 컴포넌트의 부모단에서 제어하는 구조로 사용되는 구나! 이해되는 순간이였어요.
function Form() {
const ref = useRef(null);
function handleClick() {
ref.current.focus();
}
return (
<form>
<MyInput label="Enter your name:" ref={ref} />
<button type="button" onClick={handleClick}>
Edit
</button>
</form>
);
}
2. width 값이 일정한 형제요소가 있고 나머지 width 값을 전부 차지해야하는 컴포넌트가 있을 때 height 값은 어떻게 줘야 할까?
-> [ 해결 ] 부모요소에 flex 속성을 주고 해당 태그에 flex-1 를 주면 나머지 영역 전체를 차지하게 됩니다. 또 형제요소의 너비값을 상수 변수로 만든 후 부모요소 너비 100%에 형제요소 너비값을 빼주면 됩니다.
더 나아가 테일윈드에서 calc 를 사용하는 방법은 w-[calc(100%-30px)] 이렇게 사용할 수 있습니다. 중간에 공백 넣으니 스타일이 먹지 않네요.
새롭게 안 내용
0. export 경로 묶기 컴포넌트 파일에 index.tsx 파일을 만들고 export 를 묶어주면 외부에서 컴포넌트들을 import 할때 코드 양을 줄일 수 있다.
1. @ 를 사용해 특정 경로를 별칭으로 정의해 편리하게 import 할 수 있다.
-> [ 더 알아보기 ] 해당 기능은 Path Aliasing 이라고 합니다. Path Aliasing 는 프로젝트 내에서 특정 경로를 별칭( alias )으로 정의하여 import 할 수 있도록 하는 기능 입니다.
2. 테일윈드 css 에서 h-20 는 height가 20*4 = 80px -> 숫자가 있다면 *4 하면 px 값을 예상할 수 있다.
3. 시맨틱 테그는 원칙적으로 영역을 꽉차게 잡는 다.
4. css 네이밍 규칙 중 .page__container 처럼 작성하면 scss 작성시 장점이 있다. html을 해당 파일처럼 작성한다면 scss 로 아래와 같이 스타일링 할 수 있다. 단 뎁스가 3개를 넘어가면 가독성이 떨어지니 뎁스가 깊어진다면 다른 클래스 명으로 작성하는 게 바람직하다.
또한 _fonts.scss 처럼 scss 파일 앞에 _ 가 있다면 빌드시 css 로 변환할 필요없는 파일이란 것을 의미한다. 요새 css 가 scss 문법을 기본적으로 통합하고 있어서 알고만 있으면 좋을 것같아요.
<div class="page">
<div class="page__container">
<div class="page__container_wrapper">
<div class="card">
<div class="card__wrapper">
</div>
</div>
</div>
</div>
</div>
2. 앞으로 뭘 더 하면 좋을까? (Longed for)
타입스크립트를 좀 더 연습하는 시간을 갖고 지금처럼 당일 새롭게 알게 된 부분들을 정리하고 또 혼자 더 나아가서 찾아보고 공부하는 시간을 유지해야겠습니다.