Skip to content

๐Ÿ› ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด SPA๋กœ ๊ตฌํ˜„ํ•œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

Notifications You must be signed in to change notification settings

Jxxunnn/project-open-market

Folders and files

NameName
Last commit message
Last commit date

Latest commit

ย 

History

82 Commits
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 
ย 

Repository files navigation

์˜คํ”ˆ ๋งˆ์ผ“

แ„‰แ…ณแ„แ…ณแ„…แ…ตแ†ซแ„‰แ…ฃแ†บ 2023-01-05 แ„‹แ…ฉแ„Œแ…ฅแ†ซ 1 40 20

์†Œ๊ฐœ ๋ฐ ๊ฐœ์š”

๋งˆ์ผ“์— ๋“ฑ๋ก๋˜์–ด ์žˆ๋Š” ์ƒํ’ˆ์„ ๊ตฌ๋งคํ•˜๊ณ ์ž ํ•˜๋‹ค๋ฉด ์ƒํ’ˆ์˜ ์„ธ๋ถ€์‚ฌํ•ญ์„ ํ™•์ธํ•œ ๋’ค, ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋„ฃ์–ด, ์ƒํ’ˆ์„ ๊ตฌ๋งคํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

[๐Ÿ› Vanilla JavaScript๋กœ SPA ๊ตฌํ˜„ํ•˜๊ธฐ]

๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด SPA๋กœ ๊ตฌํ˜„ํ•œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

  • React๋ฅผ ์‚ฌ์šฉํ•  ๋•Œ๋Š” DOM์„ ์ง์ ‘ ์กฐ์ž‘ํ•  ์ผ์ด ๋“œ๋ฌผ์—ˆ๋Š”๋ฐ ์ด๋ฒˆ ํ”„๋กœ์ ํŠธ๋ฅผ ์ง„ํ–‰ํ•˜๋ฉด์„œ DOM ๊ตฌ์กฐ ๋ฐ ๊ด€๋ จ ํ•จ์ˆ˜๋ฅผ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.
  • ํŽ˜์ด์ง€ ๋ฆฌ๋กœ๋“œ ์—†์ด ๋ผ์šฐํŒ… ๋ณ€๊ฒฝ, root ํƒœ๊ทธ๋งŒ ์žˆ๋Š” ๊ตฌ์กฐ์—์„œ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ Œ๋”๋งํ•˜๋Š” ๋ฐฉ๋ฒ• ๋“ฑ SPA๋ฅผ ์ง์ ‘ ๊ตฌํ˜„ํ•˜๋ฉด์„œ SPA๊ฐ€ ๋™์ž‘ํ•˜๋Š” ๋ฐฉ์‹์„ ๋กœ์šฐ ๋ ˆ๋ฒจ์—์„œ ์ดํ•ดํ•  ์ˆ˜ ์žˆ์—ˆ์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ๋ฐฉ์‹

state๋ฅผ ๊ธฐ์ค€์œผ๋กœ DOM์ด ๋ Œ๋”๋ง ๋  ์ˆ˜ ์žˆ๋„๋ก state-setState-render ๊ทœ์น™์„ ์ง€์ผœ๊ฐ€๋ฉฐ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์„ค๊ณ„ํ•˜์˜€์Šต๋‹ˆ๋‹ค. URL ๋ผ์šฐํŒ… ์ฒ˜๋ฆฌ๋Š” location.pathname์„ ์ด์šฉํ•ด URL ๋ณ„๋กœ ๋ถ„๊ธฐ๋ฅผ ํƒœ์šฐ๊ณ , History API๋ฅผ ์ด์šฉํ•ด URL๋งŒ ์—…๋ฐ์ดํŠธํ•˜๋ฉด์„œ ์›น ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ์ ์ธ ํŽ˜์ด์ง€ ์ด๋™ ์ฒ˜๋ฆฌ๋ฅผ ๋ฐฉ์ง€ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

