[TIL] 2022-05-25 / 48일차(React)

미음제

·

2022. 5. 25. 20:05

https://ko.reactjs.org/

 

오늘 배운 내용

 

React를 공부하는 방법?

 

라이브러리는 개발을 돕기 위해 여러 기능을 모아둔 모듈이다. 라이브러리, 프레임워크를 사용할 때 깊은 depth까지 제대로 파고들어야 잘 활용하거나 제대로 활용할 수 있다는 생각에 깊게 공부하는 바람에 어렵게 느껴질 수 있다고 한다. 기능의 구체적 원리, 코드를 알기 위해 깊게 파고들기보다는(나중에 천천히 공부하는 방향성을 갖고) 천천히 공부해 가는 것을 추천한다고 한다.

 

 

파일 구조 – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

우선 '컴포넌트 자체만'을 열심히 생각하는 자세로 첫 시작을 해야 한다고 한다. 재사용성, 확장성을 미리 생각하고 개발을 하는 것은 쉬운 일이 아니라고 한다.

 

컴포넌트 구조 및 아키텍처 그리고 누가 봐도 깔끔하고 좋은 코드를 작성하는 방법은 잠시 잊어두고 당장 눈앞에 보이는 UI를 컴포넌트로 구현해보면서 공부하는 것이 좋다고 한다. 학습량이 늘어나고 데이터가 쌓이고 나면 UI를 점차 추상적으로 바라보는 방법을 익히며 재사용성에 대해 깨달아 가는 방식으로 공부하도록 하자.

 

깊은 depth를 무작정 파고들어 봤자 이해가 되지 않을 뿐더러(특히 나의 경우는..) 첫 시작부터 거리감을 느끼고 라이브러리나 프레임워크 사용에 거리낌을 느낄 수도 있다. '컴포넌트의 가장 큰 장점은 재사용성에 있다.' 재사용성이 있다는 것은 언제든 교체할 수 있고, 리팩터링하기 쉽다는 말이다. 컴포넌트를 쉽게 바꿀 수 있기 때문에 일단 컴포넌트를 만드는 방법으로 학습하도록 하자. 추후에 실력이 올라가면서 컴포넌트를 리팩터링 하는 방향성을 갖도록 하자.

 

 

 


 

React 

 

https://ko.reactjs.org/

 

React – 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리

A JavaScript library for building user interfaces

ko.reactjs.org

 

React는 사용자 인터페이스를 만들기 위한 JavaScript 라이브러리라고 한다. facebook에서 만들었고, facebook 내부에서는 2011년부터 사용했고, 2013년 5월부터 오픈 소스로 공개된 라이브러리이다.

 

React의 특징

 

특징 1 : 반응형 프로그래밍에서 상태가 변하는 경우에는 해당 상태가 의존되어 있는 다른 곳에서도 새롭게 연산을 적용한다.

 

b = 27
c = 33
a = b + c
print(a) // 60
c = 40
print(a) // 60

 

기본적으로 우리가 생각하는 결과는 위와 같다. a라는 변수에 b와 c의 값을 더해 합산을 하여 할당하고, 이후에 c라는 변수의 값을 40으로 재할당하더라도 a의 값은 변하지 않는다.

 

반면 리액트는 상태를 관찰하고 상태가 변경되면 의존되어 있는 상태에서 새롭게 연산을 작용한다.

 

b = 27
c = 33
a = b + c
print(a) // 60
c = 40
print(a) // 67

 

이런 식의 새로운 연산을 한다고 생각할 수 있다. 단적인 예시니까 개념으로만 이해하고 넘어가자.

 

특징 2 : React는 컴포넌트의 조합으로 View를 구성한다.

 

React는 MVC 아키텍처에서 View만을 관리하는 라이브러리로 다른 영역에 관여를 하지 않는다.

React는 View를 컴포넌트 시스템으로 관리를 한다.

컴포넌트는 재사용이 가능한 독립적인 객체로, Application이 실행되는 런타임 시점에 사용된다.

 

컴포넌트에는 여러 요소가 담기게 된다. HTML, Style, Javascript를 포함하고 있고, Event와 State가 담길 수 있다.

Javascript 로직은 Event와 State를 관리하는 로직이다.

 

React 컴포넌트

 

React 컴포넌트 - Tree 구조

 

