React 가이드 1편 - 리액트 컴포넌트 기초

kdeun1·2022년 10월 16일
1

React 정리

목록 보기
1/7
post-thumbnail

기초

특징

리액트는 컴포넌트로 구성되어있음

  • 컴포넌트 : 재사용이 가능하고 관심사를 분리할 수 있음
  • 생산성과 유지보수가 용이하다
  • 웹 사이트를 위한 최신의 반응형 UI를 구축할 수 있음
  • 선언적 접근 방식(declarative approach)를 사용한다.
  • 컴포넌트의 최종 상태와 어떤 상황에서 어떤 상태가 사용되어야 하는지 정의하면 된다. 리액트는 이 모든 작업을 숨어서 처리한다.

Vanilla JS vs. React

  • JS로 작업할 때는 모든 단계의 코드를 일일이 작성해야한다. 요소를 생성, 컨텐츠 추가, 클래스 추가, 이벤트 리스너 추가
  • JS는 명령적 접근 방식으로 일련의 액션들을 단계 별로 코딩해야하며, 절차적인 세부 사항을 신경써야 한다
  • React는 컴포넌트를 조합하여 화면에 렌더링하는 작업을 한다.
  • React는 커스텀 HTML 컴포넌트에 커스텀 HTML 요소를 가지며, 컴포넌트를 만들어 유지보수성과 관리성에 유리하다.
  • React는 최신의 다채로운 복잡한 UI를 쉽게 구축할 수 있게 해준다. 고수준의 구문을 제공해서 선언형 방식, 선언형 컴포넌트 중심의 방식으로 코드를 작성한다. 즉, 복잡하고 인터랙티브하고 반응형있는 UI를 쉽게 만들 수 있다.

프로젝트 생성

CRA(Create React App) 사용

리액트 프로젝트를 생성하는데 사용하며, 간단한 파일, 폴더와 미리 설정된 환경 설정 파일들이 존재한다.

npx create-react-app 프로젝트_이름
cd 폴더명
npm install
npm start

Node.js가 필요하다. 프록시나 VPN, 백신을 확인해야한다.


분석

index.js

// index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import reportWebVitals from './reportWebVitals';

const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

index.js는 처음으로 실행되는 파일이다. 하지만 index.js의 코드 그대로가 아닌 변환된 버전의 코드가 실행된다. cra 프로젝트 설정에서 코드를 변환하고 최적화하는 스크립트가 포함되었다면 이 과정은 백그라운드에서 처리된다.
위 코드는 브라우저에서 그대로 실행되지 않는다. npm start 프로세스는 코드를 확인해서 변환한 후 브라우저에 전달한다. 브라우저 안에서 특정 작업이 추가로 처리된다.
import './index.css';과 같은 코드는 css 파일을 js 파일로 변환하는 것과 같은데, 일반적인 JS에서는 작동하지 않는 코드이다. 유효하지 않는 구문이다.
root.render( <React.StrictMode> <App /> </React.StrictMode> ); 코드도 JS 파일 안에 HTML 코드처럼 보인다. 유효하지 않은 코드지만, 브라우저로 전달되기 전에 코드가 변환되어 개발자가 더 편한 코드로 개발할 수 있게 해준다.

react-dom

react의 서드파티 라이브러리이다. import ReactDOM from 'react-dom/client';코드를 통해 라이브러리가 제공하는 기능을 index.js에서 사용할 수 있다. const root = ReactDOM.createRoot(document.getElementById('root'));는 React로 구축할 UI를 React 앱의 엔트리 페이지(public/index.html)에 어디에 배치해야하는지 React에 알려주는 기능을 한다.
index.html에 <div id="root"></div>에 React가 주도하는 UI(렌더링되어야할 것들)를 추가한다.

App

import App from './App';을 가져와 root에 render시킨다. App파일은 JSX 구문으로 만들어진 컴포넌트이다. root에 렌더링할 첫 번째 컴포넌트이다.
App.js 파일 안에는 대문자로 시작하는 App() 함수가 존재하고 이를 export하고 있다.
JS 파일 안에 HTML 코드를 반환하고 있는 App() 함수는 익숙한 형태가 아니고 유효한 JS 코드도 아니다. 이 형태가 JSX이다.

JSX

JS안에 있는 HTML 코드이다. JSX는 JavaScriptXML을 의미한다. 결국 HTML은 XML이라고 할 수 있기 때문이다. 실제로 JSX로 작성하더라도 브라우저에 로드된 js파일의 코드를 열어보면 변환된 코드들이다. 브라우저 devtool에 보이는 코드들은 리액트 패키지 코드 + 작성한 코드가 번들링되어 보여진다.
JSX 코드는 개발자로서 개발 친화적으로 작성하기 쉬운 코드이며, 일반적으로 브라우저에서 지원되지 않는다. 브라우저에서는 브라우저 친화적으로 변환된다.


컴포넌트 기초

커스텀 컴포넌트 만들기

하나의 컴포넌트는 하나의 js 파일로 만든다.
App.js는 앱 내 루트 컴포넌트이다. 리액트는 컴포넌트 트리를 만들어서 App 컴포넌트 또는 다른 부모 컴포넌트 하위로 추가해서 사용한다. 이 컴포넌트 트리의 구조를 렌더링한다.
컴포넌트 규칙이 존재한다.

  • 대문자로 시작하는 단어, 복합 명사의 경우 파스칼 케이스
  • 파일 이름을 보고 HTML과 데이터를 추측할 수 있어야 한다.