URL์˜ ๋ณ€๊ฒฝ์„ ํด๋ผ์ด์–ธํŠธ๊ฐ€ ๊ฐ์ง€ํ•˜๊ณ  ํŽ˜์ด์ง€๋ฅผ ์ƒˆ๋กœ ๊ทธ๋ฆฌ๋„๋ก ์ฒ˜๋ฆฌํ•˜๊ธฐ ์œ„ํ•ด ์ปค์Šคํ…€ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ–ˆ์Šต๋‹ˆ๋‹ค. ์žฅ๋ฐ”๊ตฌ๋‹ˆ์— ๋‹ด์€ ์ƒํ’ˆ ๋ฐ์ดํ„ฐ๋ฅผ localStorage์— ์ €์žฅํ•˜์—ฌ ํด๋ผ์ด์–ธํŠธ ๋‚ด์—์„œ ๊ธฐ๋ก๋˜๊ณ  ๋™์ž‘๋˜๊ฒŒ ํ•˜์˜€์Šต๋‹ˆ๋‹ค.

๊ตฌํ˜„ ์‚ฌํ•ญ

์ƒํ’ˆ ๋ชฉ๋ก ํŽ˜์ด์ง€

  • ๋ชฉ๋ก์—์„œ ์ƒํ’ˆ์„ ํด๋ฆญํ•˜๋ฉด ์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ์—๋Š” ์ƒํ’ˆ ํŒ๋งค์ž, ์ƒํ’ˆ๋ช…, ๊ฐ€๊ฒฉ์ด ๋ณด์—ฌ์ง‘๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ ์ข‹์•„์š” ๊ธฐ๋Šฅ์ด ํด๋ผ์ด์–ธํŠธ๋‚ด์—์„œ ๊ธฐ๋ก๋˜๊ณ  ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€

  • productId์— ํ•ด๋‹นํ•˜๋Š” ์ƒํ’ˆ์„ ๋ถˆ๋Ÿฌ์˜ค๊ณ , ํ•ด๋‹น ์ƒํ’ˆ ์ •๋ณด๋ฅผ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.
  • + ๋ฒ„ํŠผ๊ณผ - ๋ฒ„ํŠผ์„ ์‚ฌ์šฉํ•ด์•ผ๋งŒ ์ˆ˜๋Ÿ‰ ๋ณ€๊ฒฝ์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ์ˆ˜๋Ÿ‰์„ ๋ณ€๊ฒฝํ•  ๋•Œ ํ˜„์žฌ ์ƒํ’ˆ์˜ ์žฌ๊ณ  ์ˆ˜๋Ÿ‰๋˜ํ•œ ๋ณ€ํ•ฉ๋‹ˆ๋‹ค.
  • ์„ ํƒ๋œ ์˜ต์…˜์— ๋งž์ถฐ์„œ ๊ฐ€๊ฒฉ์„ ๊ณ„์‚ฐํ•˜๊ณ , ์ด ๊ฐ€๊ฒฉ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์ด๋ฏธ ์„ ํƒ๋œ ์ƒํ’ˆ์„ ๋‹ค์‹œ ์„ ํƒํ•˜์˜€์„ ๋•Œ, ์ƒํ’ˆ์€ ์ถ”๊ฐ€๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ๋ฐ”๋กœ ๊ตฌ๋งค ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ์‹œ, ๊ฒฐ์ œ ํŽ˜์ด์ง€๋กœ ๋„˜์–ด๊ฐ‘๋‹ˆ๋‹ค.
  • ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฒ„ํŠผ์„ ๋ˆŒ๋ €์„ ์‹œ, ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ ์ƒ์„ธ ํŽ˜์ด์ง€์—์„œ ์žฅ๋ฐ”๊ตฌ๋‹ˆ ์ถ”๊ฐ€ ๊ธฐ๋Šฅ์ด ํด๋ฆฌ์ด์–ธํŠธ๋‚ด์—์„œ ๊ธฐ๋ก๋˜๊ณ  ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค.

