πŸ§—
JIN-DevNote
  • ν”„λ‘ νŠΈμ—”λ“œ μƒμ‘΄μ½”μŠ€ 3κΈ°
  • 0μ£Όμ°¨
    • 1.μ™€μΉ΄νƒ€μž„ μ„€μΉ˜
    • 2.git-training
  • 1μ£Όμ°¨
    • 1.κ°œλ°œν™˜κ²½
    • 2.Typescript
    • 3.React
    • 4.Testing Library
    • 5.Parcel & ESLint
  • 2μ£Όμ°¨
    • 1.JSX
  • 3μ£Όμ°¨
    • 1.React Component
    • 2.React State
  • 4μ£Όμ°¨
    • 1.Express
    • 2.Fetch API & Cors
    • 3.React의 hook
    • 4.useRef & Custom hook
    • 5.usehooks-ts
  • 5μ£Όμ°¨
    • 1.Tdd
    • 2.React Testing library
    • 3.MSW
    • 4.Playwright
  • 6μ£Όμ°¨
    • 1.External Store
    • 2.Tsyringe
    • 3.Redux λ”°λΌν•˜κΈ°
    • 4.usestore-ts
  • 7μ£Όμ°¨
    • 1.Routing
    • 2.Routes
    • 3.Router
    • 4.Navigation
  • 8μ£Όμ°¨
    • 1.Design System
    • 2.Style Basics
    • 3.CSS in JS
    • 4.styled-components
    • 5.props와 attrs
    • 6.Global Style & Theme
Powered by GitBook
On this page
  • JSX 없이 React λ§Œλ“€κΈ°
  • Reactμ—μ„œ JSXλ₯Ό μ‚¬μš©ν•˜λŠ” λͺ©μ 
  • Syntactic sugar
  • λŒ€ν‘œμ μΈ Syntactic sugar
  • React.createElement
  • React Element
  • React StrictMode
  • VDOM(Virtual DOM)μ΄λž€?
  • DOMμ΄λž€?
  • DOMκ³Ό Virtual DOM의 차이
  • Reconciliation(μž¬μ‘°μ •) 과정은 무엇인가?
  1. 2μ£Όμ°¨

1.JSX

JSX(JavaScript XML)λŠ” Javascript에 XML을 μΆ”κ°€ν•œ ν™•μž₯ν•œ 문법이닀.

JSX 없이 React λ§Œλ“€κΈ°

main.ts

import React from 'react';
import ReactDOM from 'react-dom/client';

import App from './App';

function main() {
  const container = document.getElementById('root');
  if (!container) {
    return;
  }

  const root = ReactDOM.createRoot(container);
  root.render(React.createElement(App, null));
}

main();

App.ts

import React, { useState } from 'react';

import Greeting from './components/Greeting';

type ImageProps = {
  src: string;
  alt?: string;
  width?: number;
}

function Image({ src, alt = '', width }: ImageProps) {
  return (
    React.createElement('img', { src, alt, width: width ?? 'auto' })
  );
}

export default function App() {
  const [count, setCount] = useState(0);

  const handleClick = (value: number) => {
    setCount(count + value);
  };

  return (
    React.createElement(
      'div',
      null,
      React.createElement(Greeting, { name: 'wholeman!' }),
      React.createElement(Image,
      {
        src: '/images/test.jpg',
        alt: 'Test Image',
        width: 200
      }),
      React.createElement('p', null, 'Count: ', count),
      [1, 2, 3, 4, 5].map((i) => React.createElement('button',
      { type: 'button', key: i, onClick: () => handleClick(i) },
      '+',
      i)),
    )
  );
}

components/Greeting.ts

import React from 'react';

export default function Greeting({ name }: {
  name: string;
}) {
  return (
    React.createElement('p', null, 'Hello, ', name)
  );
}

Reactμ—μ„œ JSXλ₯Ό μ‚¬μš©ν•˜λŠ” λͺ©μ 

근본적으둜, JSXλŠ” React.createElement(component, props, ...children) ν•¨μˆ˜μ— λŒ€ν•œ 문법적 섀탕을 μ œκ³΅ν•  뿐이닀.

const element = (
  <h1 className="greeting">
    Hello, world!
  </h1>
);

const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);

두 μ˜ˆμ‹œλŠ” λ™μΌν•œ 결과값을 λ‚˜νƒ€λ‚΄μ€€λ‹€.

ν•˜μ§€λ§Œ React.createElement둜 μž‘μ„±ν•˜μ˜€μ„ λ•Œ 보닀 JSXλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 훨씬 직관적이고 가독성이 μ’‹κ³  JSXλŠ” ν•˜λ‚˜μ˜ νŒŒμΌμ— μžλ°”μŠ€ν¬λ¦½νŠΈμ™€ HTML을 λ™μ‹œμ— μž‘μ„± ν•  수 μžˆλŠ” 점이 μž₯점이닀.

Syntactic sugar

