TIL. [React] Custom Component

김은서·2022년 8월 28일
0

TIL

목록 보기
33/52

Component Driven Development (CDD)
레고처럼 조립해 나갈 수 있는 부품 단위로 UI 컴포넌트를 만들어 나가는 개발을 진행할 수 있습니다.

CSS 전처리기(CSS Preprocessor)
CSS가 구조적으로 작성될 수 있게 도움을 주는 도구

SASS(Syntactically Awesome Style Sheets)
CSS를 확장해 주는 스크립팅 언어

CSS 전처리기의 문제를 보완하기 위해 BEM, OOCSS, SMACSS 같은 CSS 방법론이 대두되었음.
각각의 장단점이 있으나 결국 세 방법론 모두 같은 지향점을 가지고 있음.

방법론의 공통 지향점

  • 코드의 재사용
  • 코드의 간결화(유지 보수 용이)
  • 코드의 확장성
  • 코드의 예측성(클래스 명으로 의미 예측)

애플리케이션으로 개발 방향이 진화하면서 컴포넌트 단위의 개발은 캡슐화의 중요성을 불러왔음.
하지만 CSS는 컴포넌트 기반의 방식을 위해 만들어진 적이 한 번도 없었음.
결국 CSS도 컴포넌트 영역으로 불러들이기 위해서 CSS-in-JS가 탄생해서 이 문제를 정확하게 해결함.

CSS-in-JS에는 대표적으로 Styled-Component가 있습니다.

Styled-Component는 기능적(Functional) 혹은 상태를 가진 컴포넌트들로부터 UI를 완전히 분리해 사용할 수 있는 아주 단순한 패턴을 제공함.

Styled Components

Styled Components 설치하기

npm install --save styled-components

package.json에 다음 코드를 추가
여러 버전의 Styled Components가 설치되어 발생하는 문제를 줄여줌.

{
  "resolutions": {
    "styled-components": "^5"
  }
}

Styled Components를 사용할 파일로 불러오기

import styled from "styled-components"

Styled Components 문법

1. 컴포넌트 만들기

const 컴포넌트이름 = styled.태그종류`
CSS속성1:속성값;
CSS속성2:속성값;
`;

ex)
const RedButton = styled.buttton`
background-color:red;
color:white;
`;

Styled Components는 ES6의 Templete Literals 문법을 사용합니다. 즉, 따옴표가 아닌 백틱을 사용함.

2.컴포넌트를 재활용해서 새로운 컴포넌트 만들기

const 컴포넌트이름 = styled.(재활용할 컴포넌트)`
추가할 CSS속성1:속성값;
추가할 CSS속성2:속성값;
`

ex)
const BigRedButton = styled(RedButton)`
padding : 10px;
margin-top:10px;
`;

const BigBlueButton = styled(BigRedButton)`
background-color:blue;
`

컴포넌트를 선언하고 styled() 에 재활용할 컴포넌트를 전달해준 다음, 추가하고 싶은 스타일 속성을 작성해주면 됨.

3. Props 활용하기

Styled Component로 만든 컴포넌트도 React 컴포넌트처럼 props를 내려줄 수 있음.
내려준 props 값에 따라서 컴포넌트를 렌더링하는 것도 가능함.

const 컴포넌트이름 = styled.태그종류`
CSS속성:${(props) => 함수코드}
`

Styled Components는 템플릿 리터럴 문법( ${ } )을 사용하여 JavaScript 코드를 사용할 수 있음.
props를 받아오려면 props를 인자로 받는 함수를 만들어 사용하면 됨.

1) Props로 조건부 렌더링하기

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

<Button1>Button1</Button1>
<Button1 skyblue>Button1</Button1>

위 코드의 경우는 삼항연산자를 활용해 <Button> 컴포넌트에 skyblue 라는 props가 있는지 확인하고, 있으면 배경색으로 skyblue를, 없을 경우 white를 지정해주는 코드.

2) Props 값으로 렌더링하기

props의 값을 통째로 활용해서 컴포넌트 렌더링에 활용할 수 있음.

const Button = styled.button`
background:${(props) => props.color ? props.color : "white"}
`

<Button1>Button1</Button1>
<Button1 color="orange">Button1</Button1>
<Button1 color="tomato">Button1</Button1>


