[TIL] Component-Driven Development(CDD)

ㅜㅜ·2022년 10월 27일
2

Today I learn

목록 보기
41/77
post-thumbnail

Component-Driven Development

:부품 단위로 UI 컴포넌트를 만들어 나가는 개발

(기획 단계에서부터 디자이너, 기획자와 이 컴포넌트 부품들을 함께 공유힐 수 있음)



🤔 CSS in Js 발명 과정

구조화된 CSS의 필요성 대두

  1. 프로젝트 규모 & 복잡도 증가, 작업하는 팀원들 수 증가
  2. 다양한 디바이스 등장으로 더 복잡해진 CSS

CSS 전처리기(CSS Preprocessor) 등장

  • CSS 전처리기는 CSS가 구조적으로 작성될 수 있게 도움을 주는 도구로, 컴파일러가 필요함.
  • CSS 전처리기 중에서는 SASS(Syntactically Awesome Style Sheets)가 가장 유명.
    변수나 함수, 상속 등의 개념을 활용해 재사용이 가능하고, CSS 구조화가 가능.
  • ❌ But 전처리기 내부에서 어떤 작업을 하는지 알지 못한 채, 스타일이 겹치는 문제 해결 위해 단순히 계층 구조 만들어내는 것에 의지하게 되고, 그 결과 컴파일된 CSS 용량이 커지게 됨. (문제점)

CSS 방법론 대두

  • CSS 전처리기 문제 보완을 위해 BEM, OOCSS, SMACSS 등의 방법론이 대두됨
  • 방법론들의 공통 지향점 : 코드의 재사용 / 코드 간결화(유지 보수 용이) / 코드의 확장성 / 코드의 예측성 (클래스명으로 의미 예측)
  • BEM : Block, Element, Modifier로 구분해 클래스명 작성하는 방법
  • ❌ But 이런 방법론들은 클래스명 선택자를 장황하게 만들고, 마크업을 불필요하게 크게 만들고, 재사용할 때마다 모든 UI 컴포넌트 명시적으로 확장, 캡슐화(객체의 속성과 행위를 하나로 묶고 실제 구현 내용 일부를 외부에 감추어 은닉)의 개념이 없는 등의 문제점 존재.

CSS-in-Js 탄생 !

  • CSS를 컴포넌트 영역으로 불러들이며 CSS-in-Js가 탄생함.
  • 컴포넌트 안으로 캡슐화가 가능하고, 네이밍이나 최적화를 신경쓸 필요가 없어짐.
  • ❌ But 빠른 페이지 로드에 불리.
  • 대표적으로 'Styled-Componets'가 있음.
  • CSS in JS 라이브러리를 사용하면 CSS도 쉽게 Javascript 안에 넣어줄 수 있고, HTML + JS + CSS까지 묶어서 하나의 JS파일 안에서 컴포넌트 단위로 개발할 수 있게 됨. 이런 CSS in JS 라이브러리 중에서 현재 가장 인기 있는 라이브러리가 Styled Components.



CDD 개발 도구

🤩 Styled Components

React 환경에서 사용가능한 CSS를 컴포넌트화 시킬 수 있는 라이브러리.

  • 설치
//터미널에 명령어 입력 

//with npm
$ npm install --save styled-components

//with yarn
$ yarn add styled-components

//사용할 파일로 불러와주기 
import styled from "styled-components"
  • 권장사항
//package.json에 다음 코드 추가 
//여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여줍니다.
{
  "resolutions": {
    "styled-components": "^5"
  }
}
  • 컴포넌트 만들기
    : ES6의 Template Literals 문법을 사용함.
//사용 예시 

import styled from "styled-components";

const BlueButton = styled.button`
	background-color : blue;
	color: white;
`;

export default function App() {
  // React 컴포넌트를 사용하듯이 사용.
  return <BlueButton>Blue Button</BlueButton>;
}
  • 컴포넌트 재활용
    : 컴포넌트 선언하고, styled()에 재활용할 컴포넌트를 전달해준다음, 추가하고 싶은 스타일 속성 작성.
//위에서 만든 BlueButton 재활용

const BigBlueButton = styled(BlueButton)`
	padding:10px;
	margin-top:10px;
`;
  • props 활용
    :props를 인자로 받는 함수를 만들어서 사용 가능.
//1.props로 조건부 렌더링 
//Button 컴포넌트에 skyblue라는 props가 있는지 확인하고 
//있으면 배경색으로 skyblue, 없으면 white 지정
const Button = styled.button`
	background: ${(props)=> props.skyblue? "skyblue":"white"}
`;


//2.props 값으로 렌더링하기
//props.color가 없다면 white, 있으면 porps.color 값 그대로 가져와 스타일 속성으로 리턴
const Button = styled.button`
	background : ${(props)=> props.color? props.color:"white"}
`;

//삼항 연산자만 사용해야하는 건 아님 
//js 코드라면 뭔든 가능 
const Button = styled.button`
	background:${(props)=>props.color||"white"}
//아래 예시에서 return 문 속의 Button 요소에 skyblue라는 props가 전달되었음  
import styled from "styled-components";

const Button1 = styled.button`
  background: ${(props) => (props.skyblue ? "skyblue" : "white")};
