[멋사] 3주차 과제 - React 기초 정리👩🏻‍💻

·2023년 4월 13일
0

likelion

목록 보기
3/14

들어가기 앞서 간단한 용어 정리^^,~,,

  • JSON: JavaScript Object Notation의 축약어로 데이터를 저장하거나 전송할 때 많이 사용되는 경량의 DATA 교환 형식 ➡️ 데이터를 텍스트 형식으로 저장하고, XML의 대안으로 고안되었다. (종료태그여부, 구문 길이, 속도 등)
  • XML: 사람과 기계가 읽을 수 있는 형식으로 문서를 인코딩하기 위한 규칙 집합을 정의하는 마크업 언어로, 데이터를 텍스트 형식으로 저장한다.
    ➡️ JSON 표현식이 사람과 기계 모두 이해하기 쉽고 용량이 작아서 최근에는 JSON이 XML을 대체해서 데이터 전송에 많이 사용된다.
  • html: 웹페이지 및 웹 응용 프로그램의 구조를 만들기 위한 표준 마크업 언어
  • 바벨: 자바스크립트의 최신 문법 및 사양을 지원하지 않는 브라우저도 쓸 수 있게끔 변환해주는 transcompiler

1. 리액트란? ⚛︎

  • 자바스크립트 라이브러리의 하나로서 특히 SPA(Single Page Application)을 위한 사용자 인터페이스(UI)를 구축하는데 사용되는 오픈소스 JavaScript 라이브러리를 말한다.

최대한 성능을 아끼고 편안한 사용자 경험을 제공하면서 구현하고자 개발되었다.

리액트는 프레임워크가 아닌 라이브러리이다. ➡️ 웹/앱의 뷰를 개발하는 라이브러리로 기타 기능은 직접 구현해야 한다.
다른 개발자들이 만든 라이브러리 라우팅 ➡️ 리액트 라우터, Ajax ➡️ Axion, 상태 관리 ➡️ 리덕스 등을 사용하여 빈자리를 채운다.

자신의 취향대로 스택을 설정할 수 있다는 장점이 있지만, 여러 라이브러리를 접해야한다는 단점도 존재한다.

👩🏻‍💻 리액트는 데이터가 변할 때마다 어떤 변화를 줄 지 고민하는 것이 아닌, 기존의 뷰를 날려버리고 처음부터 새로 렌더링하는 방식이다.

  • 애플케이션 구조가 간단하다.
  • 작성해야 하는 코드 양이 줄어든다.
  • 데이터의 변화가 있으면 기존에 있던 것은 버리고 정해진 규칙에 따라 새로 렌더링한다.

2. 리액트의 특징

2-1. Virtual DOM

👩🏻‍💻 DOM(Document Objenct Model)이란?

  • 객체로 문서 구조를 표현하는 방법 (HTML or XML)

DOM을 수많은 플랫폼과 웹브라우저에서 사용할 때, "동적 UI에 최적화 되어 있지 않다"는 취약한 단점이 존재한다.

규모가 큰 웹 애플리케이션에서 DOM에 직접 접근하여 변화를 주면 성능 이슈가 발생한다.
➡️ 이벤트가 발생할 때마다 Virtual DOM을 만들고, 다시 그릴 때마다 실제 DOM과 비교하여 전후 상태를 비교한 뒤 변경이 필요한 최소한의 변경사항만 실제 DOM에 반영하여 앱의 효율성과 속도를 개선한다. (Diff 알고리즘)

단, Virtual DOM을 이용한다고 해서 사용하지 않을 때와 비교해서 무조건 빠른 건 아니다. (작업이 매우 단순할 경우에는 오히려 리액트를 사용하지 않는 게 나은 경우도 존재한다!)
➡️ 리액트와 Virtual DOM은 업데이트 처리의 간결성을 제공한다.

2-2. Data Flow

  • 리액트는 데이터의 흐름이 한 방향으로만 흐르는 단방향 데이터 흐름을 가진다.
    (양방형 데이터 흐름일 경우 규모가 커질수록 데이터의 흐름을 추적하기 힘들고 복잡해진다.)

2-3. Component 기반 구조

  • Component는 독립적인 단위의 소포트웨어 모듈을 말한다.
  • 리액트는 UI(View)를 여러 컴포넌트 단위로 구분하여 구현한다.
    ➡️ 앱을 리액트로 만든다는 것은 곧 작고 단단한 컴포넌트들을 만들고 이 컴포넌트들을 유기적으로 연결한다는 것을 의미한다.

