[새싹] 현대IT&E 231122 기록 - React

최정윤·2023년 11월 22일
0

새싹

목록 보기
27/67
post-custom-banner

React 기본

npm

  • node.js의 기본 패키지 관리자이다. 다양한 패키지 사이의 의존성 및 버전 정보를 관리한다.
  • 프로젝트 패키지 관련 정보는 "package.json"파일에 저장된다.
  • 패키지를 재활용하기 위해 프로젝트별 "./node_moduls/"로컬 폴더에 다운로드 받아 설치된다.
  • 주요 npm 명령어
    • install: 패키지를 설치한다. 글로벌로 설치된다. packge.json 파일이 있는 경우 파일 정보를 이용하여 설치한다.
    • init: 패키지관리에 필요한 package.js를 생성한다.
    • uninstall: 패키지를 삭제한다.
    • list: 설치된 패키지 목록을 확인한다.
    • update: 패키지를 업데이트한다. 패키지명을 생략하면 모두 업데이트 된다.
    • cache: 캐쉬를 확인한다. clean --force를 이용하여 삭제한다.
    • rebuild: 패키지를 재설치한다.

CRA

  • react의 개발 환경을 자동으로 설정하여, 개발에 집중할 수 있도록 한다.
  • 폴더 구조
    • public: 컴파일이 필요 없는 정적인 파일이 저장되는 폴더
    • sr: 컴파일 되어 실행되는 소스와 컴포넌트 및 관련된 파일 저장되는 폴더
    • node_modules: Nodejs가 이용되는 패키지가 설치된 폴더
    • /package.json: 프로젝트, 패키지 등 프로젝트에 관련된 정보가 있는 설정 파일

폴더 구조

  • 일반적으로 리액트로 개발할 경우 다음과 같이 폴더를 생성한 뒤 소스를 분류하여 진행한다.
  • 주로 컴포넌트와 관련된 소스가 많이 생성되어, "src"폴더 위주로 분류가 생성된다.
  • src 폴더 기준
    • components: 재사용 가능한 공통 컴포넌트와 관련 파일이 컴포넌트별 폴더로 관리된다.
    • pages: 페이지별로 사용되는 컴포넌트와 관련 파일이 페이지 폴더별로 관리된다.
    • store: 상태관리 라이브러리(Redux)와 관련된 코드가 관리된다. context로 하기도 한다.
    • utils: 공통 유틸리티가 관리된다.
    • assets: 이미지, 스타일시트, 폰트등 폴더별로 자원이 관리된다.
    • services: API등 외부 연동 서비스에 관련된 기능이 관리된다.
    • hooks: 사용자화 훅을 관리한다.
  • npm run eject
    • CRA(create-react-app)가 자동으로 설정하고 노출 시키지 않은 환경 설정을 수정할 수 있게 활성화한다.
    • config와 scripts 폴더가 생성되고 관련 파일들이 생성된다. 기본적으로 한 번 실행하면 되돌리기가 힘들다.
    • 환경 설정을 잘못 할 경우 개발 및 실행에 문제를 일으키기 때문에 될 수 있으면 수정하지 않는다.

실행

  • index.js 는 index.html과 App.js를 이용하여 화면을 렌더링(Rendering)하여 출력을 한다.
    • index.html
      • 리액트가 이용할 DOM 컨테이너(Container)를 제공한다.
    • App.js
      • 컴포넌트이다. DOM 컨테이너에서 생성될 요소객체(Element Object)등이 선언된다.
    • index.js
      • 컴포넌트를 이용하여 DOM 컨테이너에 요소객체를 생성하고, DOM에 요소 변경 내용을 추가 또는 수정, 삭제한다.

단계별 명령어

  • 설치
$ npm install -g npm
$ npx create-react-app react-app
  • 실행
$ react-app> npm start
  • 배포
$ react-app> npm run build