각 컴포넌트 들은 Tree 구조로 구성할 수 있다. 컴포넌트 간 관계가 생기면 각 컴포넌트들은 서로 데이터와 메시지를 주고받을 수 있다.

 

특징 3 : 가상돔(Virtual DOM)

 

가상 돔(Virtual DOM)은 코드로 DOM Tree를 표현한다. 필요한 부분만 한 번에 렌더링 하기에 별다른 최적화 과정이 없이 빠른 성능을 낼 수 있다. 그러나 DOM을 직접 조작하는 것보다는 느리다.

 

대부분의 케이스에서 빠른 성능을 보이는 것이지 가상 돔을 사용하는 것이 DOM을 직접 조작하는 것보다 빠르다는 이야기는 '미신'이다. 따라서 성능이 중요한 곳에는 바닐라 JS를 직접 사용한다고 한다.

 

성능보다는 '개발을 편하게 하기 위해' 가상 돔을 사용한다고 이해한다. 성능 최적화를 엄청나게 신경 써서 하지 않더라도 괜찮은 성능이 나오기 때문에, 성능 최적화는 생각하지 않고 편리하게 사용하기 위해 가상 돔을 활용한다고 할 수 있다.

 

 

 

[TIL] 2022-03-30 / 8일차

오늘 배운 내용 코딩 테스트를 준비하는 방법 알고리즘을 잘 공부하는 방법 문제를 풀 때 중요한 것! 항상 여러 가지 풀이가 존재할 수 있다는 것을 인지하자 항상 예외가 존재할 수 있다는 것을

mieumje.tistory.com

 

React 시작하기

 

 

새로운 React 앱 만들기 – React

A JavaScript library for building user interfaces

ko.reactjs.org

 

 

 

GitHub - facebook/create-react-app: Set up a modern web app by running one command.

Set up a modern web app by running one command. Contribute to facebook/create-react-app development by creating an account on GitHub.

github.com

 

 

공식 문서에 나와있는 가장 빠르게 React 프로젝트를 시작하는 방법이다. webpack 설정을 별도로 지정하지 않고 사용할 수 있어 가장 쉬운 방법이라고 할 수 있다. React를 처음 시작할 때 이 방법을 가장 많이 사용한다.

 

npx create-react-app my-app

 

명령어를 실행하면 다음과 같은 구조로 프로젝트가 자동 생성된다.

 

 

App을 실행하면 index.html을 통해 들어가게 된다. 최초 진입점이라고 생각하면 될까 싶다. build가 된 JS 파일들이 index.html에 주입된다.

 

index.js 파일은 React App의 시작점이라고 한다.

 

App 컴포넌트는 최상위 컴포넌트(Root 컴포넌트)다. 

 

// 처음 프로젝트를 실행했을 때의 App.js
import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

 

Javascript 파일 내부에 html처럼 보이는 코드들이 존재한다. html 처럼 보이는 이 코드들이 가상 돔을 정의한 것이다. 이러한 포맷 구조를 JSX라고 한다.

 

JSX를 사용하는 데에는 몇 가지 규칙이 있다.

 

JSX 규칙

 

JSX 규칙 1 : className

 

html의 class 속성을 지정할 때는 class="클래스 속성명"으로 지정하지만, JSX에서는 className으로 지정한다. 다른 이유가 있는 것은 아니고 Javascript에서 class를 정의할 때, class 예약어를 사용하기 때문이다.

 

JSX 규칙 2 : 최상위 요소는 반드시 하나여야 한다.

 

JSX에서는 반드시 최상위 요소가 하나만 존재해야 한다. 가상 돔에서 컴포넌트 변화를 효율적으로 감지하기 위해서이다. 여러 요소가 있어야 하는 경우에는 상위에 새로운 DOM으로 감싸거나, React fragment를 사용해야 한다.

 

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="Component 1">
      // 내용 생략
    </div>
    <div className="Component 2">
      // 내용 생략
    </div>
  );
}

export default App;

 

이런 식으로 div 요소를 두 개를 사용하고 싶다면 다음과 같은 방식으로 사용해야 한다.

 

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div>
      <div className="Component 1">
        // 내용 생략
      </div>
      <div className="Component 2">
        // 내용 생략
      </div>
    </div>
    
    // or
    
    <> // 이 방식이 React fragment, fragment에 이름을 지정할 수 도 있다.
      <div className="Component 1">
        // 내용 생략
      </div>
      <div className="Component 2">
        // 내용 생략
      </div>
    </>
  );
}

