
Today I Learn📖
- To do list Drag & Drop (강의)
<태그명 draggable="true">: 드래그가 가능한 요소로 만들어주는 속성draggable="true" 설정dragstart, dragover, drop 구현e.preventDefault() 꼭 쓰기onDrop으로 상위 컴포넌트로 알림// App.js
import { request } from "./api.js";
import TodoList from "./TodoList.js";
export default function App({ $target }) {
this.state = {
todos: []
}
const incompletedTodoList = new TodoList({
$target,
initialState: {
title: '완료되지 않은 일들',
todos:[]
},
onDrop: async (todoId) => { // 드랍됐을 때 완료 여부 상태를 토글로 바꿈
await request(`/${todoId}/toggle`, {
method: 'PUT' // 클릭 형식의 toggle과 동작 원리 같은 것 !
})
await fetchTodos()
}
});
const completedTodoList = new TodoList({
$target,
initialState: {
title: '완료된 일들',
todos:[]
},
onDrop: async (todoId) => {
await request(`/${todoId}/toggle`, {
method: 'PUT' // 사실 클릭 형식의 toggle과 동작 원리 같음
})
await fetchTodos()
}
});
this.setState = nextState => {
this.state = nextState;
const { todos } = this.state
incompletedTodoList.setState({
...incompletedTodoList.state,
todos: todos.filter (todo => !todo.isCompleted)
})
completedTodoList.setState({
...completedTodoList.state,
todos: todos.filter (todo => todo.isCompleted)
})
}
const fetchTodos = async () => {
const todos = await request('')
this.setState({
...this.state,
todos
})
}
fetchTodos()
}
// TodoList.js
export default function TodoList({ $target, initialState, onDrop }) {
const $todoList = document.createElement('div')
$todoList.setAttribute('droppable', 'true')
$target.appendChild($todoList)
this.state = initialState
this.setState = nextState => {
this.state = nextState
this.render()
}
this.render = () => {
const { title, todos = [] } = this.state
$todoList.innerHTML = `
<h2>${title}</h2>
<ul>
/* draggable 속성으로 드래그 가능하게 만들기 */
${todos.map(todo => `<li draggable="true">${todo.content}</li>`).join('')}
</ul>
${todos.length === 0 ? '설정된 일이 없습니다.' : ''}
`
}
this.render()
/* 드래그 된 요소의 id값 가져오기 */
$todoList.addEventListener('dragstart', e => {
const $li = e.target.closest('li')
e.dataTransfer.setData('todoId', $li.dataset.id)
})
/* 드래그 되는 방식 (move, copy, none, link) */
$todoList.addEventListener('dragover', e => {
e.preventDefault() // 필수
e.dataTransfer.dropEffect = 'move'
})
/* drop 시키기 */
$todoList.addEventListener('drop', e => {
e.preventDefault() // 필수
const droppedTodoId = e.dataTransfer.getData('todoId')
/* drop된 게 현재 TodoList에 없을 경우, 상위 컴포넌트에 알림 */
const { todos } = this.state
if (!todos.find(todo => todo.id === droppedTodoId)) {
onDrop(droppedTodoId)
}
})
}
UI는 낙관적 업데이트로 사용자 경험 향상, 데이터, 네트워크 처리는 TaskQueue에 쌓아둔 뒤 한꺼번에 처리
-> 한꺼번에 저장하는 버튼 만들어서 사용해도 됨 (그 외에도 여러 방법 존재)
// TaskManager.js
export default function TaskManager() {
const tasks = []
this.addTask = (task) = {
tasks.push(task)
}
this.run = async () => {
if (tasks.length > 0) {
const task = tasks.shift()
await task()
this.run ()
}
}
this.hasTask = () => tasks.length > 0
}
// App.js
...
import TaskQueue from "./TaskManager.js"
export default function App({ $target }) {
const tasks = new TaskManager();
...
tasks.addTask(async() => {
await request ('/${todoId}/toggle', {
method: 'PUT'
})
})
}
});
...
const $button = document.createElement('button')
$button.textContent = '변경내용 동기화'
$target.appendChild($button)
$button.addEventListener('click', () => tasks.run())
}
웹 워커 (Web Workers)
메인 스레드 바깥인 백그라운드 스레드에서 스크립트를 실행하므로, 자바스크립트의 싱글 스레드를 보완 가능
-> 멀티 스레딩을 가능하게 하므로 UI 스레드가 블로킹되지 않아 사용자 경험 개선됨, 백그라운드에서 복잡한 작업 수행 가능
- 메인 스레드와 별도의 실행 컨텍스트를 가지므로 DOM에 직접 접근 불가능
-> 웹 페이지의 HTML 요소를 직접 조작하거나 글로벌 변수를 공유할 수 없음- postMessage, onmessage 이벤트를 통해 메인 스레드와 데이터를 주고받음
-> 전송되는 데이터는 복사본이므로 메모리 공유는 X
requestIdleCallback(): 브라우저가 더 이상 할 일이 없을 때 실행하는 함수 (모든 브라우저에서 지원하는 것은 아님)requestanimationframe(): 화면의 그래픽이 부드럽게 움직이도록 새로고침 될 때마다 실행되는 함수
에이잭스 (AJAX, Asynchronous JavaScript and XML)
웹 페이지가 서버와 비동기적으로 데이터를 교환할 수 있게 해주는 기술(이자 현상)
-> 웹 페이지 전체를 새로고침하지 않고도 일부분만 업데이트 가능
- 작동 방법
- fetch API 등으로 비동기 통신
- JSON으로 서버와 데이터 주고받음
- JavaScript & DOM으로 해당 부분 동적 업데이트
- 해당 부분에 CSS 존재할 경우, CSS 적용
드래그 & 드랍의 기본 틀을 만들어두고, 작업을 더 효율적으로 최적화시키며 개선하는 강의였다.
오늘 새로운 단어도 많이 들었고, TaskQueue를 통해 작업을 쌓아두었다가 한꺼번에 처리하는 방법도 배웠다. 여기서 사용되는 테스크 큐가 알고리즘때 배운 큐라는 게 신기했다 ㅎㅎ 알고리즘을 어떻게 적용하는 거지? 라는 생각을 했었는데 최적화 시키는데 사용됨을 알게됐다 !
데이터를 주고받기만 하지 않고, 데이터의 흐름과 네트워크 요청을 어떻게 잘 제어할 것인가? 를 고민해야함을 느꼈다. 여기서 효율성이 판가름 되니까..!!
오늘로 바닐라 JS 2까지 끝났다. 실무에서는 JS만으로 작업할 일이 거의 없을 것이라고 하시지만, 강사님과 라이브러리 없이 JS만으로 웹앱 만들기를 배우며 가지를 배울 수 있었다.
1. 다른 라이브러리 / 프레임워크의 동작 원리를 더 쉽게 이해할 수 있는 능력
2. 컴포넌트 단위로 구현하며 각 컴포넌트의 독립성을 챙기며 유지보수 용이성, 확장 가능성 등을 향상시킴
-> 특히 UI를 컴포넌트 단위로 추상화 해서 사용하기
3. 상태 & 데이터 중심의 UI 표현 -> 이를 통한 화면의 변화 추적
로토강사님 덕분에 많이 배웠습니다! 고생 많으셨습니다 🙇🏻♀️