모듈(Module)

  • 함수나 코드로 구성된 프로그램의 기능적 단위이다. 애플리케이션의 구성요소이며, 자바스크립트의 경우 파일 단위로 생성한다.
  • 모듈내 함수나 변수는 모듈 스코프(Module Scope)가 적용되고, export로 지정하지 않는 이상 보호된다.
  • 애플리케이션을 기능 단위로 분류하여 복잡성과 코드 간의 정적인 의존성을 최소화하여 재사용성 및 유지보수가 용이해 진다.
  • Node.js는 CommonJS, ECMAScript 모듈 사양을 지원한다. CommonJS 모듈 사양이 기본이다.

모듈 탐색

  • 파일 경로가 지정된 경우 파일의 위치를 상대 경로를 기본으로 탐색한다. 확장자는 생략 가능하다.
    • import App from './App.js';
  • Node.js의 코어 모듈인지 확인한다.
    • import http from 'http';
  • 코어 모듈이 아닌 경우 node_modules 폴더를 기준으로 파일 또는 하위 경로를 탐색한다.
    • import React from 'React';
  • 모듈내에 함수, 객체, 기본값 등을 외부에서 접근 가능하게 지정하고, 외부에서 참조하여 사용 가능하게 한다.

CommonJS Module(CJS Module)

  • 개요
    • CommonJS는 웹 브라우저에서 사용에 머물던 JavaScript 생태계를 서버, 데스크탑 등으로 확장
      하여 응용 프로그램을 개발하기 위해 진행된 프로젝트이다.
    • ECMA 표준 사양과 별개로 Node.js 위주로 발전되어 독자적인 체계를 가지고 있다. 따라서 표준을
      준수하는 브라우저 기반 실행 환경과 완벽한 호환되지 않는다.
    • Node.js의 기본 사양으로 지속적으로 지원되어 CommonJS로 제작된 많은 패키지들을 이용할 수
      있는 장점이 있다.
    • 최근에 Node.js는 ECMA 표준 및 모듈 사양 지원을 강화하고 있다.
    • CommonJS 모듈은 동기식으로 처리된다.
  • 설정
    • 'package.json'의 'type' 속성을 'commonjs'로 지정한다. 확장자는 '.js'를 이용한다.
    • 파일 확장자를 '.cjs'로 지정한다.
  • 문법
    • require(string 모듈명) 함수
      • id 매개변수로 전달된 모듈명 또는 경로에서 지정된 모듈의 module.exports 객체를 반환한다.-
      • 처음 호출시 require.cache에 저장되어, 동일 id를 require하면 cache에 저장된 객체가 반환되어 공유한다. singleton DP와 동일한 기능을 한다.
      • 구조 분해 할당(Destructuring assignment)을 하는 경우 export에 사용된 속성명을 사용해야 한다.
      • require 문의 위치는 정해진 곳이 없다. if 문내에서도 사용 가능하다.
    • module.exports 객체
      • 함수, 객체, 값들을 module.exports 에 담아 require 함수에서 반환할 수 있게 한다.
      • exports는 module.exports의 단축어이다.
    • default를 이용하면 모호성이 발생되어 유지보수 등에서 문제가 될 확률이 높아 피하고, module.exports 를 이용하는 것을 권장한다.

n01.helloworld.js

const hello = require('./modules/helloworld/HelloWorld.js');

console.log('Hello World');
hello.hello('홍길동');

HelloWorld.js

exports.hello = function(name = '회원') {
  console.log(`${name}님 안녕하세요`);
};

n02_cjs.js

const a1 = require('#labs/cjs/cjs01.js');
console.log(a1);

const fnA2 = require('#labs/cjs/cjs02.js');
fnA2();

const objA3 = require('#labs/cjs/cjs03.js');
console.log(objA3.a);
objA3.fnA();
console.log('=================================');

// named
const mA = require('#labs/cjs/cjs04.js');
console.log(mA.a);
mA.fnA();

const {a, fnA} = require('#labs/cjs/cjs04.js'); // 객체 구조 분해 할당
console.log(a);
fnA();
console.log('=================================');

