Skip to content

[Mission002] TODOS 시스템에 비동기/온오프라인을 고려하여 업데이트하기#16

Open
s280493 wants to merge 12 commits intomasterfrom
mission002/jisun
Open

[Mission002] TODOS 시스템에 비동기/온오프라인을 고려하여 업데이트하기#16
s280493 wants to merge 12 commits intomasterfrom
mission002/jisun

Conversation

@s280493
Copy link
Collaborator

@s280493 s280493 commented Dec 26, 2019

  1. CURD
  2. localStorage에 데이터 넣기 - 서버에서 데이터를 가져오기에 적용하진 않았는데요,
    미션에서도 언급하신 것처럼,
    오프라인 모드에서 데이터를 보여주는 용도로 추후 업데이트 할 예정입니다.

Copy link
Collaborator

@StellaKim1230 StellaKim1230 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

코드 잘 봤습니다 ^^
지선님 코드 보면서 제 코드도 한번 돌아 볼 수 있는 시간이었습니다!
미션2 고생하셨습니다~ 👍

@@ -0,0 +1,34 @@

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

첫 줄은 삭제해주셔도 좋을 것 같습니다^^


export let isLoading = true;

export const getData = async (username) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

로토 컨벤션은 함수명을 getData 보다는 fetchData (즉, data를 fetch해오는 부분)으로 사용한다고 하더라구요 ㅎㅎ

await fetch(`${URL}/${username}/${id}/toggle`, {
method: 'PUT',
}).then(() => {

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then() 부분은 빈공간인데 추후를 대비해서 남겨놓으신건지 궁금합니다 ㅎㅎ

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네에, 쓰이지 않을까, 싶어 만들었는데, 아마 사용하지 않을 것 같네요.
지워두겠습니다~


const todoCount = new TodoCount(data);
todoCount.setState(data);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todoInput 컴포넌트에서 todoList render 하고, todoCount render을 담당하고 있는 것 같습니다.
각 컴포넌트가 담당하는 기능들을 더 분리시켜주면 어떨까요??^^


const todoList = document.getElementById("todoList");

export function TodoList(data) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아래 함수를 arrow function을 사용하셔서 TodoList 함수도 arrow function으로 맞춰주는 것이 가독성에 더 좋을 것 같습니다.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@StellaKim1230
arrow function의 경우 prototype을 가지지 않아서 생성자 함수로 사용할 수가 없습니다~ 그래서 new 로 생성할 TodoList의 경우 function 선언식으로 하는게 맞는 것 같아요 :) 저도 한참 arrow function refactoring하다가 실수했었던 경험이 있어서 정보 공유합니다 ㅎㅎ 링크

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

위의 동준님 말씀대로,
new로 생성할 컴포넌트를 작성할 때, arrow function으로 만들면 안 되더라구요 !
초반에 많이 삽질했던 기억이 납니다..!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그렇군요!!! 몰랐네요 ㅠㅠ 두분 덕분에 알고 갑니다 ㅎㅎ

const toggles = document.getElementsByClassName("toggle");
const deleteBtns = document.getElementsByClassName("destroy");

for (let i = 0; i < toggles.length; ++i) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

toggle의 길이를 먼저 계산하고, 그 안에서 change 이벤트 일어났을때 onComplete 해주는 것보다는, toggle에 각 index 를 부여한 다음에 toggle된 index를 찾아서 그 부분만 onComplete 를 호출해주는 것이 더 빠를 것이라 생각이 듭니다.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그리고 toggle className 중 change 이벤트 리스너를 걸어서 onComplete 함수 호출하는 부분은 TodoList 함수 밖으로 뺴는 것이 더 좋을것 같아요^^

editInput.style.display = "none";
}