μ§κ΄€μ μ΄μ§€λŠ” μ•Šμ§€λ§Œ μ½”λ“œμ˜ 양을 쀄일 수 μžˆλŠ” 문법적인 섀탕을 μ˜λ―Έν•œλ‹€.

λŒ€ν‘œμ μΈ Syntactic sugar

1. Ternary Operator(μ‚Όν•­ μ—°μ‚°μž)

  μ‚Όν•­ μ—°μ‚°μž μ‚¬μš© μ „

  setProviderList(prev => prev.map(item => (
    if (item.id === search.provider) {
      return { ...item, isChecked: !item.isChecked }
    } else {
      return item
    }
  )));


  μ‚Όν•­ μ—°μ‚°μž μ‚¬μš© ν›„

  setProviderList(prev => prev.map(item => (
    item.id === search.provider ? { ...item, isChecked: !item.isChecked } : item
  )));

  μ‚Όν•­ μ—°μ‚°μžλ₯Ό μ‚¬μš©ν•˜κ²Œ 되면 μ‚¬μš© 전보닀 훨씬 κ°„κ²°ν•˜κ²Œ μž‘μ„±μ΄ κ°€λŠ₯ν•˜λ‹€.

2. Object Spread / Array Spread (객체 μ „κ°œ / λ°°μ—΄ μ „κ°œ)

  setProviderList(prev => prev.map(item => (
    item.id === search.provider ? { ...item, isChecked: !item.isChecked } : item
  )));

  μœ„μ˜ map μ•ˆμ—μ„œ 객체의 일뢀뢄을 λ³€κ²½ν•˜κ³  싢을 λ•Œ { ...item, isChecked: !item.isChecked }
  와 같이 기쑴의 κ°μ²΄μ•ˆμ˜ 값을 μ „κ°œν•˜κ³  λ³€κ²½ν•˜κ³ μž ν•˜λŠ” 값을 λ³€κ²½ν•œλ‹€.

  const DEFAULT_CONFIG = {
    preserveWhitespace: true,
    noBreaks: false,
    foo: "bar",
  };

  const USER_CONFIG = {
    noBreaks: true,
  }

  const config = { ...DEFAULT_CONFIG, ...USER_CONFIG };

  μœ„μ™€ 같이 두 객체λ₯Ό λͺ¨λ‘ μ „κ°œν•΄μ„œ ν•˜λ‚˜μ˜ 객체둜 λ³€κ²½ν•˜λŠ” 것도 κ°€λŠ₯ν•˜λ‹€. μ΄λ•Œ 같은 key 값에 valueκ°€
  λ‹€λ₯Ό 경우 뒀에 λ“€μ–΄μ˜€λŠ” 객체의 κ°’μœΌλ‘œ λ³€ν™˜λœλ‹€.

  배열도 객체의 μ˜ˆμ œμ™€ λ™μΌν•˜κ²Œ μ „κ°œ ν›„ ν•˜λ‚˜μ˜ λ°°μ—΄λ‘œ λ³‘ν•©ν•˜λŠ”κ²Œ κ°€λŠ₯ν•˜λ‹€. λ‹€λ§Œ λ°°μ—΄μ˜ κ²½μš°λŠ” keyκ°€ μ—†κΈ°
  λ•Œλ¬Έμ— 각각 λ‹€λ₯Έ 배열을 μ „κ°œν•΄μ„œ 병합 ν•  λ•Œ μ€‘λ³΅λ˜λŠ” 값도 λͺ¨λ‘ λ“€μ–΄κ°€κ²Œ λœλ‹€.

  const arr1 = ['a', 'b', 'c'];
  const arr2 = ['c', 'd', 'e'];
  const arr3 = [...arr1, ...arr2];
  // console.log(arr3) => ['a', 'b', 'c', 'c', 'd', 'e']

3. Object Destructuring / Array Destructuring (객체 ꡬ쑰 λΆ„ν•΄ ν• λ‹Ή / λ°°μ—΄ ꡬ쑰 λΆ„ν•΄ ν• λ‹Ή)

  export default function LectureBody({ classroomLecture }: Props): ReactElement {

    const {
      moduleList, classroomId, lastSectionId, lastSectionType,
    } = classroomLecture;
  ...
  }

  μ»΄ν¬λ„ŒνŠΈ props둜 전달받은 객체λ₯Ό ꡬ쑰 λΆ„ν•΄ν•˜μ—¬ ν•„μš”ν•œ κ°’λ§Œ μ‚¬μš©ν•  수 μžˆλ‹€.

  // 이름과 성을 μš”μ†Œλ‘œ κ°€μ§„ λ°°μ—΄
  let arr = ["Bora", "Lee"]

  // ꡬ쑰 λΆ„ν•΄ 할당을 μ΄μš©ν•΄
  // firstNameμ—” arr[0]을
  // surnameμ—” arr[1]을 ν• λ‹Ήν•˜μ˜€λ‹€.
  let [firstName, surname] = arr;

  배열도 λ§ˆμ°¬κ°€μ§€λ‘œ ꡬ쑰 λΆ„ν•΄ν•˜μ—¬ λ³€μˆ˜λ‘œ ν• λ‹Ήν•˜μ—¬ μ‚¬μš© ν•  수 μžˆλ‹€.

  // 두 번째 μš”μ†ŒλŠ” ν•„μš”ν•˜μ§€ μ•ŠμŒ
  let [firstName, , title] = ["Julius", "Caesar", "Consul", "of the Roman Republic"];

  alert( title ); // Consul

  μΆ”κ°€λ‘œ ν•„μš”ν•˜μ§€ μ•Šμ€ λ°°μ—΄μ˜ 값은 μ‰Όν‘œλ₯Ό μ‚¬μš©ν•˜μ—¬ μš”μ†Œλ₯Ό 버릴 수 μžˆλ‹€.