const {m_a, m_fnA} = require('#labs/cjs/cjs05.js'); // 객체 구조 분해 할당
console.log(m_a);
m_fnA();

console.log('=================================');

if (m_a > 0) {
  const a2 = require('#labs/cjs/cjs01.js');
  console.log(a2);
}

cjs01.js

module.exports = 10;

cjs02.js

module.exports = function() {
  console.log('fnA()');
};

cjs03.js

module.exports = {
  a: 10,
  fnA: function(){
    console.log('fnA');
  }
}

cjs04.js

exports.a = 'A';

exports.fnA = function () {
  console.log('fnA');
};

cjs05.jsx

const m_a = 'm_A';

function m_fnA() {
  console.log('m_fnA');
}

let a = {m_a, m_fnA, m_a2: m_a};

module.exports = a;

n03_mjs.mjs

// default
import a1 from '#labs/esm/esm01.mjs';
console.log(a1);

import fnA1 from '#labs/esm/esm02.mjs';
fnA1();

import objA from '#labs/esm/esm03.mjs';
console.log(objA.a);
objA.fnA();

console.log('================================');

// named
import * as mA from '#labs/esm/esm04.mjs';
console.log(mA.a);
mA.fnA();

import { a, fnA } from '#labs/esm/esm04.mjs'; // 객체 구조 분해 할당
console.log(a);
fnA();

import { a as a2, fnA as fnA2 } from '#labs/esm/esm04.mjs'; // 객체 구조 분해 할당
console.log(a2);
fnA2();

console.log('================================');
import { m_a, m_fnA, m_a2} from '#labs/esm/esm05.mjs'; // 객체 구조 분해 할당
console.log(m_a);
m_fnA();

import * as mB from '#labs/esm/esm05.mjs';
console.log(mB.a);
mB.m_fnA();

esm01.mjs

let a = 10;

export default a = 10;

esm02.mjs

export default function() {
  console.log('fnA()');
};

esm03.mjs

export default {
  a: 10,
  fnA: function () {
    console.log('fnA');
  },
}

esm04.mjs

export let a = 'A';

export function fnA() {
  console.log('fnA');
};

esm05.mjs

const m_a = 'm_A';

function m_fnA() {
  console.log('m_fnA');
}

export { m_a, m_fnA, m_a as m_a2 };

ECMAScript Module(ES Module, ESM)

  • 개요
    • ECMA가 ES6(ES2015)부터 웹 표준으로 지원하는 모듈관련 사양(Spec)이다. Node.js는 표준 지
      원 전에 CommonJS 모듈 사양이 이용되었다.
    • Node.js v12 부터 사용 가능하다. 하지만 babel등의 번역기를 이용하면 Node.js 버전과 상관없
      이 이용 가능하다.
    • 최근에는 ECMAScript 모듈 사용이 권장되고 있고, 지원이 강화되고 있다.
    • ES 모듈은 비동기식으로 처리된다.
  • 설정
    • 'package.json'의 'type' 속성을 'module'로 지정한다. 확장자는 '.js'를 이용한다.
    • 파일 확장자를 '.mjs'로 지정한다.
  • 문법
    • 기본적으로 commonjs와 비슷하다.
    • 최상위 스코프(Top Level)에 기술해야 한다. 코드의 제일 위에 기술하는 관례가 있다.
    • 염격 모드(use strict)가 기본이다.
    • import ~ from 모듈명 문
      • id 매개변수로 전달된 모듈명 또는 경로에서 지정된 모듈을 참조한다.
      • 동일 id를 impor하면 singleton으로 관리된다.
      • 구조 분해 할당(Destructuring assignment)을 하는 경우 export에서 사용된 속성명을 사용해야 한다.
    • export 문
      • 함수, 객체, 값들을 import 에서 접근할 수 있게 한다.
      • 내보내는 모듈은 엄격 모드(use strict)이다.
    • default는 이름에 대한 모호성이 발생되어 유지보수 등에서 문제가 될 확률이 높아 피한다.

컴포넌트

App.js

import logo from './logo.svg';
import './App.css';
import React, { useState } from 'react';

function Header(props) {
  console.log('props', props)
  return (
    <header>
      <h1><a href="/" onClick={(event)=>{
        event.preventDedault();
        props.onChangeMode();
      }}>{props.title}</a></h1>
    </header>
  )
}

function Nav(props) {
  const lis = []
  for(let i=0; i<props.topics.length; i++) {
    let t = props.topics[i];
    lis.push(<li key={t.id}>
      <a id={t.id} href={'/read/'+t.id} onClick={event=>{
        event.preventDefault();
        props.onChangeMode(Number(event.target.id));
      }}>{t.title}</a>
      </li>);
  }
  return(
    <nav>
      <ol>
        {/* <li><a href="/read/1">html</a></li>
        <li><a href="/read/1">css</a></li>
        <li><a href="/read/1">js</a></li> */}
        {lis}
      </ol>
    </nav>
  )
}

function Article(props) {
  return(
    <article>
      <h2>{props.title}</h2>
      {props.body}
    </article>
  )
}

function App() {
  const [mode, setMode] = useState('WELCOME');
  const [id, setId] = useState(null);
  const topics = [
    {id:1, title:'html', body:'html is ...'},
    {id:2, title:'css', body:'css is ...'},
    {id:3, title:'javascript', body:'javascript is ...'}
  ]
  let content = null;
  if(mode === 'WELCOME') {
    content = <Article title="Welcome" body="Hello, Web"></Article>
  } else if(mode === 'READ') {
    let title, body = null;
    for(let i=0; i<topics.length; i++){
      console.log(topics[i].id, id);
      if(topics[i].id === id) {
        title = topics[i].title;
        body = topics[i].body;
      }
    }
    content = <Article title="Welcome" body="Hello, Read"></Article>
  }
  return (
    <div className="App">
      <Header title="WEB" onChangeMode={()=>{
        setMode('WELCOME');
        alert('Header');
      }}></Header>
      <Nav topics={topics} onChangeMode={(_id)=>{
        setMode('READ');
        alert(_id);
      }}></Nav>
      {content}
      <Article title="Welcome" body="Hello, Web"></Article>
      <Article title="Hi" body="Hello, React"></Article>
      {/* <header>
        <h1><a href="/">WEB</a></h1>
      </header>
      <nav>
        <ol>
          <li><a href="/read/1">html</a></li>
          <li><a href="/read/1">css</a></li>
          <li><a href="/read/1">js</a></li>
        </ol>
      </nav>
      <article>
        <h2>Welcome</h2>
        Hello, WEB
      </article> */}
    </div>
  );
}

export default App;

개요

  • 리액트 애플리케이션의 UI를 구성하고 있는 재사용 가능한 기본 단위이다. 리액트 애
    플리케이션의 UI는 컴포넌트들의 조합으로 구성한다.
  • props를 이용하여 데이터를 받고, 일반 객체(plain object)인 리액트 엘리먼트
    (React Element)를 반환하는 것을 컴포넌트라고 한다.
  • 컴포넌트 명은 HTML Tag와 구분하기 위해 대문자로 시작하는 파스칼(Pascal)표기
    법을 따른다.
  • 리액트 요소는 주로 JSX(JavaScript XML)을 이용하여 생성한다.
  • Tag, CSS, Data, JavaScript 함수 등을 조합하여 재활용 가능한 컴포넌트로 관리할
    수 있다.
  • 컴포넌트 선언에 CommonJS, ES Module 선언 방법이 이용된다. 최근에 ES
    Module 선언 방법을 주로 이용한다.
  • UI 구성에 오픈 소스(Open Source)인 Chakra UI, Material UI, Bootstrap등을
    이용하기도 한다.
  • 기본적으로 container / presentational 패턴과 atomic 패턴을 지원한다.
    • container : 데이터와 처리에 관련된 자바스크립트 부분이다.
    • presentational : 화면 출력 부분으로 JSX 부분이다.
    • atomic : 컴포넌트를 중복을 피하기 위해 작은 단위로 나누는 구조이다.