if (e.keyCode === 13) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저희 같이 동준님 코드를 참고해봐여 ㅎㅎ

}
});
}
setTimeout(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혹시 setTImeout 을 왜 넣었는지 알수있을까요??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

dblclick 이벤트에 이슈가 있어서, 클릭 이벤트로 바꾸고, click 횟수가 두 번이면 더블클릭으로 인지하게 하려고 했는데요,
지금 dblclick 이벤트로 바꾸고 보니, 잘 돌아가네요....!

다시 dblclick 이벤트로 바꾸었습니다~!

@@ -0,0 +1,33 @@
import { renderTodoList } from '../components/TodoList.js';

export const onSelectTab = (data) => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

onSelectTag 은 전체할일, 해야할일, 완료한일 클릭시 실행되는 함수인거죠??

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 맞습니다!

let selectedTodoData = [];

if (selectedTab.id === 'completed') {
for (let i = 0; i < data.length; ++i) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filter 함수를 사용하면 코드가 더 간결해질 것 같습니다.
filter

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

selectedTodoData = filter(data => data.isCompleted)

이런식으로도 가능하게되면 array.push 함수를 사용 하지 않아도 될 것 같아요!

Copy link
Owner

@eastjun-dev eastjun-dev left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

지선님 코드를 처음 피드백 드려보는 것 같습니다 :)
코드를 보다보니 3가지를 좀 더 신경써주시면 보다 협업하기 좋은 코드로 금방 변할 수 있을 것 같아요~
지선님의 노력의 시간이 보다 더 효율적으로 사용될 수 있도록 열심히 피드백으로 도와드리겠습니다 👍

  1. 필요없는 주석 제거
    주석은 꼭 필요한 경우에만 남겨야 좋을 것 같아요. :)

  2. depth 줄이기
    보통 로직을 구현하다가 if문 안에 for문 안에 if문 이런식으로 depth가 2가 넘어가면 코드가 복잡해지는 경우가 많더라구요. depth가 3이상이 된다면, 해당 부분을
    함수로 따로 분리해서 구현하면 보다 읽기 좋은 코드가 될 것 같아요 :)

  3. event delegatation
    현재 모든 btn element들을 for문으로 돌면서 이벤트를 바인딩하는 코드를 볼 수 있는데, 이는 event delegation을 이용하면 훨씬 간결하게 줄일 수 있어요.
    혹시 이해가 가지 않거나 어려운 부분 있으시면 질문 주세요 😄

export const putData = async (username, id) => {
await fetch(`${URL}/${username}/${id}/toggle`, {
method: 'PUT',
}).then(() => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then 이후에 구현부분이 없는데, 추가할 로직이 없으시다면 제거해주셔도 좋을 것 같아요 :)

import { TodoTab } from "./components/TodoTab.js";
import { getTodoListData } from './store/store.js';

// 데이터 로드, 컴포넌트 랜더링
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼭 필요한 주석이 아니라면 없어도 괜찮을 것 같아요 :)

};
}

// 초기 데이터에 따라 todoList render
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼭 필요한 주석이 아니라면 없어도 괜찮을 것 같아요 :)

@@ -0,0 +1,36 @@
import { getData, postData, deleteData, putData } from '../api/api.js';

const username = 'jisun';
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 자바스크립트 코드에서 double quote와 single quote가 혼용되서 사용하고 있는데 하나로 정해서 사용해주시는게 협업하는 측면에서 좋을 것 같아요 :) 그리고 이번 기회에 eslint를 적요해보시는 것도 좋을 것 같아요~ 세부적인 컨벤션 등을 신경쓰지 않아도 되서 매우 편리합니다 :)

});
};

// TodoList의 data 제거
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

꼭 필요한 주석이 아니라면 없어도 괜찮을 것 같아요 :)