--------------------------------------------
const Button = styled.button`
background:${(props) => props.color || "white"}
`

<Button1>Button1</Button1>
<Button1 color="pink">Button1</Button1>
<Button1 color="turquoise">Button1</Button1>

4. 전역 스타일 설정하기

스타일을 컴포넌트로 만들 수 있다는 것은 좋지만, 전역에 스타일을 설정하고 싶을 땐 어떻게하면 좋을까?

우선 전역 스타일을 설정하기 위해 Styled Components에서 createGlobalStyle 함수를 불러옴.

import { createGlobalStyle } from "styled-components";

그 다음 이 함수를 사용해 CSS 파일에서 작성하듯 설정해주고 싶은 스타일을 작성함.

const GlobalStyle = createGlobalStyle`
	button {
		padding : 5px;
    margin : 2px;
    border-radius : 5px;
	}
`

이렇게 만들어진 <GlobalStyle> 컴포넌트를 최상위 컴포넌트에서 사용해주면 전역에 <GlobalStyle> 컴포넌트의 스타일이 적용됨.

function App() {
	return (
		<>
			<GlobalStyle />
			<Button>전역 스타일 적용하기</Button>
		</>
	);
}

Storybook

UI 개발 즉, Component Driven Development를 하기 위한 도구.
각각의 컴포넌트들을 따로 볼 수 있게 구성해 주어 한 번에 하나의 컴포넌트에서 작업할 수 있음.
복잡한 개발 스택을 시작하거나, 특정 데이터를 데이터베이스로 강제 이동하거나, 애플리케이션을 탐색할 필요 없이 전체 UI를 한눈에 보고 개발할 수 있음.

Storybook은 재사용성을 확대하기 위해 컴포넌트를 문서화하고, 자동으로 컴포넌트를 시각화하여 시뮬레이션할 수 있는 다양한 테스트 상태를 확인할 수 있음.
이를 통해 버그를 사전에 방지할 수 있도록 도와줌.
또한 테스트 및 개발 속도를 향상시키는 장점이 있으며, 애플리케이션 또한 의존성을 걱정하지 않고 빌드할 수 있음.

순서

  1. 리액트 프로젝트를 만들기.
npx create-react-app storybook-practice
  1. 폴더 안에서 다음 명령어를 입력하여 Storybook을 설치.
npx storybook init

이 명령어는 package.json 을 보고 사용 중인 프론트엔드 라이브러리에 맞는 Storybook 사용 환경을 알아서 만들어주기 때문에, 꼭 React가 아니더라도 다양한 프론트엔드 라이브러리에서 사용할 수 있음.

  1. 터미널 창에 다음 명령어를 입력하여 Storybook을 실행
npm run storybook

useRef

React로 모든 개발 요구 사항을 충족할 수는 없음.
아래와 같이 DOM 엘리먼트의 주소값을 활용해야 하는 경우 특히 그럼.

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

React는 이런 예외적인 상황에서 useRef 로 DOM 노드, 엘리먼트, 그리고 React 컴포넌트 주소값을 참조할 수 있음.
아래 예시 코드처럼 작성하시면 주소값을 활용할 수 있음.

const 주소값을_담는_그릇 = useRef(참조자료형)
// 이제 주소값을_담는_그릇 변수에 어떤 주소값이든 담을 수 있습니다.
return (
    <div>
      <input ref={주소값을_담는_그릇} type="text" />
        {/* React에서 사용 가능한 ref라는 속성에 주소값을_담는_그릇을 값으로 할당하면*/}
        {/* 주소값을_담는_그릇 변수에는 input DOM 엘리먼트의 주소가 담깁니다. */}
        {/* 향후 다른 컴포넌트에서 input DOM 엘리먼트를 활용할 수 있습니다. */}
    </div>);

이 주소값은 컴포넌트가 re-render 되더라도 바뀌지 않습니다. 이 특성을 활용하여 아래의 제한된 상황에서 useRef 를 활용할 수 있음.

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>);
}

제시된 상황 제외한 대부분의 경우 기본 React 문법을 벗어나 useRef 를 남용하는 것은 부적절하고, React의 특징이자 장점인 선언형 프로그래밍 원칙과 배치되기 때문에, 조심해서 사용해야 함.

0개의 댓글