export default App;

 

JSX 규칙 3 : 표현식

 

function App() {
  const name = 'Learn React';
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          {name}
        </a>
      </header>
    </div>
  );
}

 

JSX 규칙 4 : 조건식

 

&&(곱 연산)을 통해 렌더링을 지정할 수 있다.

 

function App() {
  const isShow = true;

  return (
    <div>
      {isShow && (
        <h1>This is Title</h1>
      )}
    </div>
  );
}

 

JSX 규칙 5 : 삼항 연산자

 

function App() {
  const isShow = 'h1';

  return (
    <div>
      {isShow === 'h1' ?  (
        <h1>This is Title</h1>
      ) : null }
    </div>
  );
}

export default App;

 

JSX 규칙 6 : 반복

 

function App() {
  const names = ['React', 'Vue', 'Angular'];

  return (
    <div>
      <ul>
        {
          names.map(item => (
            <li key={item}>{item}</li>
          ))
        }
      </ul>
    </div>
  );
}

export default App;

 

반복을 사용할 때는 key를 적어주어야 한다. key를 통해 React에서 성능 최적화를 하기 때문이다.

 


 

React 컴포넌트

 

React 컴포넌트 - Tree 구조

 

여러 컴포넌트들이 모여 하나의 App을 구성하게 된다. 서로 연결된 각각의 컴포넌트 들은 데이터와 메시지를 주고받을 수 있다.

 

컴포넌트 간 데이터는 위에서 아래로 흐르는 '단방향' 구조다.

 

재사용성이 좋은 컴포넌트를 구성하는 방법?

 

좋은 도구나 방법은 따로 없고, 개발자 스스로 UI에서 찾아야 한다. UI를 추상적으로 불 수 있어야 한다.

 

UI를 추상적으로 본다?

 

내가 우선 이해한 바로는 다음과 같다.

 

1

 

2

 

두 사진에서 빨간색 부분은 얼핏 봤을 때 재사용이 가능해 보이는 UI이다. 이런 UI를 컴포넌트로 만든다면 재사용을 할 수 있다.

 

3

 

4

 

3, 4 사진에서 사용되는 부분도 정확하게 똑같은 구조를 갖고 있는 것은 아니지만 재사용성이 있다고 볼 수 있다. 필요한 부분에서 약간의 수정만 있다면 재사용할 수 있다.

 

이런 식으로 UI를 추상적으로 바라보면 공통점이 보이게 된다고 한다. 여기서 공통점을 찾을 수 있게 된다면 재사용의 시작이라고 할 수 있다.

 

단, UI를 너무 추상적으로 보아 제약이 없는 컴포넌트는 문제가 될 수 있다. 다른 사람이 보았을 때 해당 컴포넌트가 어떤 컴포넌트인지 한 번에 알아보기 힘들 수 있다. 적당선을 찾아 컴포넌트를 만들어야 한다.

 

아직까진 추상적으로 생각하는? 방식이 와닿지는 않는다. 컴포넌트 하나를 만드는 게 어려운 상태라 재사용성에 대해 고민해 보지 못했었다. 앞으로 강의를 듣거나, 과제를 할 때 이 방향성에 대해 인지하고 생각해볼 필요가 있다고 느껴진다. 더군다나 React 강의 기간이 끝나면 바로 팀 프로젝트를 진행하니 더더욱 연습할 필요가 있다.

 

컴포넌트는 어떻게 분류하는가?

 

React는 라이브러리로 자유도가 높다고 할 수 있다. 자유도가 높은 만큼 개발자 입장에서 고민도 많아지게 된다. 정해진 규격이 없기 때문에 규칙을 세우는 것이 어려운 과제가 될 것이다.

 

처음 React를 접하고 컴포넌트를 분류해야 한다면 깊은 고민을 하기보다는 우선 컴포넌트를 만들어보자. 글의 서두에 작성한 내용과 동일하다.

 