์žฅ๋ฐ”๊ตฌ๋‹ˆ / ์ฃผ๋ฌธ ๊ฒฐ์ œ ํŽ˜์ด์ง€

  • ์„ ํƒ๋œ ์ •๋ณด๋งŒ ์ด ์ƒํ’ˆ๊ธˆ์•ก๊ณผ ํ• ์ธ์ด ์ ์šฉ๋˜์–ด ์ด ๊ฒฐ์ œํ•  ๊ฐ€๊ฒฉ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์„ ํƒ๋œ ์ •๋ณด๋งŒ ์ด ์ƒํ’ˆ๊ธˆ์•ก๊ณผ ํ• ์ธ์ด ์ ์šฉ๋˜์–ด ์ด ๊ฒฐ์ œํ•  ๊ฐ€๊ฒฉ์ด ๋‚˜ํƒ€๋‚ฉ๋‹ˆ๋‹ค.
  • ์ƒํ’ˆ์˜ x ๋ฒ„ํŠผ์„ ํด๋ฆญํ•  ์‹œ ์ƒํ’ˆ์ด ์‚ญ์ œ๋ฉ๋‹ˆ๋‹ค.

ํŽ˜์ด์ง€ ํ•˜๋‹จ ๋„ค๋น„๊ฒŒ์ด์…˜ ์œ„

  • ์žฅ๋ฐ”๊ตฌ๋‹ˆ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.
  • ํ™ˆ ๋ฒ„ํŠผ์„ ๋ˆ„๋ฅด๋ฉด ์žฅ๋ฐ”๊ตฌ๋‹ˆ ํŽ˜์ด์ง€๋กœ ์ด๋™ํ•ฉ๋‹ˆ๋‹ค.

์ตœ์ข… ๊ตฌํ˜„ ํ™”๋ฉด gif

Animation2


Directory Structure

๐Ÿ“public
  โ”œโ”€๐Ÿ“„favicon.ico
  โ””โ”€๐Ÿ“„index.html
๐Ÿ“src
  โ”œโ”€๐Ÿ“components
  โ”‚   โ”œโ”€๐Ÿ“Cart
  โ”‚   โ”‚   โ””โ”€๐Ÿ“„index.js
  โ”‚   โ”‚   โ””โ”€๐Ÿ“„Order.js
  โ”‚   โ”‚   โ””โ”€๐Ÿ“„OrderList.js
  โ”‚   โ”‚   โ””โ”€๐Ÿ“„Payment.js
  โ”‚   โ”œโ”€๐Ÿ“Common
  โ”‚   โ”‚   โ”œโ”€๐Ÿ“„Anchor.js
  โ”‚   โ”‚   โ””โ”€๐Ÿ“„Header.js
  โ”‚   โ”œโ”€๐Ÿ“ProductDetail
  โ”‚   โ”‚   โ”œโ”€๐Ÿ“„Card.js
  โ”‚   โ”‚   โ”œโ”€๐Ÿ“„index.js
  โ”‚   โ”‚   โ”œโ”€๐Ÿ“„Info.js
  โ”‚   โ”‚   โ””โ”€๐Ÿ“„InfoImage.js
  โ”‚   โ””โ”€๐Ÿ“ProductList
  โ”‚       โ”œโ”€๐Ÿ“„Content.js
  โ”‚       โ”œโ”€๐Ÿ“„Contents.js
  โ”‚       โ”œโ”€๐Ÿ“„index.js
  โ”‚       โ”œโ”€๐Ÿ“„Price.js
  โ”‚       โ”œโ”€๐Ÿ“„Product.js
  โ”‚       โ””โ”€๐Ÿ“„Thumbnail.js
  โ”œโ”€๐Ÿ“pages
  โ”‚   โ”œโ”€๐Ÿ“„CartPage.js
  โ”‚   โ”œโ”€๐Ÿ“„ErrorPage.js
  โ”‚   โ”œโ”€๐Ÿ“„ProductDetailPage.js
  โ”‚   โ””โ”€๐Ÿ“„ProductListPage.js
  โ”œโ”€๐Ÿ“utils
  โ”‚   โ”œโ”€๐Ÿ“„api.js
  โ”‚   โ”œโ”€๐Ÿ“„handleLocalStorage.js
  โ”‚   โ”œโ”€๐Ÿ“„router.js
  โ”‚   โ””โ”€๐Ÿ“„toKRCurrency.js
  โ””โ”€๐Ÿ“„App.js
๐Ÿ“„index.html
๐Ÿ“„index.js
๐Ÿ“„input.css
๐Ÿ“„package-lock.json
๐Ÿ“„package.json
๐Ÿ“„README.md
๐Ÿ“„tailwind.config.js

