-
Notifications
You must be signed in to change notification settings - Fork 217
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[10기 김형남] TodoList with CRUD #215
base: hyoungnam
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
완벽하게 되어 있는것 같습니다.. 제가 모르는게 많아서 리뷰시간동안 코드흐름만 계속 읽어봤네요.. 좋은코드 읽을 수 있게 해주셔서 감사합니다.
ps. 혹시 이게 옵저버 패턴이라는 건가요..? 감탄만 나오네요..
src/components/TodoList.js
Outdated
this.store.setState(newState); | ||
} | ||
if (isDestroy) { | ||
const newState = buildNewState("DELETE", this.store, e); | ||
this.store.setState(newState); | ||
} | ||
}); | ||
this.$app.addEventListener("dblclick", (e) => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
이벤트 콜백 함수를 따로 만들어서 관리하는 방법도 좋지 않을 까라는 생각을 해보았습니다.ㅎㅎ
|
||
export default class Store { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
형남님 코드를 보면서 많이 배울 수 있었습니다 .!! 감사합니다 👍
@@ -0,0 +1,3 @@ | |||
export const $ = (node) => document.querySelector(node); | |||
export const $all = (node) => document.querySelectorAll(node) | |||
export const isInClassList = (tagName, eventTarget) => eventTarget.classList.contains(tagName) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
export const isInClassList = (tagName, eventTarget) => eventTarget.classList.contains(tagName) | |
export const isClassListContains = (tagName, eventTarget) => eventTarget.classList.contains(tagName) |
좀 더 명확하게 적기
|
||
export default class Store { | ||
constructor() { | ||
this.state = get(USER, { todos: [], view: "all" }); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
store에 state를 저장하는 것은 결합이 강하고 역할이 많으니 좀 더 분리
return this.state; | ||
} | ||
//SET | ||
setState(newState) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
비즈니스 로직은 상태를 가진 계층에서 처리하기
render() { | ||
const { view, todos } = this.store.getState(); | ||
//prettier-ignore | ||
const curViewTodos = view === "all" ? todos |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const curViewTodos = view === "all" ? todos | |
const currentViewTodos = view === "all" ? todos |
reduce 메소드를 사용할때만 cur 사용하기
//prettier-ignore | ||
import { TOGGLE, DESTROY, DELETE, EDITING, EDIT } from "./constant.js"; | ||
import { filterTodos } from "../../utils/helpers.js"; | ||
import { $, isInClassList } from "../../utils/selectors.js"; | ||
|
||
//MOUNT HELPER | ||
export function toggleTodoItem(e, store) { | ||
const isToggle = isInClassList(TOGGLE, e.target); | ||
if (isToggle) { | ||
buildNewState(TOGGLE, store, e); | ||
} | ||
} | ||
export function deleteTodoItem(e, store) { | ||
const isDestroy = isInClassList(DESTROY, e.target); | ||
if (isDestroy) { | ||
buildNewState(DELETE, store, e); | ||
} | ||
} | ||
export function setEditingMode(e) { | ||
const isList = e.target.closest("li"); | ||
if (isList) { | ||
isList.classList.add(EDITING); | ||
} | ||
} | ||
export function editSelectedTodo(e, store) { | ||
const isEditing = isInClassList(EDIT, e.target); | ||
if (isEditing && e.key === "Enter") { | ||
buildNewState(EDIT, store, e); | ||
e.target.closest("li").classList.remove(EDITING); | ||
} | ||
if (isEditing && e.key === "Escape") { | ||
const currentValue = $(".label").textContent; | ||
e.target.value = currentValue; | ||
e.target.closest("li").classList.remove(EDITING); | ||
} | ||
} | ||
|
||
//VIEW HELPER | ||
export function buildListTodos(store) { | ||
const { todos, view } = store.getState(); | ||
return view === "all" ? todos : filterTodos(todos, view); | ||
} | ||
|
||
//STATE HELPER | ||
function buildNewState(op, store, e) { | ||
const OPERATIONS = { | ||
toggle: toggleTodoStatus, | ||
delete: deleteTodo, | ||
edit: editTodo, | ||
}; | ||
const prevState = store.getState(); | ||
const targetId = Number(e.target.closest("li").getAttribute("dataset-id")); | ||
|
||
const newTodos = OPERATIONS[op](prevState, targetId, e); | ||
|
||
const newState = { ...prevState, todos: newTodos }; | ||
store.setState(newState); | ||
} | ||
|
||
//TODO - STATUS | ||
function toggleTodoStatus(prevState, targetId, e) { | ||
const newStatus = e.target.checked ? "completed" : "active"; | ||
const newTodos = prevState.todos.map((todo) => { | ||
if (todo.id === targetId) { | ||
return { ...todo, status: newStatus }; | ||
} | ||
return todo; | ||
}); | ||
return newTodos; | ||
} | ||
//TODO - DELETE | ||
function deleteTodo(prevState, targetId) { | ||
const newTodos = prevState.todos.filter((todo) => { | ||
return todo.id !== targetId; | ||
}); | ||
return newTodos; | ||
} | ||
|
||
//TODO - UPDATE | ||
function editTodo(prevState, targetId, e) { | ||
const newTodos = prevState.todos.map((todo) => { | ||
if (todo.id === targetId) { | ||
return { ...todo, content: e.target.value }; | ||
} | ||
return todo; | ||
}); | ||
return newTodos; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
helper라는 함수 이름 아래 MOUNT, VIEW, STATE 로직이 다 모여있음. 역할 분리 필요하며 특히 state로직은 state 계층으로
🎯 요구사항
🎯🎯 심화 요구사항