프로그래머스에서 진행하는 자바스크립트 스터디에 참여, 학습한 내용을 적은 글입니다.
참여 스터디: [17기] 프론트엔드 개발을 위한 자바스크립트(feat. VanillaJS), 2022.09 - 2022. 10 (4주)
https://school.programmers.co.kr/learn/courses/15244
스터디 전체 회고는 1편 스터디 회고에 작성했습니다.
Todolist/TodoCount
: 전체 개수, 완료 개수 표시Todolist/TodoInput
: 입력창Todolist/TodoList
: 투두 아이템 목록index.js
에서 컴포넌트를 불러와 App
작성 및 실행import
하고 CRUD 기능을 작성했다.state
를 내부에서도 저장해 관리하면 로컬스토리지와 이원화되서 관리가 더 어려울 것이라고 생각했음
//...
function App() {
//...
this.getState = () => {
const state = JSON.parse(localStorage.getItem(STORAGE_KEY));
if (state === null) {
return INITIAL_STATE;
}
this.validateState(state);
return state;
};
this.setState = (nextState) => {
this.validateState(nextState);
localStorage.setItem(STORAGE_KEY, JSON.stringify(nextState));
const state = this.getState();
todoList.render(state);
todoCount.render(state);
};
this.addTodo = (inputValue) => {
this.setState([
...this.getState(),
{ id: generateId(), text: inputValue, isCompleted: false },
]);
};
this.deleteTodo = (itemId) => {
const nextState = this.getState().filter(({ id }) => id !== itemId);
this.setState(nextState);
};
this.updateTodo = (itemId) => {
const nextState = this.getState().map(({ id, text, isCompleted }) => {
if (id !== itemId) return { id, text, isCompleted };
return { id, text, isCompleted: !isCompleted };
});
this.setState(nextState);
};
const todoInput = new TodoInput({
handleAddButtonClick: (inputValue) => this.addTodo(inputValue),
handleremoveAllButtonClick: () =>
this.$element.dispatchEvent(new CustomEvent('removeAll')),
});
const todoList = new TodoList({
handleCheckBoxClick: (itemId) => this.updateTodo(itemId),
handleItemTextClick: (itemId) => this.updateTodo(itemId),
handleDeleteButtonClick: (itemId) => this.deleteTodo(itemId),
});
const todoCount = new TodoCount();
todoList.render(this.getState());
todoCount.render(this.getState());
todoInput.clear();
}
window.addEventListener('DOMContentLoaded', () => {
new App();
});
JSON.parse
를 사용할 때 에러와 404 상태 코드를 전부 확인할 수 있게 try...catch
구문을 추가try...catch
구문을 사용하면서 코드 양이 많아서 로컬스토리지 관련 코드를 유틸로 이동// js/utils.js
//...
const getLocalStorage = (key) => {
const state = JSON.parse(localStorage.getItem(key));
return state;
};
const setLocalStorage = (key, value) => {
const newValue = JSON.stringify(value);
localStorage.setItem(key, newValue);
};
//...
CRUD
세부 로직들을 TodoStore.js
로 분리setState
함수에 작성된 렌더함수들을 특정 함수로 분리setState
함수에 renderAfterSetState
라는 콜백함수를 받아와 state
변경 이후 동작을 처리할 수 있도록 함// TodoStore.js
export default function TodoStore({ renderAfterSetState }) {
//...
this.getState = () => {
const state = getLocalStorage(STORAGE_KEY) || INITIAL_STATE;
this.validateState(state);
return state;
};
this.setState = (nextState) => {
this.validateState(nextState);
setLocalStorage(STORAGE_KEY, nextState);
renderAfterSetState(nextState);
};
this.addTodo = (inputValue) => {
this.setState([
...this.getState(),
{ id: generateId(), text: inputValue, isCompleted: false },
]);
};
this.deleteTodo = (itemId) => {
const nextState = this.getState().filter(({ id }) => id !== itemId);
this.setState(nextState);
};
this.updateTodo = (itemId) => {
const nextState = this.getState().map(({ id, text, isCompleted }) => {
if (id !== itemId) return { id, text, isCompleted };
return { id, text, isCompleted: !isCompleted };
});
this.setState(nextState);
};
//...
}
// index.js
//...
function App() {
//...
this.$element = $('.app');
this.$element.addEventListener('removeAll', () =>
todoStore.setState(INITIAL_STATE)
);
const todoStore = new TodoStore({
renderAfterSetState: (state) => this.render(state),
});
const todoInput = new TodoInput({
handleAddButtonClick: (inputValue) => todoStore.addTodo(inputValue),
handleremoveAllButtonClick: () =>
this.$element.dispatchEvent(new CustomEvent('removeAll')),
});
const todoList = new TodoList({
handleCheckBoxClick: (itemId) => todoStore.updateTodo(itemId),
handleItemTextClick: (itemId) => todoStore.updateTodo(itemId),
handleDeleteButtonClick: (itemId) => todoStore.deleteTodo(itemId),
});
const todoCount = new TodoCount();
this.render = (state) => {
todoList.render(state);
todoCount.render(state);
todoInput.clear();
};
//...
}