Route

import ProductListPage from "./pages/ProductListPage.js";
import ProductDetailPage from "./pages/ProductDetailPage.js";
import CartPage from "./pages/CartPage.js";
import ErrorPage from "./pages/ErrorPage.js";
import { init } from "./utils/router.js";

export default function App({ $target }) {
  this.route = () => {
    const { pathname } = location;
    $target.innerHTML = "";

    if (pathname === "/") {
      new ProductListPage({ $target }).render();
    } else if (pathname.indexOf("/products/") === 0) {
      const [, , productId] = pathname.split("/");
      new ProductDetailPage({
        $target,
        productId,
      }).render();
    } else if (pathname === "/cart") {
      new CartPage({ $target }).render();
    } else {
      new ErrorPage({ $target }).render();
    }
  };
  init(this.route);
  this.route();
  window.addEventListener("popstate", this.route);
}

Issues

Issue #1

Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of "text/html". Strict MIME type checking is enforced for module scripts per HTML spec.

type=module๋กœ ./index.js๋ฅผ ์Šคํฌ๋ฆฝํŠธํ•˜๊ณ . import๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ ๊ฒฝ๋กœ์™€ ํ™•์žฅ์ž๋ฅผ ์ •ํ™•ํ•˜๊ฒŒ ์ ์ง€ ์•Š์•„์„œ ์ƒ๊ธด ์˜ค๋ฅ˜

index.html์— ์ƒ๋Œ€๊ฒฝ๋กœ์ธ ./์„ ์ง€์ •ํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด์—ˆ๋‹ค.

<script src="/index.js" type="module"></script>

Issue #2-1

DOM tree์•ˆ์— ์›ํ•˜๋Š” node๋“ค์„ ์ถ”๊ฐ€ํ•  ๋•Œ createElement์™€ appendChild ๋“ฑ์€ ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ์ž‘์—…์ด๊ธฐ์— ๋Œ€์•ˆ์ด ํ•„์š”ํ•˜๋‹ค. innerHTML์€ XXS(ํฌ๋กœ์Šค ์‚ฌ์ดํŠธ ์Šคํฌ๋ฆฝํŒ…) ๊ณต๊ฒฉ์— ์ทจ์•ฝํ•˜๊ณ , style ํ”„๋ ˆ์ž„์›Œํฌ๋กœ tailwind๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ์— ํŒŒ์‹ฑ์ด ๋Š๋ฆฌ๋‹ค.

์†๋„

  • insertAdjacentHTML

์ƒˆ๋กญ๊ฒŒ ์‚ฝ์ž…๋  ์š”์†Œ๋งŒ์„ ํŒŒ์‹ฑํ•˜์—ฌ innerHTML๋ณด๋‹ค ํšจ์œจ์ ์ด๊ณ  ๋น ๋ฅด์ง€๋งŒ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ XSS์— ์ทจ์•ฝํ•˜๋‹ค. ํŽ˜์ด์ง€ ๋‚ด์—์„œ ๋™์ ์œผ๋กœ ๋ฐ”๋€Œ๋Š” ์š”์†Œ๊ฐ€ ๊ฑฐ์˜ ์—†๋‹ค๊ณ  ํŒ๋‹จํ•˜์—ฌ ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ.

๋ณด์•ˆ

  • DOMPurify ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ๋ฌธ์ž์—ด์„ ํ•œ๋ฒˆ ํ•„ํ„ฐ๋งํ•ด์ฃผ๋Š” Sanitize ๊ธฐ๋Šฅ์œผ๋กœ XSS ๊ณต๊ฒฉ์— ์œ„ํ—˜์ด ๋ ๋งŒํ•œ ์š”์†Œ๋ฅผ ์ œ๊ฑฐํ•ด์ค€๋‹ค.

์ด ํ”„๋กœ์ ํŠธ๋Š” ์ˆœ์ˆ˜ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ SPA๋ฅผ ๊ตฌํ˜„ํ•ด๋ณด๋ฉฐ ์›น ์ปดํฌ๋„ŒํŠธ์™€ SPA๋ฅผ ์ดํ•ดํ•˜๊ณ ์ž ํ•˜๋Š” ๋ชฉ์ ์„ ๊ฐ€์ง€๊ณ  ์žˆ๊ธฐ์— ์‚ฌ์šฉํ•˜์ง€ ์•Š์Œ.

