-
Notifications
You must be signed in to change notification settings - Fork 0
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
[holee] javascript-subway-map-precourse #1
Conversation
1. 역 관리 눌렀을 때 해당 HTML tag hidden=false
이유: 더해진 역만 렌더하는거기 때문이다
EOL은newline으로 끝나는게 표준이다.
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.
- set, map, slice 등 배열 조작 메서드들을 유연하게 사용하는 모습에서 많이 배웁니다.
- mvc 패턴 적용을 위한 기능별 함수 분리로 인해 유지보수가 편할 것 같고 코드 가독성이 좋았습니다.
- 확실히 이전 두 과제 코드보다 전반적으로 훨씬 좋네요.
- 덕분에 많이많이 배웁니다. 수고하셨어요.
export const renderLine = () => { | ||
const subwayLine = storage.getLocalStorageMap('subway-line'); | ||
let result = ''; | ||
for (const [lineName, value] of [...subwayLine]) { |
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.
배열에서 for문을 이렇게 사용할 수 있군요. 배워갑니다.
const getElementClass = (className) => { | ||
return document.getElementsByClassName(className); | ||
}; | ||
|
||
export const elementIds = { | ||
stationManagement: getElementId('station-management'), | ||
stationManagerButton: getElementId('station-manager-button'), | ||
stationNameInput: getElementId('station-name-input'), | ||
stationAddButton: getElementId('station-add-button'), | ||
stationDeleteButton: getElementClass('station-delete-button'), | ||
stationTableTbody: document.querySelector('tbody'), | ||
stationTableTbodyTr: document.querySelectorAll(`tbody tr`), | ||
lineManagement: getElementId('line-management'), | ||
lineManagerButton: getElementId('line-manager-button'), | ||
lineNameInput: getElementId('line-name-input'), | ||
lineStartStationSelector: getElementId('line-start-station-selector'), | ||
lineEndStationSelector: getElementId('line-end-station-selector'), | ||
lineAddButton: getElementId('line-add-button'), | ||
lineDeleteButton: getElementClass('lineDeleteButton'), | ||
lineTableTbody: document.querySelectorAll('tbody')[1], | ||
lineTableTbodyTr: document.querySelectorAll(`table[id=line-table] tr`), | ||
sectionManagerButton: getElementId('section-manager-button'), | ||
sectionManagement: getElementId('section-management'), | ||
sectionLineMenuButton: getElementClass('section-line-menu-button'), | ||
sectionStationSelector: getElementId('section-station-selector'), | ||
sectionOrderInput: getElementId('section-order-input'), | ||
sectionAddButton: getElementId('section-add-button'), | ||
sectionDeleteButton: getElementClass('section-delete-button'), | ||
sectionButtons: getElementId('section-buttons'), | ||
sectionRegister: getElementId('section-register'), | ||
sectionManageText: getElementId('section-manage-text'), | ||
sectionTableTbody: document.getElementsByTagName('tbody')[2], | ||
mapPrintManagerButton: getElementId('map-print-manager-button'), | ||
}; |
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.
미리 정의해 놓는 게 너무 유용해보입니다.
for (const item of document.querySelectorAll( | ||
`table[id=line-table] tbody tr`, |
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.
querySelectorAll 인자 사용 예시 배워갑니다!
export const toggleDisplay = () => { | ||
elementIds.stationManagement.hidden = true; | ||
elementIds.lineManagement.hidden = !elementIds.lineManagement.hidden; | ||
elementIds.sectionManagement.hidden = true; | ||
if (elementIds.mapPrintManagement) { | ||
elementIds.mapPrintManagement.hidden = true; | ||
} | ||
initSubwayRouteMap(); | ||
}; |
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.
저도 이 코드를 참고해서 같은 구조로 구현했습니다만,
사실상 하드코딩이라 toggle 해야하는 양이 많아졌을 때는 적합하지 않은 방법 같습니다.
일괄적으로 명령어를 전달하는 방법을 고민해야 할 것 같아요. (div class로 toggle해야하는 버튼들을 가둬두고 데이터속성 등의 방법으로 순회하며 요소에 접근하는 등....?? 잘은 모르겠습니다. 신박한 방법을 알게되면 공유하겠습니다.)
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.
맨처음에 작성한뒤 나중에 보았을때 저는 굉장히 안좋은 패턴이라고 결론 내렸습니다. 저에게 만약에 다실 짤 기회가 주어진다면 https://github.com/transcendence42/javascript-subway-map-precourse/blob/jwon/src/view/01-station/template.js 다음과 같이 작성한 후 메뉴 버튼을 클릭할 때마다 한 페이지를 통으로 생성하고 삭제를 해주는 로직으로 다실 짤 것같습니다.
elementIds.stationNameInput.value = ''; | ||
elementIds.stationNameInput.focus(); |
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.
만들어 둔 initLineInput 함수를 공용으로 사용하면 좋을 것 같습니다.
원인, 리팩토링 할때 확인안해서...발생.. 꼭... 확인을하자..
핳하... 수정 완료했습니다. 앞으로는 리팩토링 후 확인 꼭 하겠습니댜 |
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 subwayLine = storage.getLocalStorageMap('subway-line'); | ||
let result = ''; | ||
for (const [lineName, value] of [...subwayLine]) { | ||
result += addLineTable({ lineName, value }); |
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.
lineName과 value를 묶는 이유가 궁금합니다.
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.
for of 문법에서 반환되는 요소를 따로 변수 선언 없이 구조분해할당 받기 위해 다음 문법을 사용했습니다. https://developer.mozilla.org/ko/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment
혹시 더 나아질 수 있는 부분이 있는지 궁금합니다.
.innerHTML.slice(0, -3); | ||
const lineStation = e.currentTarget.dataset.lineStation.slice(0, -7); | ||
if (!storage.removeSectionStation(lineName, lineStation)) { | ||
alert('역은 2개 이하로 삭제할 수 없습니다.'); |
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.
이 부분도 controller/error-message.js 로 빼면 좋을 것 같습니다.
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.
앗앗 이부분을 빼먹었군요. 진짜 다음 문제부터는 전체적으로 docs 작성 먼저하고 천천히 한번씩 확인해봐야겠어요.
리뷰해주셔서 감사합니다. 컨트롤러로 인해 수행되는 로직이라서 이거를 어떻게 표현할지 저도 고민을 많이했습니다. 처음 제 의도는 model에는 진짜 localStorage에 직접적으로 관련된 로직들만 놓자는 원칙을 정하자는 의도였습니다. 다른 분들의 코드를 다보고 난후 지금의 생각을 말씀드리면 다른 분들이 짜신 코드처럼 해당 mvc 폴더 내부에 로직이 존재하는게 제일 좋은 패턴인것같습니다! |
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.
querySelector를 적극적으로 사용하는 게 인상적이었어요 !
로컬스토리지에 subway-line-list 자료는 등록하고 사용하지 않는 것 같은데 맞나요?
좋은 커리큘럼으로 진행해줘서 짧은 시간안에 많은 것을 배워갑니다 👍
const renderStation = () => { | ||
const subwayStation = storage.getLocalStorageMap('subway-station'); | ||
let result = ''; | ||
for (const station of [...subwayStation.keys()]) { |
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.
for of 문 저장해갑니다,,,
for …of 반복문
for of 반복문은 ES6에 추가된 새로운 컬렉션 전용 반복 구문입니다. for of 구문을 사용하기 위해선 컬렉션 객체가 [Symbol.iterator] 속성을 가지고 있어야만 합니다(직접 명시 가능).var iterable = [10, 20, 30]; for (var value of iterable) { console.log(value); // 10, 20, 30 }
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.
subway-station 는 value없이 key 값만 둔 이유가 있나요?
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.
for (const button of elementIds.stationDeleteButton) { | ||
addButtonEvent(button, deleteStation); | ||
} |
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.
혹시 이벤트 위임 대신 각각 달아준 이유가 있나요?
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.
이 당시는 이벤트 위임을 몰랐습니다 하핳.. 이렇게 써보니 이벤트 위임이 얼마나 편한지 느꼈습니다. 하지만, 계산기에서는 이벤트 위임을 썼다는 사실! 저도 많이 배우고 있습니다 :)
addButtonEvent(elementIds.lineManagerButton, toggleDisplay); | ||
addButtonEvent(elementIds.lineAddButton, addLine); | ||
for (const item of document.querySelectorAll( | ||
`table[id=line-table] tbody tr button`, |
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.
이런 querySelectorAll 표현도 다음에 활용해봐야겠어요 👍
export const renderSubwayRouteMap = () => { | ||
renderMap(); | ||
}; |
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.
renderSubwayRouteMap 사용하는 부분에서 바로 renderMap()을 호출하면 되지 않을까요? 이 파일에선 renderMap()을 export 하고요,
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 addStationName = (stationNames) => { |
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.
여러 역의 이름을 출력하는 함수라서 addStationNames나 addStationList라고 하면 더 직관적일 것 같아요!!
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 addButtonEvent = (submitButton, func) => { | ||
submitButton.addEventListener('click', (e) => func(e)); | ||
}; | ||
|
||
export const removeButtonEvent = (submitButton, func) => { | ||
submitButton.removeEventListener('click', (e) => func(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.
이건 이전에 유조가 했던 코멘트랑 비슷한데, 저도 제 개인적인 의견으로는 바로 addEventListener, removeEvenvListener를 사용하는 게 더 가독성 좋은 것 같아요!
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.
저한테는 이전이아니고 현재였습니다.. 하핳.. 저도 깊이 공감하여 계산기부터는 바로 직접 구현했습니다.
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.
@yechoi42 리뷰 답변드립니다!
로컬스토리지에 subway-line-list 자료는 등록하고 사용하지 않는 것 같은데 맞나요?
해당 자료는 역 삭제시 노선 관리에서 모두 삭제되었는지 판단할 때 시간복잡도를 낮추기위해서 사용했습니다.
const includeLineList = datasetStation => {
let ret = storage.getLocalStorageArray('subway-line-list');
return ret === null ? false : ret.includes(datasetStation);
};
저도 많이 배우고있습니다 👍👍
export const addButtonEvent = (submitButton, func) => { | ||
submitButton.addEventListener('click', (e) => func(e)); | ||
}; | ||
|
||
export const removeButtonEvent = (submitButton, func) => { | ||
submitButton.removeEventListener('click', (e) => func(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.
저한테는 이전이아니고 현재였습니다.. 하핳.. 저도 깊이 공감하여 계산기부터는 바로 직접 구현했습니다.
const renderStation = () => { | ||
const subwayStation = storage.getLocalStorageMap('subway-station'); | ||
let result = ''; | ||
for (const station of [...subwayStation.keys()]) { |
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 addStationName = (stationNames) => { |
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 renderSubwayRouteMap = () => { | ||
renderMap(); | ||
}; |
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.
이번 문제에서는 목록을 먼저 적어가면서 전체 큰 그림을 그리고 하나하나씩 구현하려고 노력했습니다. 또한, 전체 큰 줄기를 보며 어떤 자료구조를 어디에 써야할지, 어떤 디자인 패턴을 사용할지를 먼저 생각한 뒤 코딩을 했습니다. 우선 폴더 구조를 MVC 패턴에 맞게 나눠놓고 각각의 하위 폴더는 페이지별로 폴더를 만들어 기본 구조를 짰습니다. Model은 localStorage 관련 로직들, View에는 처음 화면에 렌더링 되는 로직들, Controller에는 이벤트에 관한 로직들로 나누어서 짰습니다.
localStorage
,dataset
,select
,DOM
, 상태관리, MVC, 기능 분리 등등 많은 것을 배웠고 성장 할 수 있는 시간이었습니다.commit 메세지 또한 기능 단위로 이전보다 잘 나누려고 했습니다. 코딩 컨벤션과 eslint를 통하여 여러 안티 패턴을 보며 좋은 코드는 무엇인지 기준을 세우는 시간이었습니다.
마지막으로, 여러 PR을 코드리뷰하고, 코드리뷰를 받으면서 더 많이 성장할 수 있었던 5일이어서 좋았습니다. 모두 모두 파이팅 입니다 :)