4. Object Rest / Array Rest (객체 λ‚˜λ¨Έμ§€ μ—°μ‚°μž, λ°°μ—΄ λ‚˜λ¨Έμ§€ μ—°μ‚°μž)

  const {
    moduleList, classroomId, lastSectionId, lastSectionType, ...rest,
  } = classroomLecture;

  let [name1, name2, ...rest] = ['a', 'b', 'c', 'c', 'd', 'e'];

  console.log(rest); // ['c', 'c', 'd', 'e'];

  restλŠ” λ‚˜λ¨Έμ§€ λ°°μ—΄ μš”μ†Œλ“€μ΄ μ €μž₯된 μƒˆλ‘œμš΄ 배열이 λœλ‹€.
  rest λŒ€μ‹ μ— λ‹€λ₯Έ 이름을 μ‚¬μš©ν•΄λ„ λ˜λŠ”λ°, λ³€μˆ˜ μ•žμ˜ 점 μ„Έ 개(...)와 λ³€μˆ˜κ°€ κ°€μž₯ λ§ˆμ§€λ§‰μ— μœ„μΉ˜ν•΄μ•Ό ν•œλ‹€.

  function sum(...theArgs) {
    let total = 0;
    for (const arg of theArgs) {
      total += arg;
    }
    return total;
  }

  console.log(sum(1, 2, 3));
  // Expected output: 6

  console.log(sum(1, 2, 3, 4));
  // Expected output: 10

  ν•¨μˆ˜μ˜ λ§€κ°œλ³€μˆ˜λ₯Ό 전달 ν• λ•Œλ„ μ‚¬μš©μ΄ κ°€λŠ₯ν•˜λ‹€.

5. Nullish coalescing (null 병합 μ—°μ‚°μž)

κΈ°μ‘΄ 문법
const name = user.name || 'Guest';

null 병합 μ—°μ‚°μž 문법
const name = user.name ?? 'Guest';

κΈ°μ‘΄ λ¬Έλ²•μ˜ 경우 μ‘΄μž¬ν•˜μ§€ μ•Šκ±°λ‚˜ null, undefined, 0 λ˜λŠ” 빈 λ¬Έμžμ—΄κ³Ό 같은 잘λͺ»λœ 값이 μžˆλŠ” 경우 κΈ°λ³Έκ°’ 'Guest'κ°€ name λ³€μˆ˜μ— ν• λ‹Ήλœλ‹€.

κ·ΈλŸ¬λ‚˜ μ΄λŸ¬ν•œ κΈ°μ‘΄ λ¬Έλ²•μ˜ μ ‘κ·Ό 방식은 name 속성이 μ‘΄μž¬ν•˜μ§€λ§Œ 잘λͺ»λœ 값을 κ°€μ§€κ³  μžˆμ–΄λ„ 기본값을 ν• λ‹Ήν•œλ‹€λŠ” 단점이 μžˆλ‹€.

null 병합 μ—°μ‚°μž(??)λŠ” νŠΉλ³„νžˆ null λ˜λŠ” undefined κ°’λ§Œ ν™•μΈν•˜λŠ” κΈ°μ‘΄ ꡬ문의 λŒ€μ•ˆμ΄λ‹€. 값이 null λ˜λŠ” undefined인 κ²½μš°μ—λ§Œ 기본값을 ν• λ‹Ήν•˜κ³  값이 falsy인 κ²½μš°μ—λŠ” ν• λ‹Ήν•˜μ§€ μ•ŠλŠ”λ‹€.

5. Arrow function (ν™”μ‚΄ν‘œ ν•¨μˆ˜)

function add(a, b) {
  return a + b;
}

const add = (a, b) => a + b;

ν™”μ‚΄ν‘œ ν•¨μˆ˜λŠ” function ν‚€μ›Œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” λŒ€μ‹  ν™”μ‚΄ν‘œ(=>)λ₯Ό μ‚¬μš©ν•˜μ—¬ ν•¨μˆ˜λ₯Ό κ°„κ²°ν•˜κ²Œ μ •μ˜ν•  수 μžˆλ‹€.

6. Template literals(ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄)

const name = 'John';
console.log('Hello, ' + name + '!');

const name = 'John';
console.log(`Hello, ${name}!`);

