Todo List 만들기 (컴포넌트 감잡기)

나혜수·2023년 2월 8일
0

자바스크립트 실전

목록 보기
5/19

Todo List 페이지의 구성 요소는 다음과 같다. (컴포넌트화)

main.js에는 data가 들어있으며 App.js의 작동을 담당한다.
App.js는 Header와 TodoForm, TodoList 컴포넌트를 한데 모아 $target에 맞춰 출력될 수 있게 한다.
index.html에서 모든 컴포넌트를 호출하여 완성한다.

index.html

script 호출 순서를 지키는 것이 중요하다.

$target으로 app을 지정하기 위해 main 태그 안에 class 속성 값으로 app을 넣어줬다.
참고로 앞에 $가 붙은 변수는 DOM 객체를 담고 있는 변수라는 의미이다.

<!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/Header.js"></script>
    <script src="./src/TodoForm.js"></script>
    <script src="./src/TodoList.js"></script>
    <script src="./src/App.js"></script>
    <script src="./src/main.js"></script>
</body>
</html>

TodoList.js

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

TodoForm의 input에 작성한 데이터가 TodoList로 들어가야 한다. TodoForm 파라미터에 TodoList를 넣고 직접 참조하는 방식은 두 함수간의 의존성이 강하다. 따라서 TodoForm 파라미터에 onSubmit이 콜백함수로 들어간다. onSubmit은 App.js에 정의되어 있는데, text를 입력 받으면 콜백을 통해 todoList로 text를 넘겨주는 방식이다.

e.preventDefault()

  • input을 제출할 때마다 화면이 새로고침 되는 것을 막는다.
  • get 방식을 이용한 웹 페이지 특성상 웹 페이지 주소 끝에 input 값이 보이는데 이를 안보이게 한다.

addEventListener 콜백함수의 인수 → 이벤트 객체
보통 e or event 로 이름을 정한다.
콜백함수의 파라미터에 인수 e를 넣고 출력해보면 이벤트 객체가 나온다.

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()
}

Header.js

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

   $target.appendChild($header)

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

App.js

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

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

main.js

const data = [
    {
        text: '유현준 바보라고 놀리기'
    },
    {
        text: '이상협한테 지민이 만나라고 하기'
    },
    {
        text: '우리집 멍멍이보러 덕소가기'
    }
]

const $app = document.querySelector('.app') // main 태그 선택 

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

🐶 결과


profile
오늘도 신나개 🐶

0개의 댓글