개요
모던 자바스크립트의 구조를 학습하고 컴포넌트 기반의 코드를 작성한다.
목표
순수 Javascript로 작성된 Todo List 어플리케이션을 작성한다.
(이 글은 Next Step에서 진행한 js-todo-list-step을 따라 작성되었습니다.)
전체 코드는 여기에서 보실 수 있습니다.
여정
User는 TodoList를 가져야한다
TodoList는 사람이 해야할 일을 작성한 것이다.
즉, User는 TodoList를 소유해야 한다.
마침내, 처음 작성했던 User 관련 컴포넌트와
Todo 컴포넌트를 연결하는 순간이다.
먼저 유저를 선택할 수 있도록 기능을 추가하자.
UserList에 User 선택기능 추가
User를 선택하려면
User 목록을 가지고 있는 UserList에 이벤트를 붙여야한다.
// UserList.js
setEvent () {
this.clickCreateButton();
this.clickDeleteButton();
this.clickUserItem(); // 추가
}
clickUserItem() {
this.addEvent('click', '#user-list .ripple', (event) => {
const userName = event.target.dataset.username;
this.selectUser(userName);
});
}
selectUser(userName) {
const { selectedUser } = store.getState();
if (selectedUser.name === userName) { return; }
store.dispatch(selectUser(userName)) // 새로운 Reducer 연산이 필요하다
}
이벤트가 발생하면 선택된 User는 어디에 저장되는가?
이를 저장할 새로운 상태와 연산이 필요하다.
// reducer.js
let initialState = {
users: [],
todos: [],
filter: FILTER_TYPE.ALL,
selectedUser: "-", // 새로운 상태 추가
}
const reducer = (state = initialState, action = {}) => {
switch (action.type) {
...
case SELECT_USER: // 새로운 연산 추가
return {
...state,
selectedUser: action.payload.name,
}
이렇게하면 아래와 같이
선택된 유저를 불러와 Rendering 할수 있다
// UserList.js
const setActiveUser = (isSelected) => {
return isSelected ? 'active' : '';
}
const UserListItem = (user, isSelected) => {
return `
<button class='ripple ${setActiveUser(isSelected)}' data-username="${user.name}">
${user.name}
</button>
`
}
template () {
const { users, selectedUser } = store.getState();
return `
<div id="user-list">
${ users && users.map( (user) =>
UserListItem(user, selectedUser === user.name)
)}
...
다음은 Todo에 User 상태를 매칭시켜 주도록 하자
TodoList에 User 상태 추가
User별로 Todo를 분류하려면 Todo마다 User가 매칭되어야 한다.
(현재 Todo 상태를 정의하는 컴포넌트는 TodoInput 뿐이다.)
// TodoInput.js
createTodoItem(content) {
const newTodoItem = {
id: String(Date.now()),
user: store.getState().selectedUser, // 추가
content: content,
completed: false
};
store.dispatch(createTodo(newTodoItem));
}
위와 같이 현재 선택된 User를 불러와 저장하도록 하자.
필자는 기존 상태(users, todos)를 활용하기 위해서
selecetedUser 이름을 저장하고 필터링하는 방식을 채택했다.
이렇게 하면 전체 목록을 불러오는 과정에서
selecetedUser 이름으로 필터링만 껴넣어주면 큰 코드 변경 없이
기능을 추가할 수 있다.
(TodoCount에도 같은 방법을 적용해주어야 한다!)
// TodoList.js
const selectedUserTodoList = () => {
const { todos, selectedUser, filter } = store.getState();
const selectedUserTodos = todos.filter(todo => todo.user === selectedUser);
return filteredTodoList(filter, selectedUserTodos);
}
template () {
const todos = selectedUserTodoList()
// 컴포넌트의 내용을 반환
// join을 하지 않으면 ','까지 같이 출력된다
return `
<ul class="todo-list">
${renderTodoList(todos)}
</ul>
`;
}
선택된 유저상태를 다루는 방법은 여러가지가 될수 있다.
조금 더 나아가 생각해보면 이 부분에는 분명 개선의 여지가 있다.
전체 리스트를 필터링하는 방법은 두가지 단점이 있다고 생각한다.
- Rendering마다 전체 리스트를 조회하는 과정이 필요하다. (시간이 더 걸린다)
- 로그인이 필요한 경우라면, 전체 유저 목록(users)를 가져올 수 없다.
따라서, 이 글을 읽는 독자 여러분들은 이 부분에서 각자의 방법으로 작성해보길 바란다!
마무리
이번 시간에는 User - TodoItem간의 관계를 정의하고 기능을 구현해보았다.
구현하면서 느꼈을지도 모르지만
현재 store는 아래와 같은 문제점이 있다.
- store를 사용하기 위해 컴포넌트들이 알아야할 정보가 너무 많다. (store 변경에 취약하다, 의존적이다)
- store를 호출하면서 중복되는 코드를 재사용할 수 없다.
- 어플리케이션을 재시작하면 정보가 초기화된다(휘발성이 있다, 실제 DB를 이용하고 있지 않다.)
다음 시간에는 store를 리팩토링해보도록 하자.
'Frontend' 카테고리의 다른 글
모던 자바스크립트 Youtube Playlist - 베이스 코드 작성하기 (0) | 2023.07.05 |
---|---|
모던 자바스크립트 TodoList - Store 리팩토링 (0) | 2023.06.14 |
모던 자바스크립트 TodoList - Todo Component (3) (0) | 2023.05.08 |
모던 자바스크립트 TodoList - Todo Component (2) (0) | 2023.05.06 |
모던 자바스크립트 TodoList - Todo Component (1) (0) | 2023.05.02 |