`;

export default function App() {
  return (
    <>
      <Button skyblue>Button1</Button>
    </>
  );
}
  • 전역 스타일 설정
//createGlobalStyle 가져오기 
import {createGlobalStyle} from "styled-components";

//위 함수 사용해 설정해주고 싶은 스타일 작성 
const GlobalStyle = createGlobalStyle`
	button {
		padding : 5px;
		margin : 2px;
		border-radius : 5px;
	}
`;

//만들어진 GlobalStyle 컴포넌트를 최상위 컴포넌트에 사용해줌 
function App(){
	return (
		<>
			<GlobalStyle />
				<Button>전역 스타일 적용하기</Button>
		</>
	);
}


🤩 Storybook

Component Explorer(컴포넌트 탐색기)에 많은 UI 개발 도구가 다양하게 있는데, 그중 하나가 Storybook

각각의 컴포넌트들을 따로 볼 수 있게 구성해주어 한 번에 하나의 컴포넌트에서 작업할 수 있음.

재사용성 확대 위해 컴포넌트를 문서화하고, 자동으로 컴포넌트를 시각화해 시뮬레이션 할 수 있는 다양한 테스트 가능. 버그 사전 방지도 가능.

테스트 및 개발 속도 향상시키는 장점. 애플리케이션 또한 의존성 걱정 않고 빌드 가능.

  • 주요 기능 : UI 컴포넌트들 카탈로그화 / 컴포넌트 변화를 Stories로 저장 / 핫 모듈 재로딩과 같은 개발 툴 경험 제공 / 리액트 포함한 다양한 뷰 레이어 지원

  • 공식문서

  • 실습
npx create-react-app storybook-practice
npx storybook init //만들어진 리액트 프로젝트 폴더를 vscode로 열어서 해당 파일 터미널에서 설치 
npm run storybook//실행

만들 버튼 엘리먼트나 타이틀 엘리먼트를 위한 js 페이지를 만들고, 내용을 작성.
같은 이름에 뒤에 .stories.js를 붙인 파일을 만들면 알아서 스토리로 인식함. 스토리도 작성.

//Button.js

import React from "react";
import styled from "styled-components";

const StyledButton = styled.button`
  background: ${(props) => props.color || "white"};
  width: ${(props) => (props.size === "big" ? "200px" : "100px")};
  height: ${(props) => (props.size === "big" ? "80px" : "40px")};
`;

const Button = ({ color, size, text }) => (
  <StyledButton color={color} size={size}>
    {text}
  </StyledButton>
);

export default Button;


//Button.stories.js

import Button from "./Button";

// title : 컴포넌트 이름으로, '/'를 넣어 카테고리화 할 수 있음. (아래 이미지에 Practice라는 카테고리 생성된 것 볼 수 있음)
// component : 어떤 컴포넌트를 가져와서 스토리로 만들 것인지 명시합니다.(Import 해온 Button)
// argTypes : 컴포넌트에 필요한 전달인자의 종류와 타입을 정해줍니다.
//            지금은 text 라는 전달인자에 text 타입이 필요함을 의미합니다. (나머지들도 다 종류들임)
export default {
  title: "Practice/Button",
  component: Button,
  argTypes: {
    color: { control: "color" },
    size: { control: { type: "radio", options: ["big", "small"] } },
    text: { control: "text" },
  },
};

export const StorybookButton = (args) => <Button {...args}></Button>;

빨간 상자 속 부분이 실습으로 만들어진 탬플릿(?)



🤩 useRef

모든 개발 요구 사항을 React로 충족하기는 힘듦.

DOM 엘리먼트 주소값을 활용해야 하는 경우가 있음.

💡 DOM 엘리먼트 주소값 활용해야 하는 경우

  • focus
  • text selection
  • media playback
  • 애니메이션 적용
  • d3.js, greensock 등 DOM 기반 라이브러리 활용

React는 이런 예외적 상황에서 useRef로 DOM 노드, 엘리먼트, React 컴포넌트 주소값을 참조할 수 있음.

useRef를 통해 DOM을 직접 조작시 리렌더링이 되지 않음.
그리고 useRef를 통해 값을 저장시 리렌더링 후 값이 초기화가 되지 않음.
따라서 렌더링 여부에 상관없이 값을 유지하고 싶을때 사용되기도 함.

특정 DOM 요소에서 써야하는 매서드를 사용해야 할 때 쓴다

매서드 안 써도 React 상에서 할 수 있는 거면 state나 props 사용

  • 사용법
const 주소값을_담는_그릇 = useRef(참조자료형)

return (
	<div>
		<input ref={주소값을_담는_그릇} type="text" />
    </div>);

// React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면
//주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담김.
//이 주소값은 컴포넌트가 re-render 되더라도 바뀌지 않음 
//향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용 가능.
function TextInputWithFocusButton(){
	const inputEl = useRef(null);
  //inputEl이라는 주소값을 담는 그릇이 생김 
  
	const onButtonClick = () => {
		inputEl.current.focus();
	};
  //onButtonClick이라는 함수는 실행되면 inputEl이라는 주소값에 해당하는 DOM요소(current)에
  //focus()라는 매서드를 실행하는 함수이다. 
  
  
	return (
		<>
			<input ref={inputEl} type="text" />
			<button onClick={onButtonClick}>Focus the input</button>
		</>);
}
//ref라는 속성에 inputEl이라는 주소값 담는 그릇을 값으로 할당해놓아서 
//input의 주소가 담겨서 사용할 수 있었던 것. 
오늘 배운 명령어... npm install --a🤭
profile
다시 일어나는 중

0개의 댓글