"재사용이 가능하다, 쉽게 교체할 수 있다."는 컴포넌트의 장점을 상기하면서 우선 작성하고, 추후에 리팩터링 하는 과정을 거치면 된다(어느 정도 실력이 생기고 학습 데이터가 많아졌다면). 컴포넌트를 분류하는 자신만의 기준이 생기거나, 팀 단위 작업을 할 때 그 팀만의 기준이 있는 경우 그때 분류를 해도 늦지 않다는 얘기다.

 

대표적으로 컴포넌트를 분리하는 방법으론 다음과 같은 케이스가 있다.

 

  • 도메인을 기준으로 분류
  • 역할을 기준으로 분류(Header, Nav, Footer... )
  • 크기로 분류

 

어디까지나 분류의 기준은 팀이다. 언제든 변경이 가능하다는 점을 생각하자.

 

React의 컴포넌트는 함수다.

 

컴포넌트는 함수로 만들어져 있다.

 

import logo from './logo.svg';
import './App.css';

function App() { // -> App 컴포넌트
  return (
    <div className="App">
      // 내용
    </div>
  );
}

export default App;

 

 

컴포넌트(함수)는 props 객체를 받아 내부 로직을 실행하고, 화면에 노출될 JSX를 반환하게 된다. 컴포넌트 Tree 구조에서 최상위 컴포넌트(Root 컴포넌트)가 최종적으로 화면에 보이는 컴포넌트가 된다. 

 

Root 컴포넌트가 화면에 노출된다.

 

컴포넌트는 화면에 보일 JSX를 만드는 것이라, 처음부터 잘 만들고자 하기보다는 현재 상태에서 최선의 방안을 모색해 코드를 작성하고, 자주 리팩터링 하는 과정을 거치는 것이 좋다고 한다.

 

잘 설계하는 것도 중요하지만, 실력 성장에 맞게 리팩터링 하는 과정을 거치는 것이 좋다.

 

React 컴포넌트 분리하기

 

create-react-app을 통해 생성된 프로젝트에서 간단하게 컴포넌트를 분리해보자. 

 

import logo from './logo.svg';
import './App.css';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <img src={logo} className="App-logo" alt="logo" />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}

export default App;

 

최상위 컴포넌트 JSX 내부에 img 태그로 logo를 렌더링하고 있다. logo를 컴포넌트로 분리해보자.

 

우선 컴포넌트를 생성하기 위해 새로운 디렉터리를 만들고 해당 디렉터리에서 컴포넌트를 생성한 후, App 컴포넌트에서 import를 해주면 된다.

 

//src/components/Logo/index.js
import logo from './logo.svg';

function Logo() {
  return <img src={logo} className="App-logo" alt="logo" />
}

export default Logo;

 

import './App.css';
import Logo from './components/Logo'

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Logo />
        <p>
          Edit <code>src/App.js</code> and save to reload.
        </p>
        <a
          className="App-link"
          href="https://reactjs.org"
          target="_blank"
          rel="noopener noreferrer"
        >
          Learn React
        </a>
      </header>
    </div>
  );
}
export default App;

 

이렇게 하위 컴포넌트를 import 하여 컴포넌트를 분리할 수 있다.

 

React 컴포넌트 : props

 

props를 통해 데이터를 하위 컴포넌트로 넘겨줄 수 있다. string을 넘겨줄 때에는 ""를 통해, 그렇지 않은 경우는 {}을 통해 넘겨주게 된다.

 

import './App.css';
import Logo from './components/Logo'
function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Logo size="100px"/>
        // 생략
    </div>
  );
}
export default App;

 

import logo from './logo.svg';

function Logo(props) {
  return <img src={logo} className="App-logo" alt="logo" style={{ width: props.size, height: props.size}}/>
}

export default Logo;

 

size라는 데이터를 부모 컴포넌트에서 하위 컴포넌트로 넘겨주고, 하위 컴포넌트에서 해당 데이터를 사용해 style 속성을 지정했다.

 

props의 default 값을 지정할 수도 있다. Logo 컴포넌트에서 다음과 같이 default 값을 지정한다. props로 값이 내려오지 않을 경우 default 값으로 데이터를 지정하게 된다.

 

Logo.defaultProps = {
  size: 200,
}

 

또한 props의 데이터 타입도 지정할 수 있다. props로 number 타입 데이터를 받고, 그렇지 않은 경우 에러를 발생하게 된다.

 

import PropTypes from 'prop-types';

// 생략

Logo.propTypes = {
  size: PropTypes.number
}

 

