🔍 Custom Component 란?
React에서 Custom component란, 개발자가 직접 작성하여 재사용할 수 있는 컴포넌트를 의미합니다. 이러한 컴포넌트는 보통 JSX로 작성되며, 부모 컴포넌트로부터 전달된 프로퍼티를 이용해 데이터를 받아 렌더링합니다. 컴포넌트를 만들어 다른 컴포넌트에서 여러번 사용할 수 있고, 이는 애플리케이션의 유지보수성과 재사용성을 향상시키는 데 매우 유용합니다.
🔍 CDD 란?
Component Driven Development 의 약자로, 컴포넌트를 중심으로 개발하는 방법론을 말합니다. 이는 UI를 작은 단위로 쪼개어 개발하고, 각각의 컴포넌트를 독립적으로 개발 및 테스트하고, 이들을 다시 조합하여 큰 화면을 만드는 것을 중심으로 합니다.
CDD는 React와 같은 컴포넌트 기반 라이브러리나 프레임워크에서 특히 유용합니다. 컴포넌트 기반으로 개발하며 적용하면 애플리케이션의 유지보수성과 재사용성을 높이고, 더 나은 품질의 코드를 작성할 수 있습니다.
🎀 CDD의 장점
- 모듈화 : 컴포넌트 단위로 개발하기 때문에 코드가 간결해지고 재사용성이 높아집니다.
- 빠른 피드백 : 컴포넌트 단위로 테스트하고 개발하기 때문에 개발자는 빠른 피드백을 받을 수 있습니다.
- 협업 : 각각의 컴포넌트를 독립적으로 개발하기 때문에 여러 개발자가 협업할 때 충돌이나 영향을 줄이는 것이 가능합니다.
- 품질 : 작은 단위로 테스트하고 개발하기 때문에 품질 관리가 수월해지며, 테스트의 범위를 줄여 더 효율적으로 테스트를 진행할 수 있습니다.
🔍 CSS in JS 란?
자바스크립트 코드 안에서 CSS를 작성하는 방식으로, 자바스크립트 객체를 사용해 스타일을 정의합니다. 이렇게 작성된 스타일 객체는 프레임워크에서 제공하는 컴포넌트와 함께 사용됩니다. React에서는 styled-components, Emotion 등의 라이브러리를 사용합니다.
🎀 CSS in JS 의 장점
- 스타일과 컴포넌트가 결합하여 있어서, 컴포넌트의 재사용성이 높아집니다.
- CSS 클래스 이름 충돌을 방지할 수 있습니다.
- 자바스크립트 코드와 스타일 코드가 함께 유지보수되기 때문에, 컴포넌트의 스타일을 쉽게 변경할 수 있습니다.
- 조건부 스타일링이 쉽고, CSS Prepocessor의 변수, 함수 등을 사용할 수 있어 생산성이 높아집니다.
프로젝트의 규모나 복잡도가 점점 커지고, 팀 구성원의 수도 많아짐에 따라 CSS를 작성하는데 일관된 패턴이 필요해졌습니다. 이러한 문제점들을 해결하기 위해 CSS 전처리기(CSS Preprocessor)라는 개념이 등장했습니다. CSS가 구조적으로 작성될 수 있게 도움을 주는 도구입니다.
🔍 CSS Preprocessor 이란?
CSS를 작성하기 위한 언어로, CSS의 기능을 확장하고 생산성을 높이기 위해 만들어졌습니다. CSS Preprocessor 에서는 변수, 함수, 믹스인 등의 기능을 제공해 CSS 코드의 재사용성과 유지보수성을 높이고, 코드의 중복을 줄여 효율성과 일관성을 높일 수 있습니다. 또한 개발자들 사이의 코드 스타일 차이나 팀에서의 표준화 문제를 해결할 수 있습니다.
하지만, CSS와의 호환성 문제가 발생할 수 있고, 새 문법과 기능을 배워아 하는 단점이 있습니다. 따라서 CSS Preprocessor은 생산성과 유지보수성을 높이는 유용한 도구이지만 프로젝트의 요구사항과 개밠환경을 고려해 사용해야 합니다.
CSS 전처리기 자체만으로는 웹 서버가 인지하지 못하므로 여기에 맞는 Compiler를 사용해야 하고, 컴파일을 하게 되면 실제로 우리가 사용하는 CSS 문서로 변환이 됩니다. 이를 통해 CSS 파일들을 잘 구조화할 수 있게 되었고, CSS 파일을 작게 분리할 수 있는 방법이 생겼습니다.
가장 유명한 CSS 전처리기로, CSS를 확장해 주는 스크립팅 언어입니다.
자바스크립트처럼 특정 속성의 값을 변수로 선언하여 필요한 곳에 선언된 변수를 적용할 수도 있고, 반복되는 코드를 한 번의 선언으로 여러 곳에서 재사용할 수 있도록 해 주는 등의 기능을 가졌습니다.
SASS는 SCSS 코드를 읽어 전처리한 다음 컴파일해서 전역 CSS 번들 파일을 만들어 주는 전처리기의 역할을 합니다. 하지만 CSS의 구조화를 해결해주는 대신 계층 구조를 만드는데 의지하고 CSS 용량이 커지는 단점이 생겼습니다.
🎀 SASS
- Sassy CSS의 약자로, CSS를 보다 효율적으로 작성할 수 있도록 도와주는 전처리기입니다. 기존의 CSS문법과 거의 동일하지만, 변수, 함수, 중첩 등의 기능이 추가된 CSS 확장 문법입니다.
$primary-color과 같은 형식으로 변수를 만들어, 여러 클래스의 색상을 일괄적으로 변경할 수 있습니다.- CSS와 함께 사용할 수 있으며, SCSS코드를 CSS로 컴파일하여 사용합니다. CSS와 유사한 문법을 가지고 있어 개발자들이 쉽게 적응할 수 있는 전처리기 중 하나입니다.
🎀 컴파일(Compile)
소스 코드를 한 프로그래밍 언어에서 다른 언어로 번역하는 과정을 말합니다. 컴파일러는 소스 코드를 받아서 해당 언어의 문법에 맞게 분석하고, 기계어나 바이트코드 등으로 변환해 실행 가능한 파일을 만듭니다. 컴파일은 소스 코드의 오류를 찾는 것뿐만 아니라, 소스 코드를 보다 효율적으로 실행 가능한 형태로 변환함으로써 소프트웨어의 성능과 안정성을 향상하는 역할을 합니다. 컴파일의 결과물은 일반적으로 실행가능한 파일이나 라이브러리 형태로 제공되며, 이를 통해 소프트웨어를 배포하고 실행할 수 있습니다.
SASS를 보완하기 위해 BEM, OOCSS, SAMCSS 같은 방법론이 대두되었고 각 장단점이 있지만, 모든 방법은 코드의 재사용, 코드의 간결화(유지 보수 용이), 코드의 확장성, 코드의 예측성을 지향합니다.
대표적인 CSS 방법론으로 BEM이 있습니다. Block, Element, Modifier로 구분하여 클래스 명을 작성하는 방법으로 각각 -, _로 구분합니다. 클래스 명은 BEM 방식의 이름을 여러 번 반복하여 재사용할 수 있도록 하며, 더 일관된 코딩구조를 만들어 줍니다.
하지만 여기에도 문제점은 있습니다. 클래스 명 선택자가 장황해지고 긴 클래스 명 때문에 마크업이 불필요하게 커지고, 재사용 시 모든 UI 컴포넌트를 명시적으로 확장해야 합니다. 또 SASS와 마찬가지로 진정한 캡슐화 개념이 없어서 개발자들이 유일한 클래스 명을 선택하는데 의존했습니다.
컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔고, CSS도 컴포넌트 영역으로 불러들이기 위해 탄생했습니다. 대표적으로 Styled-Component가 있습니다.
Styled-Compnent는 기능적 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공합니다.
🎀 CSS in JS 의 페이지 로드 속도
일반적으로 기존의 외부 CSS 파일과 비교해 다소 무거운 라이브러리를 사용하고, 페이지 로드 시 자바스크립트를 로드하고 실행해야 하므로 초기 로딩 시간이 더 오래 걸릴 수 있습니다.
그러나 상황에 따라 페이지 로딩 속도에 미치는 영향은 다릅니다. CSS 코드가 적을 경우 CSS in JS를 사용해 그 코드를 동적으로 생성할 수 있고, 사용자가 필요로 하는 코드만 로드되므로 초기 로딩 시간이 단축될 수도 있습니다.
CSS in JS는 성능 최적화를 위한 여러 가지 방법을 제공합니다. 일부 라이브러리는 사용하지 않는 스타일을 자동으로 제거하고, 렌더링 성능 최적화를 위해 스타일을 더욱 효율적인 방식으로 적용하므로써 페이지 로딩 속도를 향상시킬 수 있습니다.
따라서 페이지 로딩 속도는 상황에 따라 달라집니다.
🎀 CSS in JS 와 번들의 크기
일반적으로 CSS in JS 라이브러리를 사용하면 번들의 크기가 증가합니다. 추가적인 코드와 로직을 포함하기 때문입니다. 또 일부 라이브러리는 자체 CSS 해석기를 사용해 CSS 코드를 자바스크립트 객체로 변환하고, 이 객체를 사용해 스타일을 적용하는 과정에서 추가적인 처리가 들어가 번들의 크기가 커집니다.
하지만 이러한 크기의 증가는 일반적으로 미미한 편입니다. 대부분 CSS in JS 라이브러리를 사용해 작성하는 코드는 일반적인 CSS 코드보다 적은 용량을 차지하고 일반적으로 코드를 압축하고 최적화하는 기능을 제공해 번들 크기를 최소화할 수 있습니다.
즉, 번들 크기가 약간 증가할 수 있지만 일반적으로 무시할 수 있는 수준이고, 이를 상쇄할 이점이 더욱 많습니다.
🔍 Styled Components 란?
React 애플리케이션에서 컴포넌트 스타일링을 단순화하고 모듈화할 수 있도록 도와주는 라이브러리 입니다. Styled Components를 사용하면 JS 코드 안에서 CSS 스타일을 작성할 수 있으며, 클래스 이름 충돌 문제를 해결할 수 있습니다.
🎀 Styled Components 의 특징
1. CSS-in-JS : Styled Components는 JavaScript 파일 안에서 CSS 코드를 작성하는 것은 CSS in JS 개념에 해당합니다. 이를 통해 컴포넌트 스타일링과 관련된 JS와 CSS 코드를 한데 모아 관리할 수 있습니다.
2. 컴포넌트 단위 스타일링 : 스타일이 모둘화 되고, 컴포넌트 별로 스타일링을 적용할 수 있습니다. 이는 코드의 가독성과 유지보수성을 높일 수 있습니다.
3. 동적스타일링 : 동적으로 스타일을 변경하는 것이 가능합니다. 이는 React의 State나 Props 값을 활용해 컴포넌트의 스타일을 변경할 수 있습니다.
4. CSS 변수 : 변수를 사용해 공통적으로 사용되는 스타일 값들을 변수로 선언해 재사용이 가능한 스타일링을 구현할 수 있스빈다.
5. 테마 지원 : 어플리케이션 전반적인 스타일링을 일관성 있게 구현할 수 있습니다.
Styled Components는 CSS in JS 라는 개념이 대두되면서 나온 라이브러리로, 현재 가장 인기 있는 라이브러리입니다. CSS를 컴포넌트화 시켜주는 라이브러리로, 이를 사용해 CSS도 쉽게 JavaScript 안에 넣어주어 HTML + CSS + JS를 묶어 하나의 JS 파일 안에서 컴포넌트 단위로 개발할 수 있게 됩니다.
🎀 Styled Components 설치
npm install --save sytled-components- package.json에 다음 코드를 추가
{ "resolutions" : { "styeld-components" : "^5" }}import styeld from "styeld-components"로 불러와서 사용
const 컴포넌트명 = 으로 컴포넌트를 선언합니다. styled.태그를 할당하고 백틱(`)안에 CSS문법과 똑같이 스타일 속성을 작성해주면 컴포넌트가 만들어집니다. React 컴포넌트를 사용하듯 리턴문 안에 작성해주면 스타일이 적용된 컴포넌트가 렌더링됩니다.styled()에 재활용할 컴포넌트를 전달해 준 다음, 추가하고 싶은 스타일 속성을 작성합니다.${}을 사용해 Props를 인자로 받는 함수를 만들어 사용하면 됩니다.Props 로 조건부 렌더링하기
스타일을 조건부로 설정할 수 있습니다.
//EX
const Button = styled.button`
background : ${(props) => props.red ? "red" : "white"}
`; // 배경색을 받아온 값이 레드면 레드로, 아니면 화이트로 지정해주는 코드
Props 값으로 렌더링하기
const Button = styled.button`
backgroun : ${(props) => props.color ? props.color : "white"}
`; // props.color 유무에 따라 있으면 그대로 값을 가져와 리턴해주고 아니면 화이트로 지정하는 코드
꼭 삼항연산자를 사용해야 하는 것은 아니고 JS 코드라면 무엇이든 가능합니다.
// 우선 `createGlobalStyle` 함수를 불러옵니다.
import { createGlobalStyle } from "styled-components"
//불러온 함수를 사용해 설정해주고 싶은 스타일을 작성합니다.
const GlobalStyle = createGlobalStyle`
button {
padding : 5px;
margin : 2px;
}
`
//만든 <GlobalStyle> 컴포넌트를 최상위 컴포넌트에서 사용해줍니다.
function App() {
return (
<>
<GlobalStyle />
<Button> 전역버튼 </Button>
</>
);
}
CDD를 지원하는 도구로 Component Explorer(컴포넌트 탐색기)가 등장했고, 다양한 UI 개발도구 중 하나가 StoryBook 입니다.
🔍 StoryBook 이란?
UI 개발을 위한 오픈소스 도구로, React, Vue, Angular 등의 프레임워크를 사용하는 프론트엔드 개발자들에게 많이 사용되는 도구 중 하나입니다. StoryBook 을 사용하면 개발자들은 컴포넌트의 개별적인 기능과 UI 디자인을 독립적으로 개발할 수 있습니다. 이는 개발자들이 컴포넌트를 개발할 때, 디자인, 레이아웃, 로직 등을 모두 동시에 고려해야 하는 번거로움을 줄여줍니다.
StoryBook은 다양한 스토리북 컴포넌트를 구성하여 구성요소의 시각적 모습 및 동작을 문서화할 수 있습니다. 다른 개발자나 디자이너들이 컴포넌트를 이해하고 사용할 수 있도록 도와줍니다. 또한 다양한 애드온과 확장성이 뛰어나기 때문에, 다양한 개발 프로세스에 맞추어 사용할 수 있습니다. 마지막으로 오픈소스 도구로 다양한 커뮤니티에서 사용자들의 피드백과 기여를 받으므로, 지속적인 개선과 발전이 이루어지고 있어 더 나은 UI 개발경험을 돕습니다.
각각의 컴포넌트들을 따로 볼 수 있게 구성해주어 한번에 하나의 컴포넌트에서 작업할 수 있어 전체 UI를 한 눈에 보고 개발할 수 있습니다.
StoryBook은 재사용성을 확대하기 위해 컴포넌트를 문서화하고, 자동으로 컴포넌트를 시각화하여 시뮬레이션할 수 있는 다양한 테스트 상태를 확인할 수 있습니다. 사전에 버그를 방지하도록 도와주고 테스트 및 개발 속도를 향상시키는 장점이 있고, 애플리케이션 또한 의존성을 걱정하지 않고 빌드할 수 있습니다.
StoryBook은 기본적으로 독립적인 개발환경에서 실행됩니다. 애플리케이션의 다양한 상황에 구애받지 않고 UI컴포넌트를 집중적으로 개발할 수 있고, 회사의 내부 개발자들을 위해 문서화 하여 회사 UI라이브러리로 사용하거나, 외부 공개용 디자인시스템을 개발하기 위한 기본 플랫폼으로 사용할 수 있습니다.
UI 컴포넌트들 카탈로그화
컴포넌트 변화를 Stories로 저장
핫 모듈 리로딩과 같은 개발 툴 경험 제공
🎀 핫 모듈 리로딩(Hot Module Reloading)
웹 개발에서 코드 수정 시 페이지 전체를 리로딩하지 않고도 수정한 코드 부분만 빠르게 적용하는 기술입니다. 이는 개발자들이 코드를 수정하면서 개발 생산성을 높이고, 새로고침에 의한 시간 낭비를 줄이는 데 도움을 줍니다. 보통 웹팩과 같은 모듈 번들러에서 지원됩니다. 웹팩은 핫 모듈 리로딩을 위해 개발 서버에서 소스 코드의 변경 사항을 실시간으로 감지하고, 필요한 모듈만 로딩하여 적용하는 기능을 제공해 더 빠른 반응성을 확보케 해줍니다.
리액트를 포함한 다양한 뷰 레이어 지원
우선 리액트 프로젝트를 만들어 줍니다. (npx create-react-app 프로젝트명)
폴더가 생성되면 폴더 안에서 Storybook을 설치합니다.
npx storybook init -> package.json을 보고 사용중인 프론트엔드 라이브러리에 맞는 사용환경울 알아서 만들어줍니다.
설치가 완료되면 storybook폴더와, /src/stories폴더가 생성됩니다.
npm run storybook으로 실행할 수 있습니다. -> localhost:6006으로 접근하여 실행시킵니다.
👀 이 때 실행오류가 난다면
npm i @testing-library/dom을 입력한 후 다시 실행합니다.
storybook 을 사용하면 애플리케이션을 실행하고 이벤트를 통해 상태를 변경하는 과정을 거치지 않아도 상태변화에 대한 컴포넌트의 변화를 확인할 수 있습니다.
파일명.js파일을 만들고 같은 이름의 파일명.stories.js를 만들면 storybook폴더 안에 있는 Storybook설정 파일에 의해 알아서 스토리로 인식합니다.
🔍 useRef 는?
리액트의 Hook 중 하나로, 함수형 컴포넌트에서 클래스 컴포넌트의 인스턴스 변수와 유사한 기능을 수행하는 데 사용됩니다. 이를 사용해 DOM 노드나 변수를 저장하고, 이를 컴포넌트의 다른 부분에서 참조하거나 변경할 수 있습니다. 컴포넌트의 state와 독립적으로 값을 저장하거나 관리할 수 있으며, 최적화나 성능개선에도 유용하게 사용됩니다.
보통 useEffect와 함께 사용되며, useEffect 내부에서 생성된 DOM 요소나 변수에 접근하거나 수정할 수 있고, useRef는 최초 렌더링 이후에도 변수나 DOM 요소의 값을 유지하므로 컴포넌트가 다시 렌더링되어도 값이 유지됩니다. 즉 일반적인 state와 달리 컴포넌트의 상태를 변경하지 않으므로 기본적으로 리렌더링하지 않습니다.
🎀 useRef를 사용하는 예시
포커스를 가져오거나, 어떤 DOM 요소의 크기나 위치를 가져오는 작업, 함수형 컴포넌트에서 인스턴스 변수와 유사한 동작을 하는 기능을 구현할 때 많이 사용됩니다.
DOM 엘리먼트 주소값을 활용해야하는 경우, React로 모든 개발 요구사항을 충족할 수 없습니다. 이런 예외적인 상황에서 useRef로 DOM노드, 엘리먼트, React 컴포넌트 주소값을 참조할 수 있습니다.
const 주소값을_담는_그릇 = useRef(참조자료형)
// 이제 주소값을_담는_그릇 변수에 어떤 주소값이든 담을 수 있습니다.
return (
<div>
<input ref={주소값을_담는_그릇} type="text" />
{/* React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면*/}
{/* 주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담깁니다. */}
{/* 향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용할 수 있습니다. */}
</div>);
컴포넌트가 리렌더 되더라도 위의 주소값이 바뀌지 않는 특성을 활용해 제한된 상황에서 useRef를 활용할 수 있습니다.
🎀 useRef 를 사용해 DOM을 조작하면서 다른 방법으로 컴포넌트를 리렌더링할 수 있습니다. 다른 state나 props가 변경될 때 리렌더링이 발생할 수 있습니다. 또는 컴포넌트 내부에서 'forceUpdate'함수를 호출해 강제로 리렌더링을 할 수도 있습니다. 그러나 이러한 방법은 권장되지 않습니다.
하지만 대부분의 경우에 React 문법을 벗어나 useRef를 남용하는 것은 부적절합니다. 주의해서 사용해야 합니다.