๋Œ€์•ˆ

  • ๋” ์ƒ์„ฑ Factory ํ•จ์ˆ˜

๋ฆฌ์•กํŠธ์˜ React.createElement(component, props, ...children)์—์„œ ์ฐฉ์•ˆํ•˜์˜€์Œ. ํ•˜์ง€๋งŒ ๋ฐ์ดํ„ฐ ๋ฐ”์ธ๋”ฉ์„ ๊ณ ๋ คํ•˜์—ฌ ํ•จ์ˆ˜๋ฅผ ์ž‘์„ฑํ•˜๊ฒŒ ๋œ๋‹ค๋ฉด ๋น„์šฉ์ด ๋งŽ์ด ๋“œ๋Š” ์ž‘์—…์ด ๋  ๊ฒƒ์ด๋ผ ์˜ˆ์ƒ ๋˜๊ธฐ์— ์ถ”ํ›„ ๋ฆฌํŒฉํ† ๋ง ๊ณผ์ •์—์„œ ๊ณ ๋ คํ•ด๋ณผ ๊ฒƒ.

๊ฒฐ๋ก 

ํ”„๋กœ์ ํŠธ์˜ ๊ทœ๋ชจ๊ฐ€ ํฌ์ง€ ์•Š๊ณ , ์„œ๋น„์Šค ์ œ๊ณต์ด ์•„๋‹Œ, SPA ๊ตฌํ˜„์ด ๋ชฉ์ ์ด๊ธฐ์— ํŒŒ์‹ฑ ์†๋„์™€ ๋ณด์•ˆ์€ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค.

Issue #2-2

style ํ”„๋ ˆ์ž„์›Œํฌ๋กœ tailwind๋ฅผ ์‚ฌ์šฉํ•˜๊ณ  ์žˆ๊ธฐ์— innerHTML์„ ์‚ฌ์šฉํ•˜๋ฉด ๋™์ ์œผ๋กœ ๋ฐ์ดํ„ฐ๋ฅผ ๋ฐ”์ธ๋”ฉํ•ด์•ผํ•˜๋Š” ์ƒํ™ฉ์—์„œ ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์›Œ์ง€๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

์ปดํฌ๋„ŒํŠธ ๋‹จ์œ„๋ฅผ ๋”์šฑ ์ž‘๊ฒŒ ์ชผ๊ฐœ์–ด ์ตœํ•˜์œ„ ์ปดํฌ๋„ŒํŠธ์—์„œ innerHTML๋ฅผ ์‚ฌ์šฉํ•˜๊ณ , appendChild๋กœ ์š”์†Œ๋ฅผ ์ƒ์œ„ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•œ๋‹ค. ์ดˆ๊ธฐ ์„ค๊ณ„ ๋‹จ๊ณ„์—์„œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๊ณ ๋ คํ•˜์ง€ ๋ชปํ–ˆ๊ณ  ๋ฐ”๋‹๋ผ JS์˜ ์„ฑ๋Šฅ์ƒ ๋ณต์žก๋„๊ฐ€ ์ƒ์Šนํ•˜์—ฌ ์•„ํ† ๋ฏน ํŒจํ„ด์€ ๊ณ ๋ คํ•˜์ง€ ์•Š๋Š”๋‹ค.

Issue #3

์ดˆ๊ธฐ ๋‹จ๊ณ„์—์„œ ์žฌ์‚ฌ์šฉ์„ฑ์„ ๊ณ ๋ คํ•˜์—ฌ ๊ณตํ†ต ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋ถ„๋ฆฌํ•˜์ง€ ์•Š์•„ ํŽ˜์ด์ง€ ๋ณ„๋กœ ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋”ฐ๋กœ ์ œ์ž‘ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

ํ…Œ์ผ์œˆ๋“œ์˜ layer๊ธฐ๋Šฅ์œผ๋กœ class๋ฅผ ๋ฌถ๊ณ  ๊ณตํ†ต ์š”์†Œ๋ฅผ shared ์ปดํฌ๋„ŒํŠธ๋กœ ์ œ์ž‘ํ•œ ํ›„ ๋™์ ์œผ๋กœ ์š”์†Œ๋ฅผ ๋ฐ˜ํ™˜ํ•˜์˜€๋‹ค๋ฉด ๊ฐ€๋…์„ฑ๊ณผ ์ƒ์‚ฐ์„ฑ์ด ํ›จ์”ฌ ์ข‹์•„์กŒ์„ ๊ฒƒ์œผ๋กœ ์˜ˆ์ƒ ๋œ๋‹ค. ์ด ๋ฌธ์ œ๋Š” ๋ฆฌํŒฉํ† ๋ง ์‹œ ๊ณ ๋ คํ•  ์˜ˆ์ •์ด๋‹ค.

Issue #4

history API๋ฅผ ์ด์šฉํ•˜์—ฌ URL๋งŒ ์—…๋ฐ์ดํŠธํ•˜๋ฉด์„œ ์›น ๋ธŒ๋ผ์šฐ์ €์˜ ๊ธฐ๋ณธ์ ์ธ ํŽ˜์ด์ง€ ์ด๋™ ์ฒ˜๋ฆฌ๋ฅผ ๋ฐฉ์ง€ํ•˜๋ ค ํ•˜์˜€์œผ๋‚˜, pushState๋ฅผ ํ†ตํ•ด URL์ด ๋ณ€๊ฒฝ๋œ ๊ฒƒ์„ ๊ฐ์ง€ํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๊ตฌํ˜„ํ•ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

์ปค์Šคํ…€ ์ด๋ฒคํŠธ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ route๊ฐ€ ๋ณ€๊ฒฝ๋œ๋‹ค๋ฉด ์ฝœ๋ฐฑ ํ•จ์ˆ˜๋ฅผ ํ˜ธ์ถœํ•˜๋„๋ก ์ด๋ฒคํŠธ๋ฅผ ๋ฐ”์ธ๋”ฉํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

const ROUTE_CHANGE_EVENT = "ROUTE_CHANGE";

export const init = (onRouteChange) => {
  window.addEventListener(ROUTE_CHANGE_EVENT, () => {
    onRouteChange();
  });
};

export const routeChange = (url, params) => {
  history.pushState(null, null, url);
  window.dispatchEvent(new CustomEvent(ROUTE_CHANGE_EVENT, params));
};

Issue #5

innerHTML๋กœ ์ƒ์„ฑํ•œ ๋…ธ๋“œ๋Š” querySeletor๋กœ ์„ ํƒํ•˜์ง€ ๋ชปํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

์ด๋ฒคํŠธ ์œ„์ž„์„ ์‚ฌ์šฉํ•˜์—ฌ ์ƒ์œ„ ์š”์†Œ์—์„œ ํ•˜์œ„ ์š”์†Œ์˜ ์ด๋ฒคํŠธ๋“ค์„ ์ œ์–ดํ•˜์—ฌ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

Issue #6

์ƒˆ๋กœ๊ณ ์นจํ•˜๋ฉด ๋ธŒ๋ผ์šฐ์ €๋Š” html css js ํŒŒ์ผ์„ ์ฒ˜์Œ๋ถ€ํ„ฐ ๋‹ค์‹œ ์ฝ๊ธฐ ๋•Œ๋ฌธ์— ์ฐœํ•œ ์ƒํ’ˆ์— ๋Œ€ํ•œ state ๋ฐ์ดํ„ฐ๊ฐ€ ๋ฆฌ์…‹๋˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

localStorage์— ์ฐœํ•œ ์ƒํ’ˆ์— ๋Œ€ํ•œ state ๋ฐ์ดํ„ฐ๋ฅผ ์ €์žฅํ•˜์—ฌ ํ•ด๊ฒฐํ•˜๊ณ , setState ํ•จ์ˆ˜๋ฅผ ์‚ฌ์šฉํ•˜๋ฉฐ ๋™์ ์œผ๋กœ ์ƒํƒœ ๊ฐ’์„ ๊ฐฑ์‹ ํ•ด์ฃผ์—ˆ๋‹ค.

Issue #7