const onEditMode = data => {
let clickCount = 0;

todoList.addEventListener("click", e => {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

더블 클릭이벤트를 구현하시려고 한 것 같아 보여요~
clickCount를 세는 것말고, dblclick를 활용해주시면 좋을 것 같아요 :)


editInput.style.display = "block";
editInput.addEventListener("keydown", e => {
if (e.keyCode === 27) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keyCode === 27 이 어떤 키보드 값을 나타내는지 알 수 없으므로, 따로 상수로 관리하면 더 보기 좋을 것 같아요 :)

const label = e.target.childNodes[3];
const editInput = e.target.nextSibling.nextSibling;
const prevValue = editInput.value;
const id = e.target.parentElement.id;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ui에 나중에 tag가 추가되는 경우가 발생할 수도 있을 것 같은데 parentNode보다는 closest를 이용해보면 어떨까요~?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

수정했습니다~~!

editInput.style.display = "block";
editInput.addEventListener("keydown", e => {
if (e.keyCode === 27) {
editInput.style.display = "none";
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javascript 에서 style을 지정해주기 보다는 class를 이용해주시면 더 프로그래밍적으로 다루기 좋을 것 같아요 :)
css 파일에 .hidden 이라는 class가 display: none을 해주고 있어요.
그래서 $element.classList.add('hidden') 그리고 $element.classList.remove('hidden') 를 이용해서 view를 컨트롤 할 수 있을 것 같아요~!

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hidden class가 있었군요!! 넵넵!!

let selectedTodoData = [];

if (selectedTab.id === 'completed') {
for (let i = 0; i < data.length; ++i) {
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 로직 부분이 if문 안에, for문 안에, 또 if문이 있는 형태여서 코드가 복잡성이 높은 것 같아요.
for문을 통해서 값을 체크하는 부분을 filter method를 이용해서 구현하시면 아래처럼 보다 간결한 코드가 가능할 것 같아요~!
자바스크립트의 내장 함수를 이용하면 코딩할 때 많은 부분을 간략히 표현할 수 있어요 😄

if (selectedTab.id === 'completed') {
    const filteredItems = data.filter(item => item.isCompleted);
    renderTodoList(filteredItems);
    return;
}

if (selectedTab.id === 'needTodo') {
    const filteredItems = data.filter(item => !item.isCompleted);
    renderTodoList(filteredItems);
    return;
}

renderTodoList(data);

Copy link
Collaborator

@YongHoonJJo YongHoonJJo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이미 다른 분들이 리뷰해주시거나, Mission01 에서 리뷰드린 내용인 것 같습니다. 리뷰드린것들에 대한 응답 부탁드릴게요..ㅜㅜ

export const putData = async (username, id) => {
await fetch(`${URL}/${username}/${id}/toggle`, {
method: 'PUT',
}).then(() => {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

await 과 then() 을 섞어서 사용하시는 이유가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then() 이후에 코드가 필요해질까봐 습관적으로 적었는데요, 필요가 없는 코드라서 지웠습니다. 감사합니다!

todoList.innerHTML = `<li>Todo List가 비어있습니다</li>`;
} else {
list.forEach(data => {
todoList.innerHTML += `<li${
Copy link
Collaborator

@YongHoonJJo YongHoonJJo Jan 8, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mission01 에서 리뷰 드렸었는데, 별다른 응답이 없으셨고, 여기서도 그대로 진행하신거 같은데, todoList.innerHTML을 한번만 호출하지 않고, forEach 를 통해서 여러번 호출하시는 이유가 있으신가요..? ㅜ

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

todoList.innerHTML = todoItems
      .map(todoItem => todoListTemplate(todoItem))
      .join("");

data를 Foreach로 돌아서 그리는 게 익숙했는데,
vanillaJS에서 이 방식으로 하면, 브라우저를 매번 랜더링 한다는 걸 뒤늦게 알게 되었네요.

이렇게 코드를 개선했습니다.

피드백 감사드리구 넘 늦게 반영드려서 죄송해용ㅠ/ㅠ

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

map(todoItem => todoListTemplate(todoItem))
이부분은 전달받은 인자를 그대로 함수에 전달하기 때문에
map(todoListTemplate)
이렇게 하셔도 될 것 같아요!! 참고요..ㅎㅎ

todoCount.setState(todoListData);

const todoTab = new TodoTab(todoListData);
todoTab.setState(todoListData);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

객체를 생성하고, setState() 함수를 호출하고 나면 객체는 소멸이 될 것 같은데, 객체의 역할은 여기까지만 하면 되는걸까요?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants