자바스크립트의 모듈

young-gue Park·2023년 1월 30일
0

JavaScript

목록 보기
14/20
post-thumbnail

⚡ JavaScript 모듈


📌 ES6 Module 사용하기

🔷 프로그램을 구성하는 구성 요소로, 관련된 데이터와 함수를 하나로 묶은 단위

  • import

    • export 키워드로 내보내진 변수, 함수 등등을 불러올 수 있는 키워드
    • import로 불러오는 경우의 순서는 무관하다.
    • 외부 의존성이 없는 컴포넌트는 export default로 선언할 수 있다.
  • 장점

    • 스크립트 의존성을 훨씬 간편하게 관리할 수 있다.
    • 사용되거나 사용되지 않는 스크립트를 추적할 수 있다.
    • 컴포넌트 순서로 인한 스트레스에서 해방될 수 있다.
    • script src로 불러오는 것과 다르게 전역 오염이 발생하지 않는다.

    💡 import를 사용하려면 웹 서버가 필요한데 serve 모듈로 로컬 웹 서버를 띄워서 진행하기 때문에 우린 상관없다.

🖥 모듈 사용법

// module-name 내에 export default로 내보내진 것을 가져온다
import defaultExport from "module-name";

// module-name 내에서 export된 모든 것을 모두 가져온다. as 이후 이름은 중복되지만 않으면 자유롭게 정할 수 있다.
import * as allItems from "module-name";

// module-name 내에서 export 된 것 중에 특정 값만 가져온다.
import {loadItem} from "module-name";

// module-name 내에서 export 된 것 중에 특정 값만 이름을 바꿔서 가져온다.
import {
    loadItem as loadSomething
} from "module-name";

// export default된 것과 개별 export 된 것을 한번에 가져올 수도 있다.
import defaultFunction, {
    loadItem
} from "module-name";

// 별도의 모듈 바인딩이 없이 불러오기
import "module.name"

from 이후 모듈 이름 맨 뒤에 .js 잘 붙였는지 확인할 것

🖥 모듈 예시(App.js)

export default function App () {
    this.render = () => {
        alert('hello!')
    }
    this.render()
}

export const printToday = () => {
    console.log(new Date().toLocaleString()) // 지역에 맞는 날짜 표기법으로 바꿔서 출력
}

🖥 constants.js

export const DOMAIN_NAME = 'www.naver.com'
export const PORT = '8000'

export const isProduction = () => {
    return false
}

🖥 index.js

// import문은 항상 맨 위!
import * as constants from './constants.js'
import App from './App.js'

const $body = document.querySelector('body')

$body.innerHTML = $body.innerHTML + JSON.stringify(constants)

new App()

🖥 index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>
<body>
    <script src = "./src/index.js" type="module"></script> <!--type="module" 추가-->
</body>
</html>

🖨 출력 결과


📌 module을 활용하여 Todo List 수정하기

  • 어김없이 찾아온 Todo List에 적용해보기 시간이다.

🖥 index.html

<!DOCTYPE html>
<html lang="ko">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>simple Todo List</title>
</head>
<body>
    <main class="app"></main>
    <script src="./src/main.js" type="module"></script> <!--type 추가 후 나머지 컴포넌트 호출 삭제-->
</body>
</html>

🖥 App.js

// App에서 사용하는 컴포넌트, 함수를 import 키워드를 불러오도록 선언
import Header from './Header.js'
import TodoForm from './TodoForm.js'
import TodoList from './TodoList.js'
import { setItem } from './storage.js'

export default function App({$target, initialState}) {
    new Header({
        $target, 
        text: 'simple Todo List'
    })
    new TodoForm({
        $target,
        onSubmit: (text) => {
            const nextState = [...todoList.state, { text }]
            todoList.setState(nextState)

            setItem('todos', JSON.stringify(nextState)) // storage 부분 삭제
        }
    })

    const todoList = new TodoList ({
        $target,
        initialState
    })
}

🖥 storage.js

const storage = window.localStorage

export const setItem = (key, value) => {
    try {
        storage.setItem(key,value)
    } catch(e) {
        console.log(e)
    }
}

export const getItem = (key, defaultValue) => {
    try {
        const storedValue = storage.getItem(key)

        if(storedValue) {
            return JSON.parse(storedValue)
        }
        return defaultValue
    } catch(e) {
        console.log(e)
        return defaultValue
    }
}

// 모듈식으로 필요할 때만 꺼내는 방식으로 수정

🖥 Header.js

export default function Header ({$target, text}) {
    const $header = document.createElement('h1')

    $target.appendChild($header)

    this.render = () => {
        $header.textContent = text
    }
    this.render()
}

🖥 TodoList.js

export default function TodoList({$target, initialState}) {
    const $todoList = document.createElement('div'); // 컴포넌트의 DOM
    $target.appendChild($todoList);

    this.state = initialState;

    // 현재의 상태를 변경하고 변경한 상태를 다시 랜더링
    this.setState = nextState => {
        this.state = nextState;
        this.render();
    }

    this.render = () => {
        $todoList.innerHTML = `
            <ul>
                ${this.state.map(({text}) =>`<li>${text}</li>`).join('')}
            </ul>
        `
    }

    this.render();
}

🖥 TodoForm.js

 export default function TodoForm({$target, onSubmit}) {
    const $form = document.createElement('form')
    $target.appendChild($form)

    let isInit = false;

    this.render = () => {
        $form.innerHTML = `
            <input type ="text" name = "todo" />
            <button>add</button>
        `

        if(!isInit) {
            $form.addEventListener('submit', e => {
                e.preventDefault();
            
                const $todo = $form.querySelector('input[name=todo]')
                const text = $todo.value
                
                if(text.length > 1) { // 한 글자 이상 들어왔을 때만 (없으면 빈 문자열만 들어갈 수 있음)
                    $todo.value = '' // 입력 후 input 비워주기

                    onSubmit(text) // App.js의 TodoForm 내의 onSubmit이 호출
                }
            })
            isInit = true
        }
    }
    
    this.render()
}

// module
// TodoForm, TodoList, Header 컴포넌트는 외부 의존성이 없기 때문에 export default로 사용

🖥 main.js

import App from './App.js'
import { getItem } from './storage.js'
const initialState = getItem('todos', [])

const $app = document.querySelector('.app')

new App({
    $target: $app,
    initialState
})

🖨 출력 결과


잘 돌아간다.


다음 시간엔 아주 중요한... 비동기처리와 promise, async, await를 다룰 것이다.

profile
Hodie mihi, Cras tibi

0개의 댓글