ν…œν”Œλ¦Ώ λ¦¬ν„°λŸ΄μ„ μ‚¬μš©ν•˜λ©΄ μž‘μ€λ”°μ˜΄ν‘œλ‚˜ ν°λ”°μ˜΄ν‘œ λŒ€μ‹  λ°±ν‹±(`)을 μ‚¬μš©ν•˜μ—¬ λ¬Έμžμ—΄μ„ μ •μ˜ν•  수 μžˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ λ¬Έμžμ—΄ μ•ˆμ— λ³€μˆ˜μ™€ ν‘œν˜„μ‹μ„ 더 μ‰½κ²Œ 포함할 수 μžˆλ‹€.

7. Optional chaining(선택적 μ—°κ²°)

// κΈ°μ‘΄ 문법
const person = { name: 'John', address: { city: 'New York' } };
const city = person.address && person.address.city;

// Optional chaining 문법
const person = { name: 'John', address: { city: 'New York' } };
const city = person.address?.city;

Optional chaining을 μ‚¬μš©ν•˜λ©΄ 객체의 쑴재 여뢀에 λŒ€ν•œ κ±±μ • 없이 객체의 속성에 μ•‘μ„ΈμŠ€ν•  수 μžˆλ‹€. 속성이 μ •μ˜λ˜μ§€ μ•Šμ€ 경우 였λ₯˜λ₯Ό λ°œμƒμ‹œν‚€λŠ” λŒ€μ‹  κ²°κ³Όκ°€ μ •μ˜λ˜μ§€ μ•Šλ‹€

μœ„μ˜ λ‚΄μš© 말고 λ°°μ—΄ λ§€μ†Œλ“œλ„ λŒ€ν‘œμ μΈ 문법적인 섀탕에 ν¬ν•¨λœλ‹€.

const arr = [1, 2, 3, 4, 5];
const doubled = arr.map(x => x * 2);
const evens = arr.filter(x => x % 2 === 0);
const sum = arr.reduce((acc, x) => acc + x, 0);

React.createElement

React.createElementλŠ” Reactμ—μ„œ κ°€μž₯ 기본적인 μ»΄ν¬λ„ŒνŠΈ 생성 방법 쀑 ν•˜λ‚˜μ΄λ‹€. 이 ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ React μš”μ†Œλ₯Ό μƒμ„±ν•˜κ³  이λ₯Ό λ Œλ”λ§ν•  수 μžˆλ‹€.

React.createElement ν•¨μˆ˜λŠ” μ„Έ 개의 μΈμˆ˜κ°€ ν•„μš”ν•˜λ‹€.

  1. μš”μ†Œμ˜ μœ ν˜• (λ¬Έμžμ—΄ λ˜λŠ” μ»΄ν¬λ„ŒνŠΈ ν•¨μˆ˜)

  2. μš”μ†Œμ˜ 속성 (λ˜λŠ” "props") λ˜λŠ” null

  3. μžμ‹ μš”μ†Œλ“€

React.createElement('div', { className: 'test' }, 'Hello, World!')

μœ„ μ½”λ“œλŠ” μ•„λž˜μ™€ 같은 React μš”μ†Œλ₯Ό λ§Œλ“€μ–΄λ‚Έλ‹€.

<div className="test">Hello, World!</div>

React.createElement ν•¨μˆ˜λŠ” μ»΄ν¬λ„ŒνŠΈ ν•¨μˆ˜λ₯Ό 첫 번째 인수둜 μ‚¬μš©ν•  μˆ˜λ„ μžˆλ‹€. 이 경우 ν•¨μˆ˜ 이름을 λ¬Έμžμ—΄λ‘œ μ „λ‹¬ν•˜κ±°λ‚˜ ES6의 ν™”μ‚΄ν‘œ ν•¨μˆ˜ ꡬ문을 μ‚¬μš©ν•˜μ—¬ 직접 ν•¨μˆ˜λ₯Ό 전달할 수 μžˆλ‹€. λ˜ν•œ 속성 및 μžμ‹ μš”μ†Œλ“€μ€ μ»΄ν¬λ„ŒνŠΈ ν•¨μˆ˜μ˜ 인수둜 μ „λ‹¬λœλ‹€.

function MyComponent(props) {
  return React.createElement('div', { className: 'test' }, props.message);
}

React.createElement(MyComponent, { message: 'Hello, World!' });
<div className="test">Hello, World!</div>

React Element

interface ReactElement<P = any, T extends string | JSXElementConstructor<any> = string | JSXElementConstructor<any>> {
  type: T;
  props: P;
  key: Key | null;
}

React Element의 속성(property)

  • type: μš”μ†Œμ˜ μœ ν˜•, 예λ₯Ό λ“€μ–΄ "div" λ˜λŠ” μ‚¬μš©μž μ§€μ • μ»΄ν¬λ„ŒνŠΈ ν•¨μˆ˜μ΄λ‹€.

  • props: μš”μ†Œμ˜ 속성, 예λ₯Ό λ“€μ–΄ className, style, onClick λ“±μ˜ 속성이 ν¬ν•¨λœλ‹€.

  • key: μ»΄ν¬λ„ŒνŠΈκ°€ μ—…λ°μ΄νŠΈλ  λ•Œ Reactκ°€ μš”μ†Œλ₯Ό μ‹λ³„ν•˜λŠ” 데 μ‚¬μš©λ˜λŠ” κ³ μœ ν•œ μ‹λ³„μžμ΄λ‹€.

  • ref: React μš”μ†Œμ— λŒ€ν•œ μ°Έμ‘°(reference)λ₯Ό λ§Œλ“œλŠ” 데 μ‚¬μš©λœλ‹€.

React ElementλŠ” Reactμ—μ„œ λ Œλ”λ§λ˜λŠ” κ°€μž₯ μž‘μ€ λ‹¨μœ„μ΄κ³ , JavaScript 객체둜, React μš”μ†Œλ₯Ό λ‚˜νƒ€λ‚Έλ‹€. React μš”μ†ŒλŠ” 화면에 λ Œλ”λ§λ˜λŠ” μš”μ†Œλ₯Ό λ‚˜νƒ€λ‚΄λ©°, λ‹€λ₯Έ React μš”μ†Œλ“€κ³Ό κ²°ν•©ν•˜μ—¬ React μ»΄ν¬λ„ŒνŠΈλ₯Ό λ§Œλ“œλŠ” 데 μ‚¬μš©λœλ‹€.

React ElementλŠ” λΆˆλ³€κ°μ²΄(immutable object)이며, ν•œ 번 μƒμ„±λ˜λ©΄ μˆ˜μ •λ  수 μ—†λ‹€. μ΄λŸ¬ν•œ λΆˆλ³€μ„±μ€ React의 μ„±λŠ₯을 ν–₯μƒμ‹œν‚€λŠ” 데 κΈ°μ—¬ν•˜λŠ”λ° ReactλŠ” λ³€ν™”κ°€ ν•„μš”ν•œ 경우 μƒˆλ‘œμš΄ React Elementλ₯Ό λ§Œλ“€κ³  기쑴의 Element와 μƒˆ Elementλ₯Ό λΉ„κ΅ν•˜μ—¬ μ΅œμ†Œν•œμ˜ λ³€κ²½λ§Œ μ μš©ν•˜λ―€λ‘œ λ Œλ”λ§ μ„±λŠ₯을 ν–₯μƒμ‹œν‚¨λ‹€.

React StrictMode

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ 잠재적인 문제λ₯Ό 미리 κ°μ§€ν•˜κ³  ν•΄κ²°ν•  수 μžˆλ„λ‘ λ„μ™€μ£ΌλŠ” 도ꡬ StrictModeλŠ” 개발 λͺ¨λ“œμ—μ„œλ§Œ λ™μž‘ν•˜λ©°, λΈŒλΌμš°μ €μ—μ„œλŠ” μ•„λ¬΄λŸ° 영ν–₯을 λ―ΈμΉ˜μ§€ μ•ŠλŠ”λ‹€.

StrictModeλ₯Ό ν†΅ν•΄μ„œ 얻을 수 μžˆλŠ” 효과

  • λΆ€μˆ˜νš¨κ³Ό 검사: React μ»΄ν¬λ„ŒνŠΈμ—μ„œ λΆ€μˆ˜νš¨κ³Ό(일반적으둜 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œ, useEffect λ“±)λ₯Ό μ‚¬μš©ν•  λ•Œ κ²½κ³  λ©”μ‹œμ§€λ₯Ό 좜λ ₯ν•˜μ—¬ 잠재적인 문제λ₯Ό 감지할 수 μžˆλ‹€.

  • λ ˆκ±°μ‹œ λ¬Έμžμ—΄ ref κ²½κ³ : λ¬Έμžμ—΄μ„ μ‚¬μš©ν•˜μ—¬ refλ₯Ό μƒμ„±ν•˜λ©΄ κ²½κ³  λ©”μ‹œμ§€κ°€ ν‘œμ‹œλœλ‹€. λ¬Έμžμ—΄ refλŠ” 더 이상 ꢌμž₯λ˜μ§€ μ•ŠμœΌλ©°, ν•¨μˆ˜λ₯Ό μ‚¬μš©ν•˜μ—¬ refλ₯Ό μƒμ„±ν•˜λŠ” 것이 μ’‹λ‹€.

  • λ ˆκ±°μ‹œ 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œ κ²½κ³ : λ ˆκ±°μ‹œ 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œ(componentWillMount, componentWillReceiveProps, componentWillUpdate)λ₯Ό μ‚¬μš©ν•˜λ©΄ κ²½κ³  λ©”μ‹œμ§€κ°€ ν‘œμ‹œλœλ‹€. μ΄λŸ¬ν•œ λ©”μ„œλ“œλŠ” 더 이상 ꢌμž₯λ˜μ§€ μ•ŠμœΌλ©°, λŒ€μ‹ μ— componentDidMount, componentDidUpdate, getDerivedStateFromProps 및 getSnapshotBeforeUpdate λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

  • μ•ˆμ „ν•˜μ§€ μ•Šμ€ 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œ κ²½κ³ : μ•ˆμ „ν•˜μ§€ μ•Šμ€ 생λͺ…μ£ΌκΈ° λ©”μ„œλ“œ(UNSAFE_componentWillMount, UNSAFE_componentWillReceiveProps, UNSAFE_componentWillUpdate)λ₯Ό μ‚¬μš©ν•˜λ©΄ κ²½κ³  λ©”μ‹œμ§€κ°€ ν‘œμ‹œλœλ‹€. μ΄λŸ¬ν•œ λ©”μ„œλ“œλŠ” ν–₯ν›„ React μ—…λ°μ΄νŠΈμ—μ„œ μ‚­μ œλ  μ˜ˆμ •μ΄λ©°, λŒ€μ‹ μ— getDerivedStateFromProps 및 getSnapshotBeforeUpdate λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•˜λŠ” 것이 μ’‹λ‹€.

StrictModeλ₯Ό μ‚¬μš©ν•˜λ©΄ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ°œμƒν•  수 μžˆλŠ” 잠재적인 문제λ₯Ό 쑰기에 감지할 수 μžˆμœΌλ―€λ‘œ, React μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 개발 및 μœ μ§€λ³΄μˆ˜λ₯Ό 보닀 μ•ˆμ „ν•˜κ²Œ μˆ˜ν–‰ν•  수 μžˆλ‹€.

VDOM(Virtual DOM)μ΄λž€?

Virtual DOM(가상 DOM)은 React의 핡심 κ°œλ… 쀑 ν•˜λ‚˜μ΄λ‹€. Virtual DOM은 λΈŒλΌμš°μ €κ°€ 직접 μ‘°μž‘ν•˜λŠ” μ‹€μ œ DOMκ³ΌλŠ” λ³„λ„λ‘œ, JavaScript 객체둜 이루어진 객체 λͺ¨λΈμ΄λ‹€.

Reactμ—μ„œ μ»΄ν¬λ„ŒνŠΈκ°€ μ—…λ°μ΄νŠΈλ  λ•Œ, μ‹€μ œ DOM을 μ‘°μž‘ν•˜λŠ” 것이 μ•„λ‹ˆλΌ, Virtual DOM을 μ—…λ°μ΄νŠΈν•˜κ³ , 이전과 μƒˆλ‘œμš΄ Virtual DOM을 λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ λΆ€λΆ„λ§Œ μ‹€μ œ DOM에 μ μš©ν•œλ‹€. 이λ₯Ό 톡해 DOM μ‘°μž‘ 횟수λ₯Ό μ΅œμ†Œν™”ν•˜κ³ , λΉ λ₯Έ λ Œλ”λ§μ„ κ΅¬ν˜„ν•  수 μžˆλ‹€.

Reactμ—μ„œλŠ” μ΄λŸ¬ν•œ Virtual DOM을 κ΅¬ν˜„ν•˜κ³ , 각 μ»΄ν¬λ„ŒνŠΈμ˜ μƒνƒœμ™€ 속성이 변경될 λ•Œλ§ˆλ‹€ Virtual DOM을 μ—…λ°μ΄νŠΈν•˜κ³ , λ³€κ²½λœ λΆ€λΆ„λ§Œ μ΅œμ ν™”λœ λ°©μ‹μœΌλ‘œ μ‹€μ œ DOM에 μ μš©ν•˜μ—¬ UIλ₯Ό μ—…λ°μ΄νŠΈν•œλ‹€.

DOMμ΄λž€?

DOM(Document Object Model)은 λΈŒλΌμš°μ €μ—μ„œ μ›Ή νŽ˜μ΄μ§€μ˜ HTML λ¬Έμ„œλ₯Ό λ‘œλ“œν•˜κ³  νŒŒμ‹±ν•œ 결과물을 λ‚˜νƒ€λ‚΄λŠ” 객체 λͺ¨λΈμ΄λ‹€. 즉, HTML, XML λ˜λŠ” XHTML λ¬Έμ„œλ₯Ό λΈŒλΌμš°μ €κ°€ 이해할 수 μžˆλŠ” 객체 λͺ¨λΈλ‘œ λ³€ν™˜ν•˜μ—¬(HTML λ¬Έμ„œλ₯Ό μ΄λ£¨λŠ” λͺ¨λ“  μš”μ†Œλ“€μ€ 객체둜 ν‘œν˜„λ˜λ©°, μ΄λŸ¬ν•œ 객체듀은 μ„œλ‘œ 계측적인 관계λ₯Ό κ°€μ§€κ³  μžˆλ‹€.), μžλ°”μŠ€ν¬λ¦½νŠΈλ₯Ό μ‚¬μš©ν•˜μ—¬ λ¬Έμ„œμ˜ ꡬ쑰, μŠ€νƒ€μΌ, μ½˜ν…μΈ  등을 λ™μ μœΌλ‘œ μ‘°μž‘ν•  수 있게 ν•œλ‹€.

DOM과 Virtual DOM의 차이

DOM은 λΈŒλΌμš°μ €μ—μ„œ 직접 μ‘°μž‘λ˜λŠ” μ‹€μ œ κ°μ²΄μ΄λ―€λ‘œ, DOM μ‘°μž‘ μž‘μ—…μ€ λΈŒλΌμš°μ €μ˜ μ„±λŠ₯을 크게 μ €ν•˜μ‹œν‚¬ 수 μžˆλ‹€.

반면, Virtual DOM은 Reactμ—μ„œ λ‚΄λΆ€μ μœΌλ‘œ κ΄€λ¦¬λ˜λŠ” κ²ƒμœΌλ‘œ, λΈŒλΌμš°μ €κ°€ 직접 μ‘°μž‘ν•˜μ§€ μ•ŠμœΌλ―€λ‘œ DOM μ‘°μž‘ μž‘μ—…μ˜ λΉ„μš©μ„ 크게 μ ˆκ°ν•  수 μžˆλ‹€.

Reconciliation(μž¬μ‘°μ •) 과정은 무엇인가?

Reactμ—μ„œ Reconciliation(μž¬μ‘°μ •)은 Virtual DOMμ—μ„œ μ΄λ£¨μ–΄μ§€λŠ” κ³Όμ •μœΌλ‘œ, 이전 μƒνƒœμ™€ ν˜„μž¬ μƒνƒœμ˜ Virtual DOM을 λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ λΆ€λΆ„λ§Œ μ‹€μ œ DOM에 μ—…λ°μ΄νŠΈν•˜λŠ” 과정이닀.

Reconciliation은 Virtual DOM의 λ…Έλ“œλ₯Ό μˆœνšŒν•˜λ©° 이전 μƒνƒœμ™€ λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ 뢀뢄을 μ°ΎλŠ”λ‹€. 이 κ³Όμ •μ—μ„œ ReactλŠ” 효율적으둜 비ꡐλ₯Ό μˆ˜ν–‰ν•˜κΈ° μœ„ν•΄ λ‹€μ–‘ν•œ μ΅œμ ν™” κΈ°μˆ μ„ μ‚¬μš©ν•œλ‹€. 예λ₯Ό λ“€μ–΄, 같은 μ»΄ν¬λ„ŒνŠΈκ°€ μ—¬λŸ¬ 번 λ Œλ”λ§λ  λ•Œ, ReactλŠ” 이전 λ Œλ”λ§ 결과와 ν˜„μž¬ λ Œλ”λ§ κ²°κ³Όλ₯Ό λΉ„κ΅ν•˜μ—¬ λ³€κ²½λœ λΆ€λΆ„λ§Œ μ—…λ°μ΄νŠΈν•œλ‹€.

Reconciliation의 이점은 μ„±λŠ₯κ³Ό μ‚¬μš©μž κ²½ν—˜ κ°œμ„ μ΄λ‹€. ReactλŠ” Virtual DOM을 μ‚¬μš©ν•˜μ—¬ λ³€κ²½λœ λΆ€λΆ„λ§Œ λ Œλ”λ§ν•˜λ―€λ‘œ, ν•„μš”ν•œ μ΅œμ†Œν•œμ˜ DOM μ‘°μž‘λ§Œ μˆ˜ν–‰λ˜μ–΄ μ„±λŠ₯이 ν–₯μƒλ˜κ³ , λ³€κ²½λœ λΆ€λΆ„λ§Œ μ—…λ°μ΄νŠΈλ˜λ―€λ‘œ, λΆˆν•„μš”ν•œ ν™”λ©΄ κΉœλΉ‘μž„μ„ λ°©μ§€ν•˜κ³  μ‚¬μš©μž κ²½ν—˜μ„ κ°œμ„ ν•  수 μžˆλ‹€.

Aha Moment

μ „κ°œ ꡬ문에 λŒ€ν•΄μ„œ MDN을 ν™•μΈν–ˆμ„ λ•Œ μ•„λž˜μ™€ 같은 λ‚΄μš©μ„ μΆ”κ°€λ‘œ 확인 ν•  수 μžˆμ—ˆλ‹€.

apply() λŒ€μ²΄

일반적으둜 λ°°μ—΄μ˜ μ—˜λ¦¬λ¨ΌνŠΈλ₯Ό ν•¨μˆ˜μ˜ 인수둜 μ‚¬μš©ν•˜κ³ μž ν•  λ•Œ Function.prototype.apply() λ₯Ό μ‚¬μš©ν•˜μ˜€λ‹€.

  function myFunction(x, y, z) { }
  let args = [0, 1, 2];
  myFunction.apply(null, args);

  μ „κ°œ ꡬ문을 μ‚¬μš©ν•΄ μœ„ μ½”λ“œλŠ” λ‹€μŒκ³Ό 같이 μž‘μ„±λ  수 μžˆλ‹€.

  function myFunction(x, y, z) { }
  let args = [0, 1, 2];
  myFunction(...args);

λ°°μ—΄ 볡사

  let arr = [1, 2, 3];
  let arr2 = [...arr]; // arr.slice() 와 μœ μ‚¬
  arr2.push(4);

  // arr2 은 [1, 2, 3, 4] 이 됨
  // arr 은 영ν–₯을 λ°›μ§€ μ•Šκ³  남아 있음

λ°°μ—΄ 병합

  let arr1 = [0, 1, 2];
  let arr2 = [3, 4, 5];
  // arr2 의 λͺ¨λ“  ν•­λͺ©μ„ arr1 에 λΆ™μž„
  arr1 = arr1.concat(arr2);

  μ „κ°œ ꡬ문을 μ‚¬μš©ν•˜μ—¬ μœ„μ™€ λ™μΌν•˜κ²Œ λ³€κ²½ ν•  수 μžˆλ‹€.

  let arr1 = [0, 1, 2];
  let arr2 = [3, 4, 5];
  arr1 = [...arr1, ...arr2]; // arr1 은 이제 [0, 1, 2, 3, 4, 5]

λ°°μ—΄ 병합 및 μˆœμ„œλ³€κ²½

  let arr1 = [0, 1, 2];
  let arr2 = [3, 4, 5];
  // arr2 의 λͺ¨λ“  ν•­λͺ©μ„ arr1 의 μ•žμ— λΆ™μž„
  Array.prototype.unshift.apply(arr1, arr2) // arr1 은 이제 [3, 4, 5, 0, 1, 2] κ°€ 됨

  μ „κ°œ ꡬ문을 μ‚¬μš©ν•˜μ—¬ μœ„μ™€ λ™μΌν•˜κ²Œ λ³€κ²½ ν•  수 μžˆλ‹€.

  let arr1 = [0, 1, 2];
  let arr2 = [3, 4, 5];
  arr1 = [...arr2, ...arr1]; // arr1 은 이제 [3, 4, 5, 0, 1, 2] κ°€ 됨

μ°Έκ³ : unshift()와 달리, μ „κ°œ ꡬ문을 μ‚¬μš©μ‹œμ—λŠ” μƒˆλ‘œμš΄ arr1을 λ§Œλ“€λ©° κΈ°μ‘΄ 배열을 λ³€ν˜•ν•˜μ§€ μ•Šλ‹€.

μ „κ°œ ꡬ문이 μΆ”κ°€λ˜κ³  λ‚˜μ„œ λ°μ΄ν„°μ˜ λΆˆλ³€μ„±μ„ μœ μ§€ν•˜κΈ° 더 μš©μ΄ν•΄μ§„ 것 κ°™λ‹€κ³  생각이 λ“€μ—ˆλ‹€. μΆ”κ°€λ‘œ μ „κ°œ ꡬ문이 μ–΄λ””μ—μ„œ νŒŒμƒλ˜μ–΄μ Έ μ™”λŠ”μ§€ μ•Œ 수 μžˆλŠ” μ‹œκ°„μ΄μ—ˆλ‹€.

μ΄λ²ˆμ— λ°λΈŒλ…ΈνŠΈ ν‚€μ›Œλ“œλ₯Ό κ²€μƒ‰ν•΄λ³΄λ©΄μ„œ λŠλ‚€ 뢀뢄은 Reactκ°€ μ–΄λ–€ λ¬Έμ œμ μ„ ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œ JSXλ₯Ό λ„μž…ν•˜κ³  VDOM을 λ„μž…ν•˜κ²Œ λ˜μ—ˆλŠ”μ§€ μƒκ°ν•΄λ³΄λŠ” 계기가 λ˜μ—ˆλ˜ 것 κ°™λ‹€. ν˜„μž¬ μ‹€λ¬΄μ—μ„œ μž‘μ—…ν•˜λ©΄μ„œλ„ 이 기술이 μ™œ λ‚˜μ˜€κ²Œ λ˜μ—ˆλŠ”μ§€μ— λŒ€ν•΄μ„œ 깊게 κ³ λ―Ό 해본적이 μ—†κ³  λŒ€λž΅μ μΈ 뢀뢄에 λŒ€ν•΄μ„œλ§Œ μ•Œκ³  μžˆμ—ˆλ‹€λ©΄ μ΄λ²ˆμ— React에 λŒ€ν•œ μ „λ°˜μ μΈ λ‚΄μš©μ„ 찾아보고 μ •λ¦¬ν•˜λ©΄μ„œ React와 전보닀 더 κ°€κΉŒμ›Œμ§„ λŠλ‚Œμ΄ λ“€μ—ˆλ‹€. μ΄λ²ˆμ— μ •λ¦¬ν•œ λ…ΈνŠΈλ₯Ό 기반으둜 μ§€μ†μ μœΌλ‘œ 머릿속에 μ§‘μ–΄ λ„£λŠ” 과정을 ν†΅ν•΄μ„œ 기본을 잘 κΈ°μ–΅ν•˜λ„λ‘ ν•΄μ•Όκ² λ‹€.

Reference

Previous2μ£Όμ°¨Next3μ£Όμ°¨

Last updated 1 year ago

JSX μ΄ν•΄ν•˜κΈ°
Destructuring
Spread