컴포넌트를 선언하는 방법에는 두 가지가 있다.

  1. 클래스형 컴포넌트
  2. 함수형 컴포넌트

[클래스형 컴포넌트]

import React, {Component} from 'react';

class App extends Component {
  render() {
    const name = 'react';
    return <div className="react">{name}</div>
  }
}
  • Class 키워드
  • Component로 상속을 받는다.
  • render() 메소드

현재는 잘 사용하지 않는다.

[함수형 컴포넌트]

import React from 'react';
import './App.css';

function App() {
  const name = 'react';
  return <div className = "react">{name}</div>
}

export default App;
  • 보통 함수형 컴포넌트는 function을 사용하지 않고 일반적으로 화살표함수로 정의한다.

👩🏻‍💻 둘의 일반적인 차이는?

클래스형:

  • state, lifeCycle 관련 기능 사용이 가능하다.
  • 메모리 자원을 함수형 컴포넌트보다 조금 더 사용한다.
  • 임의 메서드를 정의할 수 있다.

함수형:

  • state, lifeCycle 관련 기능 사용이 불가능하다. ➡️ Hook을 통해 해결
  • 메모리 자원을 클래스형 컴포넌트보다 덜 사용한다.
  • 컴포넌트 선언이 편하다.

+) Hook이 등장한 이후부터는 함수형 컴포넌트에서도 state, lifeCycle의 대부분의 기능구현이 가능해졌으므로 일반적으로 사용되는 [함수형 컴포넌트 + Hook]을 중심으로 학습해야한다.

2-4. State(클래스/함수형 컴포넌트의 기능적 차이)

state

  • 컴포넌트 내부에서 바뀔 수 있는 값으로, 사용자와의 상호작용을 통해 데이터를 동적으로 변경할 때 사용한다.
    state가 변경되면 render() 함수가 다시 실행된다!!

클래스형:

  • constructor 안에서 this.state 초기 값을 설정할 수 있다.
constructor(props) {
  super(props);
  
  this.state = { // 초기 값 설정
    monsters: [],
    userInput: "",
  }
};
  • constructor 없이 바로 state 초기 값을 설정이 가능하다.
class Monsters extneds Component {
  state = {
    monsters: [],
    userInput: "",
  }
};
  • 클래스형 컴포넌트의 state는 객체형식이다.
this.state = { monsters: [], userInput: "", }; // 객체 형식
  • this.setState 함수로 state의 값을 변경할 수 있다.
onClick = {()=>{
  this.setState({number:number+1});
}}

함수형:

  • 리액트 16.8 이후 버전부터 함수형 컴포넌트에서 Hook을 통해 함수형 컴포넌트에서도 state 사용이 가능하다. (useState 함수로 state를 사용)
  • useState 함수를 호출하면 배열이 반환되는데, 첫 번째 원소는 현재상태를, 두 번째 원소는 상태를 바꾸어주는 함수를 의미한다.
const [현재상태, 함수] = useState(''); // [현재상태, 상태를 바꾸는 함수]
import React, { useState } from 'react';

const Counter = () => {
  const [value, setValue] = useState(0); // 현재 0
  return (
    <div>
      <p>
        현재 카운터 값은 <b>{value}</b> 입니다.
      </p>
      <button onClick={() => setValue(value + 1)}>+1</button>
      <button onClick={() => setValue(value - 1)}>-1</button>
    </div>
  );
};

useState는 반환값 두 개를 찾는다. (현재상태, 함수 ➡️ 여기서는 value, setValue이다.)
state 변수(value)와 해당 변수를 갱신할 수 있는 함수(setValue)를 반환 ➡️ 위의 코드에서는 0, value+-1이므로 클릭 될 때마다 state에 +-1이 수행되어 변수를 갱신한다.

2-5. Props (클래스/함수 컴포넌트 차이)

Props

  • 부모 컴포넌트에서 자식 컴포넌트로 전달해 주는 데이터로 고정된(정적) 데이터를 처리하는데 사용하고, 변경이 불가능하다.

컴포넌트 자체 props를 수정해서는 안 된다. (수정은 state)
➡️ 자식 컴포넌트에서 전달받은 props는 변경이 불가능하고, props를 전달해준 최상위 부모 컴포넌트만 props를 변경할 수 있다.

클래스형:

  • this.props를 통해 값을 불러올 수 있다.
class MyComponent extends Component {
  render() {
    const {name, favoriteNumber, children} = this.props;
    return (
      <div>
      안녕하세요, 제 이름은 {name}입니다. <br/>
      children 값은 {children} 입니다. <br/>
      제가 좋아하는 숫자는 {favoriteNumber} 입니다.
      </div>
	);
  }
}
  • 부모 컴포넌트에서 자식 컴포넌트에 전달해주는 props