React 컴포넌트 : children props

 

children props를 통해 태그 내부 내용을 지정할 수 있다. children props의 데이터 타입 검사는 node라는 타입을 사용하게 된다. node 타입은 jsx, element를 받을 수 있는 데이터 타입이다. 해당 props가 반드시 필요한 경우에는 isRequired를 사용할 수 있다.

 

import './App.css';
import Paragraph from './components/Paragraph';

function App() {
  return (
    <div className="App">
      <header className="App-header">
        <Paragraph>
          Edit <code>src/App.js</code> and save to reload.
        </Paragraph>
        // 생략
      </header>
    </div>
  );
}
export default App;

 

Paragraph 컴포넌트를 분리하고, 해당 내용을 children props를 통해 내려주게 된다. 

하위 컴포넌트(Paragraph)에서 children props를 통해 내려받는 내용을 {children}을 통해 p 태그에 내용으로 추가했다. 타입 검사와, isRequired까지 propTypes에서 지정해준다.

 

// src/components/Paragraph/index.js
import PropTypes from 'prop-types';

function Paragraph({ children, size = 10 }) {
  return <p style={{ fontSize: size}}>{children}</p>
}

Paragraph.propTypes = {
  children: PropTypes.node.isRequired,
  size: PropTypes.number
}

export default Paragraph;

 


 

오늘의 회고

 

 

 

너무 오랜만에 쓰는 TIL.. 노션 클론 과제 이후 밀린 강의를 따라잡기 급급하고 중간중간 또 과제를 하고 피드백하고 반영하고 무한 굴레에 빠져 있었고 "내일은 꼭 조금이라도 TIL 작성하자"는 다짐은 매번 했지만 매번 실패했다.

 

가뭄에 단비 같은 1주일의 방학(복습기간이지만 복습은 못했다. Vue 과제 완성하기 급급했다) 이후에 React를 시작하게 되면서 다시 TIL을 작성하게 된다.

 

복습기간에 Vue 과제 내용과 학습 내용을 정리해서 글을 작성하려 했는데, 과제를 마치는데 어려워 시간을 내지 못했다(논 시간도 많고).

 

밀린 글을 천천히 써 나갈까 생각했는데, 그렇게 되면 React 내용도 점차 밀리고 제대로 시작 못할 거 같아서 React 내용부터 매일(혹은 2일에 한번) TIL을 작성하고자 한다. Vue를 통해 과제를 하면서 느낀 건데, 급급하게 과제를 완성한다고 강의를 빠르게 듣고 적용하다 보니 내용을 제대로 소화하지 못한 것 같다. 최대한 강의를 밀리지 않게 듣고 TIL을 작성할 수 있도록 하는 게 맞다고 생각된다. 물론 그동안 작성하지 못한 내용들도 꼭 올릴 수 있도록 하자. 더 이상 미루면 안 된다. 미루면 안 된다기 보단 꼭 작성해서 올리자가 맞겠다.

 


Vue와 React를 배우게 되었다. 프레임워크, 라이브러리를 처음 써보는 상황이라 어렵게 느껴지기도 하지만 새로운 걸 익히는 것이라 재밌는 느낌도 있다(재밌는 게 맞는지는 잘 모르겠다.. Vue 과제 때 어려웠으니).

 

Vue 과제를 진행하고 이번 React강의를 수강하면서 느낀 것은 왜 바닐라 자바스크립트로 무엇인가를 만드는 게 어려운 일인지, Vue, React를 사용하는 게 왜 편리한지를 나름 느꼈던 것 같다. 아직 둘 다 제대로 사용하고 있지는 못하지만(강의 내용을 빌리자면 제대로 쓴다기보다는 사용경험이 부족한 상태) 귀찮은 일 들을 이 둘이 해주는 것 같다. 

 

단적으로 바닐라를 사용했을 때, state가 변경되는 state를 변경하는 함수를 따로 만들고, 각 컴포넌트에서 데이터를 주고받는 로직을 짰어야 했는데, Vue에서 store를 사용했던 개념이나, React에서 useState를 사용하면서 매우 편리하다고 느껴졌다.

 

아마 팀 프로젝트를 React로 진행할 것 같은데 제대로 학습해서 팀에 누가 되지 않도록, 그리고 내 것으로 체화할 수 있도록 열심히 해야겠다.

 

반응형