React DOM

  • React DOM은 브라우저(Browser) DOM 구조를 투영한 React 엘리먼트(Element)
    로 구성된 Virtual DOM을 생성한다.
  • ReactDOM.render()를 이용하여 JSX등을 이용하여 Virtual DOM 생성한다.
  • 자식 요소들은 생성하기 위해서는 단일 루트 요소(Root Element)가 필요하다.
  • React 엘리먼트는 순수 자바스크립트 객체이고, 상태는 수정되지 않는 불변이다. 수
    정을 할 경우 새 요소를 생성해서 갱신한다.
  • 이전 상태와 비교해 상태가 변경된 React 엘리먼트을 기준으로 브라우저 DOM을 변
    경해 준다.

종류

  • 컴포넌트를 선언방법에 따라 클래스와 함수 컴포넌트로 구분할 수 있다.
  • 최근에는 함수를 이용한 선언 방법을 권장한다. 그러나 2019년도에 발표된 v16.8 이전까지는 클래스를 이용하여 주로 선언하였다. 따라서 클래스 컴포넌트의 이해도 필요하다.
  • 함수 컴포넌트(Function Component)
function WelcomeMsg(props) {
return <h1>안녕, {props.name}</h1>;
}
  • 클래스 컴포넌트(Class Component)
class WelcomeMsg extends React.Component {
render() { return <h1>안녕, {this.props.name}</h1> };
}

함수 컴포넌트(Function Component)

개요

  • 매개변수를 이용하여 데이터를 받을 수 있고, 리액트 엘리먼트(React Element)를 반환하는 기본
    함수가 있으면 함수 컴포넌트가 된다.
  • 매개변수명은 관례상 props를 사용한다.
  • 기본으로 내보낼 함수명은 소스 코드명와 동일하게 지정한다.
  • 리액트 v16.8 버전부터 지원된 리액트 훅(React Hook)전까지는 정적(Static)인 컴포넌트로 많이
    이용되었다.
  • 컴포넌트 내에 함수는 모듈내 최상위 스코프(Top Level Scope)에 선언한다.
    • 중첩함수(Nested Function)는 성능과 디버깅에 문제가 있어 사용하지 않는다.

props

  • 값이나 함수 등을 부모 컴포넌트에서 자식 컴포넌트로 단방향(one way)으로 전달하는 경우 사용
    된다.
  • 함수형 컴포넌트에서는 매개 변수를 이용하고, 다양한 매개 변수명을 사용 가능하나 관례적으로
    "props"(property의 줄임말)를 사용한다.
  • 불변형(immutable)으로 읽기 전용이다.
  • 배열을 이용하여 출력할 경우 key가 필요하다. key를 이용하여 리액트 요소의 고유 식별자로 이용
    되고, 리렌더링(re-rendering)에 이용되어 성능을 향상시킨다.
  • key 값은 형제 노드에서만 유일한 값이면 되고 글로벌 할 필요는 없다.
  • defaultprops
    • props가 초기화 되지 않아 undefined되는 것을 피하기 위해 미리 초기화 하는 방법이다.
    • 함수형 컴포넌트가 대세가 되면서 사용 중단 예정(deprecated )이다.