// App.js
import React from 'react';
import MyComponent from './MyComponent';

function App() {
  return (
    <MyComponent name="React"/> // name 부분이 props를 설정하는 부분이다.
    );
}
export default App;
// MyComponent.js
import React from 'react';

const MyComponent = (props) => {
  return <div>테스트 페이지, {props.name}</div>; // name 받아온다.
};

export default MyComponent;

"테스트 페이지, React"가 출력된다.

함수형:

  • props를 불러올 필요 없이 바로 호출이 가능하다.
const MyComponent = ({name, children}) => {
  return (
    <div>
    안녕하세요 제 이름은 {name}입니다. <br/>
    children 값은 {children} 입니다. <br/>
    </div>
  );
};

props와 state 비교

  • props와 state 모두 컴포넌트에서 사용 혹은 렌더링할 데이터를 담고 있다.
  • props는 부모 컴포넌트에서 설정한다. ➡️ 컴포넌트 자신이 변경할 수 없다.
  • state는 컴포넌트 자신이 직접 가지고 있는 값이고, 그 값의 변경도 내부에서 가능하다.

2-6. LifeCycle

LifeCycle

  • 각각의 컴포넌트들은 생성 ➡️ 업데이트 ➡️ 제거 단계를 겪는 생명주기(LifeCycle)를 가진다.

LifeCycle API

  • 컴포넌트가 DOM 위에 생성되기 전 후 데이터가 변경되어 상태를 업데이트 하기 전 후로 실행되는 메소드

    컴포넌트가 DOM 위에 생성될 때 [컴포넌트가 처음 화면에 렌더링]
    컴포넌트가 DOM 위에 사라지기 전 [컴포넌트가 화면에 지워짐]
    데이터가 변경되어 상태를 업데이트 한 후 [데이터가 변경될 때]

  • React 컴포넌트 rendering 할 때 나오는 메소드 순서

    constructor
    componentWillMount (레거시기능?)
    render
    componenetDidMount

  • React 상태 값 변경시 나오는 메소드

    componentDidUpdate

  • 컴포넌트 제거시 나오는 메소드

    componentWillUnmount

LifeCycle API 메소드는 클래스형 컴포넌트에서만 사용이 가능하다. 함수형 컴포넌트에서는 useEffect Hook이 그 역할을 대신한다.

+) useEffect란?

  • 라이프사이클의 혼합형(componentDidMount, DidUpdate)으로 컴포넌트 생성 및 갱신 때 특정 작업을 수행한다.
useEffect(() => {
  console.log('btn create');
});

해당 코드를 작성한 뒤 리액트 페이지를 새로고침하면 컴포넌트 생성 개수만큼 콘솔이 호출된다.

  • 컴포넌트에 처음 렌더링 될 때만 실행하려면(업데이트시 실행될 필요가 없을 경우) 두번째 파라미터에 배열을 작성한다.
useEffect(() => {
  console.log('btn create');
}, []);
  • 업데이트시에만 실행되게 하려면 두 번째 파라미터에 갱신되는 파라미터를 넣는다.
useEffect(() => {
  console.log('btn create');
}, [name]);

👩🏻‍💻 왜 컴포넌트를 분리할까?

리액트에서 어떤 컴포넌트는 UI를 표현하고자 하고, 또 어떤 컴포넌트는 동작하는 로직을 담고 있는 등 다양한 역할을 하는 컴포넌트로 이루어져 있다.
컴포넌트는 재사용할 수 있는 최소 UI단위이지만 웹에 따라 수행하려고 하는 역할이 복잡하고 다양하다.
➡️ 복잡한 코드를 비슷한 기능을 하는 코드끼리 별도로 관리해야 한다. (관심사의 분리)

👩🏻‍💻 컴포넌트의 분리 기준은?

  • 프로젝트마다 기준점을 어디에 잡느냐에 따라 달라진다.
  1. View와 로직을 분리한다.
  2. state에 따라 분리한다.
  3. 다양하다...

3. React가 node를 쓰는 이유?

  • 프로젝트를 개발하는데 필요한 주요 도구들이 Node.js를 사용하기 때문이다.
    ➡️ node.js를 설치하면 패키지 매니저 도구인 npm 도구가 설치되고, 이 npm도구로 패키지 설치와 업데이트 및 삭제가 가능하다.

4. CRA 시작 파일