setState ํ•จ์ˆ˜๊ฐ€ ์‹คํ–‰๋˜์–ด ์ปดํฌ๋„ŒํŠธ๋ฅผ ์žฌ๋ Œ๋”๋งํ•  ์‹œ ํ˜•์ œ ์ปดํฌ๋„ŒํŠธ๊ฐ€ ๊ทธ ์•ž์˜ ์œ„์น˜๋กœ ์ด๋™ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ๋ฐœ์ƒํ•˜์˜€๋‹ค.

insetAdjacentHTML() ๋ฉ”์„œ๋“œ์˜ position ์ธ์ž๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ์ˆœ์„œ๊ฐ€ ์œ ์ง€๋˜๋„๋ก ์กฐ์ •ํ•˜์˜€๋‹ค.

Issue #8

์ฃผ๋ฌธ ์ˆ˜๋Ÿ‰์˜ ์ƒํƒœ๋ฅผ ๊ฐœ๋ณ„ ์ปดํฌ๋„ŒํŠธ์— ์ „๋‹ฌํ•ด์ฃผ์–ด์•ผ ํ•˜๋Š” ๋ฌธ์ œ๊ฐ€ ์ƒ๊ฒผ๋‹ค.

๊ณต์œ ํ•  ์ƒํƒœ ๊ฐ’์„ ํ•จ์ˆ˜ ๋ฐ– ์˜์—ญ์˜ ์Šค์ฝ”ํ”„์— ์ „์—ญ ๋ณ€์ˆ˜๋กœ ์„ค์ •ํ•œ ํ›„ MutationObserver๋กœ ํƒ€๊ฒŸํ•œ DOM ๋ณ€๊ฒฝ์„ ๊ฐ์‹œํ•˜์—ฌ ๋‹ค๋ฅธ ์ปดํฌ๋„ŒํŠธ์˜ ์ƒํƒœ๊ฐ€ ๋ณ€๊ฒฝ๋˜์—ˆ์„ ๋•Œ ์žฌ๋ Œ๋”๋งํ•˜๋ฉฐ ์ƒํƒœ๋ฅผ ๊ณต์œ ๋ฐ›๋Š” ๋ฐฉ๋ฒ•์œผ๋กœ ํ•ด๊ฒฐํ•˜์˜€๋‹ค.

  // ์˜ต์ €๋ฒ„ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ
  const observer = new MutationObserver(function (mutations) {
    mutations.forEach(function (mutation) {
      if (!!mutation) {
        console.log(Info.state.orderQuantity);
      }
    });
  });

  // ์˜ต์…˜ ์„ค์ •
  const config = {
    attributes: true,
    childList: true,
    characterData: true,
  };

  // ์‹คํ–‰
  observer.observe($target, config);
}

Issue #9

SPA๋ฅผ ๊ตฌํ˜„ํ•˜๋ฉด์„œ ํ•˜๋‚˜์˜ ํŒŒ์ผ์—์„œ ์—ฐ๊ฒฐํ•˜๊ณ  ์žˆ๋Š” ๋ฌด์ˆ˜ํžˆ ๋งŽ์€ ํŒŒ์ผ๋“ค์ด์ƒ๊ฒผ๋‹ค. ์—ฌ๋Ÿฌ๋ฒˆ์˜ ๋„คํŠธ์›Œํฌ ํ†ต์‹ ์„ ๊ฐ์†Œ์‹œ์ผœ ์„ฑ๋Šฅ ๊ฐœ์„ ๊ณผ ์ตœ์ ํ™”๊ฐ€ ํ•„์š”ํ•˜์—ฌ ๋ชจ๋“ˆ ๋ฒˆ๋“ค๋Ÿฌ๋ฅผ ์‚ฌ์šฉํ–ˆ๋‹ค.

"vite": "^4.1.0"

image

About

๐Ÿ› ๋ฐ”๋‹๋ผ ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ๋กœ UI ์ปดํฌ๋„ŒํŠธ๋ฅผ ๋งŒ๋“ค๊ณ  ๋ณ„๋„์˜ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ ์—†์ด SPA๋กœ ๊ตฌํ˜„ํ•œ ํ”„๋กœ์ ํŠธ์ž…๋‹ˆ๋‹ค.

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published