state

  • 컴포넌트의 상태를 동적 관리하기 위에 사용되는 기본 React Hooks 중 하나이다.
  • props와 다르게 컴포넌트 내부에서 관리된다.
  • useState() Hook를 이용하여 관리할 상태를 필요한 만큼 설정한다.
  • "상태값 변경함수"로 "상태값"을 변경하면, 컴포넌트가 비동기적으로 리렌더링이 된
    다.
  • 리렌더링을 효율적으로 하기 위해 변경 상태들을 순차적으로 관리하고, 일괄적으로
    적용된다.
  • 리액트는 부모에서 자식 컴포넌트 방향으로만 데이터가 흐르는 단방향(One way)이
    기본이다.
  • 필요할 경우 자식의 상태를 부모로 끌어올리는 방법인 state 끌어올리기(lifting
    state up)를 적용한다.
    • 단방향은 형제 노드들 사이에는 직접 데이터 전달이 불가능한 구조이다. 부모가 같은 형제 요소 노
      드에게 데이터를 전달하는 방법이다.
    • 자식 컴포넌트에서 이벤트가 발생되면 부모가 전달한 이벤트 핸들러를 이용하여 상태를 변경해야
      한다.
    • 리액트 요소 트리 깊이가 깊을 경우 발생되는 props drilling이 일어나면 상태 끌어올리기가 복잡
      해서 관리가 힘들어 진다. 상태관리 라이브러리인 Context, Redux등 사용을 권장한다.

이벤트

  • React 엘리먼트의 이벤트 처리는 DOM 이벤트 처리와 비슷하다. React 엘리먼트 중
    DOM 이벤트는 DOM 엘리먼트에 적용 가능하다.
  • React 컴포넌트에서 선언된 이벤트 핸들러는 이벤트로 처리되지 않고 props로 전달
    된다. 이벤트가 처리되는 DOM 엘리먼트에서 이벤트 핸들러에서 함께 처리된다.
  • 이벤트명는 카멜 케이스(camelCase)표기법으로 지정하고, 이벤트 핸들러(Event
    Handler)는 함수를 이용한다.
  • 이벤트명은 관례적으로 접두어로 'on'을 사용하고, 이벤트 핸들러는 'handle' 접두
    어를 사용한다.
  • 발생된 이벤트 정보는 합성 이벤트(SyntheticEvent)를 이용하여 확인한다. 합성 이
    벤트는 브라우저 이벤트의 래퍼(Wrapper)이다.
  • 브라우저 이벤트 정보가 필요할 경우 event.nativeEvent 속성을 이용한다.

JSX

  • JSX (JavaScript Syntax Extension, JavaScript XML)의 약자로 XML형식으로
    React 요소 트리(React Element Tree)를 생성하는 자바스크립트 확장 표현식이다.
  • React 요소를 편리하게 생성하기 위한 문법 설탕(syntactic sugar)이다.
  • 웹팩(Webpack)의 번들링(Bundling) 과정에서 바벨(Bable)에 의해 자바스크립트
    코드로 변환된다.
  • 바벨은 React.createElement()를 호출하여 컴파일 한다.

문법

  • 기본적으로 XML의 규칙을 따른다.
  • 단일 요소가 아닌 경우 최상위 루트 요소가 있어야 한다.
  • 코드는 소문자를 기본으로 하고, 리액트 사용자 컴포넌트는 대문자로 시작하는
    Pascal 표기법을 이용한다.
  • 단독 태그인 경우 반드시 스스로 닫아야(self-closing ) 한다.
  • 주석은 "{ / ~ / }"로 기술한다.
  • 시작 태그인 경우 태그 내부에서 "//" 를 이용하여 주석을 기술할 수 있다.
  • Boolean, null, undefined는 출력되지 않는다.
  • 표현식(Expression)을 "{ ~ }"를 이용하여 변수 값, 객체, 연산자, 함수호출 등의 자
    바스크립트 구문을 사용할 수 있다.
profile
개발 기록장
post-custom-banner

1개의 댓글

comment-user-thumbnail
2023년 11월 22일

안녕하세요 :) 국비지원 부트캠프 엘리스트랙입니다! 오늘도 개발 공부 열심히 하고 계시군요! 멋지십니다 :)
혹시 개발 공부하면서 기술면접에 대한 대비가 막막하시다면, 이번 기술면접 특강도 관심 가져보시면 좋을 것 같아 댓글로 행사 안내드려요~

프론트/ 백엔드 모두 실력있고, 실제 면접관으로 활동하고 계신 개발자 코치님께서 진행하시니 참여해 보세요> https://festa.io/events/4389

그럼 오늘도 화이팅입니다!🙇🏻‍♀️💪🏻

답글 달기