CRA(Create React App) 프로젝트 생성을 하면 해당 파일들이 만들어진다.

node_modules

  • 해당 프로젝트에서 필요한 라이브러리들이 설치되어 있는 곳 (ex.모듈)
  • import 구문을 통해 사용할 수 있다. ➡️ 이렇게 모듈을 불러와서 사용하는 것은 node.js에서 지원하는 기능(require 구문)

해당 기능을 브라우저에서 사용하기 위해 번들러를 사용한다.

번들러?
번들러란 필요한 의존성을 추적하여 해당하는 의존성들을 그룹핑해주는 도구를 말한다.
번들러를 사용하면 import(혹은 require)로 모듈을 불러왔을 때 불러온 모듈을 모두 합쳐 하나의 파일을 생성한다. 번들러에는 webpack, Parcel, browserify 등이 존재하며 리액트에서는 주로 webpack을 이용한다.
webpack을 사용한다면 svg, css파일도 불러올 수 있다.

public

  • 배포할 때 외부적으로 보여지는 대표적인 것들이 들어가있는 곳

    favicon: 로고이미지
    index.html: 뼈대가 되는 html 파일
    manifest.json: 모바일에서 저장하는 웹 어플리케이션을 만들 때 필요 (웹/앱의 정보가 담겨져있다)
    robots.txt: 크롤링을 위해 이용되는 파일

src

  • 핵심 파일들, 코드의 대부분이 이곳으로 들어옴 (index.js, js/css파일)

.gitignore

  • 해당 파일 안에 명시된 파일/폴더는 git에 올라가지 않는다.

package.json

  • 생성한 프로젝트의 정보를 json형태로 모아놓은 파일
  • 프로젝트에서 쓰이는 라이브러리, 버전이 명시되어 있다

README.md

  • 프로젝트에 대해 설명을 적는 파일

yarn.lock

  • 프로젝트에 설치되어 있는 라이브러리들의 의존성을 나열한 파일

자세한 건 CRA 프로젝트 파일 생성 게시글에서...

5. npm과 yarn에 대해 더 알아보기

➡️ 둘 다 자바스크립트 런타임 환경인 Node.js의 패키지 관리자

5-1. npm

  • Node.js로 만들어진 모듈을 웹에서 받아 쉽게 설치하고 관리해주는 프로그램

단 몇 줄의 command로 모듈을 설치하고 활용할 수 있고, 이 모듈들이 업데이트 되었는지를 체크해주는 등 JavaScript로 진행하는 프로젝트를 굉장히 편하게 진행할 수 있도록 도와준다.

5-2. yarn

  • 페이스북에서 만든 자바스크립트 패키지 매니저로 npm과 같은 기능을 수행한다. npm의 단점(속도, 안정성, 보안성 등)을 보완하기 위해 만들어졌다.

npm은 패키지를한 번에 하나씩 순차적으로 설치하는 반면, yarn은 여러 패키지를 동시에 가져오고 설치하므로 yarn이 더 빠르다.
npm은 자동으로 패키지에 포함된 다른 패키지의 코드를 실행한다 ➡️ 이는 편리하지만 안정성을 위협한다.
yarn은 yarn.lock 또는 package.json 파일에 있는 파일만을 설치하며, yarn.lock은 모든 디바이스에 같은 패키지를 설치하는 것을 방지하기 때문에 버전의 차이로 인해 생기는 버그를 방지할 수 있다.

6. JSX

자바스크립트 확장 문법으로 xml과 비슷한 형태이다.
코드가 번들링되는 과정에서 바벨을 사용하여 일반 자바스크립트 형태로 변환한다.

JSX의 특징

  • 보기 쉽고 익숙하다.
  • 활용도가 높다. (html 태그/컴포넌트 사용 가능)
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css➡️
import App from './App';

ReactDom.render( // 컴포넌트를 페이지에 렌더링하는 역할. react-dom을 불러와서 사용
  <React.StrictMode> // 리액트의 레거시 기능(정상적이지 않은)을 사용하지 못하게 함
    <App/>
  </React.StrictMode>,
  document.getElementById('root')
  );

  • JSX는 꼭 하나의 DOM 트리 구조로 이루어져야한다.
  • JSX 내부 자바스크립트 표현식에서는 if문 사용이 불가능하다. (삼항연산자로 대체)
  • && 연산자를 이용하면 조건부 렌더링이 가능하다.
import React from 'react';

function App() {
  const name = '리액트';
  return <div>{name == '리액트' && <h1>리액트입니다.</h1>}</div>;
  
export default App;

0개의 댓글