리액트의 컴포넌트는 js 함수이며, JSX 코드(html 코드)를 반환한다. 관습적으로 컴포넌트의 함수명은 파일명과 같게 사용한다. 그리고 이 함수를 밖으로 export한다.
이 커스텀 컴포넌트를 다른 js파일에서 import해서 사용하며, html 요소처럼 사용할 수 있다. 일반적인 html처럼 사용하되, 대문자로 시작하는 import명으로서 사용한다.
리턴하는 JSX코드를 인라인으로 작성하면 가독성에도 문제가 있고, 작성된 코드가 유효하지 않다.

  • 컴포넌트의 반환하는 JSX 코드는 반드시 하나의 루트 요소를 가져야한다.

위와 같은 문제점의 가장 쉬운 해결법은 또 하나의 <div>로 감싸주는 방법이 있다. 그리고 중괄호를 사용하여 요소를 감싸준다. 그리고 auto format을 사용한다.

리턴된 JSX코드의 스타일을 위해서 class명을 추가해준다. JSX코드는 HTML의 속성이 유사하지만 동일하지는 않다. JS에서 class는 예약어이기 때문에, JSX 코드에서는 className 속성을 사용한다.

동적 값 다루기

관심사의 분리와 재사용성을 위해 JSX 코드 내 값들을 동적으로 바꿔야 한다.
우선은 정적 값을 넣어보자. 함수 안에 JS 코드로 값을 정의하고 JSX 코드 내 기본 JS 코드를 넣을 수 있는 중괄호 안에 값을 넣어준다.
이전의 내용은 컴포넌트를 기계적으로 복붙했을 뿐, 재사용한 것이 아니다. props를 통해 데이터를 넘겨줘야 한다.

Props는 properties를 나타내는 것으로 커스텀 컴포넌트의 속성을 설정할 수 있다.

커스텀 컴포넌트에 파라미터를 추가(일반적인 JS와 같음)한다. 하지만 파라미터들을 일일이 나열하는 것이 아닌 단 1개의 파라미터 프로퍼티(모든 속성을 받는 객체인) props를 사용한다. props의 키는 부모 컴포넌트에서 바인딩된 속성명이다. 이런 식으로 리액트 컴포넌트 사이에 데이터를 공유할 수 있다.

컴포지션

리액트의 컴포넌트를 더 작은 조각으로 나눌 수 있다. 작은 블록들을 모아 UI를 만드는 것을 컴포지션이라고 한다.

wrapper 컴포넌트

중복되는 코드들을 모아 하나의 작은 컴포넌트 (e.g. Card 형태)를 만들어 이를 감싸서 재사용한다.

function Card(props) {
    const classes = `card ${props.className}`;
    return (<div className={classes}>{props.children}</div>);
}

export default Card;

children은 예약어이다. 상위 컴포넌트 안에 있는 하위 요소들이 모두 props.children이다. modal이나 alert 등에서 사용할 수 있으며, 코드 추출을 통한 래퍼 컴포넌트로 코드 중복을 피하고 컴포넌트들을 깔끔하게 유지할 수 있다. 컴포넌트를 결합할 때 composition을 이요한다.

JSX

JSX는 가독성이 높고 간편한 문법이다. 브라우저에서는 변환된 코드를 볼 수 있다.
package.json 파일에서 리액트와 관련있는 react, react-dom 패키지가 존재한다.
과거 오래된 버전의 리액트 프로젝트에서는 모든 JSX파일에서 react를 import했다. 최신 플젝 셋업에서 이를 처리해줘서 지금은 사용하지 않는다.

React.createElement()

3가지 타입의 전달인자가 존재한다. (3개 이상이 될 수 있음)

  • type : 생성해야하는 요소 (input, ReactHTML, ReactSVG, 문자열)
  • props? : 이런 요소의 모든 속성을 설정하는 객체
  • ...children : 요소 사이에 있는 컨텐츠들 (여러 개를 가질 수 있음)

JSX 코드를 React.createElement()로 구성할 수 있는데, 개발이 복잡하고 번거롭다. JSX 코드를 작성하면 자동적으로 내부에서 React.createElement()로 생성되는 코드가 된다.
React.createElement()로 생성하는 경우 1개 이상의 자식 요소를 가질 수 없기 때문에 JSX 문법으로 반환하는 코드는 1개의 래퍼 루트 요소를 가져야한다.

Vue 3의 h() 함수와 동일한 구조를 갖고있다. 전달인자의 타입도 동일하다.

컴포넌트 폴더 구조

components 폴더에 모두 다 넣기에는 컴포넌트 규모와 개수가 많아지는 우려가 있다.
앱의 특정 기능과 관련없는 일반적인 UI 컴포넌트와 기능이 존재하여 렌더링하는 컴포넌트로 나눌 수 있으며, 이에 따라 하위 폴더로 구성한다.
파일을 잘 정리하고 컴포넌트들을 체계적으로 유지할 수 있게 만들어주며, 하나의 폴더에 많은 컴포넌트들을 한 번에 넣지 않게 해주기 위함이다.
동료 개발자들과의 규칙에 따라 폴더 구조는 달라질 수 있다.

Syntax

선호에 따라 arrow function 사용하기


실습

참고

profile
프론트엔드 개발자입니다.

0개의 댓글