common/util/StoreUtil.js
- 이 유틸리티가 필요한 이유가 무엇인가요?
- 유틸 구조가 모호함. 굳이 계층 구조로 만드는 이유가 있나요?
- Utils
- Utils
- JavaScript 에서는 obj.get("key") 이렇게 사용하는 방식 대신에 obj.key 로 쓰는게 좋을 것 같습니다.
- getUtils
- getStore
- 디콤포지션(decomposition) 이 지원되서 편합니다.
common/util/UserUtil.js
const UserUtils = { getLoginUserId: () => { const UserStore = StoreUtils.getStore("UserStore"); return UserStore?.getLoginUserId(); }, };
|
- Util 은 보통 정적(Static) 메소드로 이루어져 있습니다
- 로그인 ID 가져오는 것은 유틸의 성격에 맞지 않는 것 같습니다.
- 의존 관계도 꼬입니다.
- Store -> Repository -> Util -> Store
- Store -> Repository -> Util -> Store
- 로그인 ID 가져오는 것은 유틸의 성격에 맞지 않는 것 같습니다.
- 다른 스토어에 대한 접근은 스토어 레벨 이상에서만 했으면 합니다.
App.js
<Provider ViewModel={rootStore} RootStore={rootStore}> ...
|
- 라우팅의 뒤쪽 파트는 네스티드 라우티을 써야하는 부분 맞죠?
- viewModel 이라는 용어보다 이제는 Store 라는 용어로 통일했으면 합니다.
repositories/ChannelRepository.js
const ChannelRepository = { getChannelList(chTypeList) { const params = { userId: userUtils.getLoginUserId(), chTypeList, }; return rest.get(`PTask/ChannelList`, params); }, |
- rest 라고 해야할까요?
- 소문자로 시작하는 것은 객체를 의미하는 것인데, 그럼 보통 new 를 해서 만들어낸 것임.
- 그런데 rest 는 클래스 레벨으로 보임
common/api/api.js
export const serverUrl = "http://222.122.67.166"; |
- configuration 으로 빼주세요
export const api = { calendar: "", file: "", note: "", }; |
- 이건 무엇을 위해서 만든 것인가요? 공통 코드에 calendar? note?
export const rest = { get(svcName, params) { const dto = { dto: params }; const t = Date.now(); return axi.get(`${svcName}?${JSON.stringify(dto)}&c=${t}`); }, ... }; |
- 여러 메소드를 포함하는 경우 가능하면 이렇게 객체 형식이 아닌 클래스를 썼으면 좋겠습니다.
- JSON.stringify 로 처리해서 넘기는 것은 아닌듯 보입니다. API 단 수정 필요
- dto 로 감싸서 쿼리 파람으로 넘기는 것도 이상합니다.
- dto 로 감싸서 쿼리 파람으로 넘기는 것도 이상합니다.
- 뒤에 c= ${t} 이건 무엇인가요?
- 모든 GET API 가 c 를 사용하지는 않을 것 같은데요.
- axios 에서 query string 이나 헤더 등은 간단하게 객체 형태로 넘길 수가 있네요.
- axios 응답을 그대로 넘겨버리면 axios 에 바인딩 됩니다.
- 자체 API 응답 포맷을 정했으면 합니다.
- 자체 API 응답 포맷을 정했으면 합니다.
repositories/ChannelRepositiory.js
- 왜 클래스를 안쓰나요?
- 안 쓸거면 function 으로 따로 정의하고 마지막에 function 을 묶어서 리턴하는 것이 readability 가 좋을 것 같은데요
- 안 쓸거면 function 으로 따로 정의하고 마지막에 function 을 묶어서 리턴하는 것이 readability 가 좋을 것 같은데요
getChannelList(chTypeList) { const params = { userId: userUtils.getLoginUserId(), chTypeList, }; return rest.get(`PTask/ChannelList`, params); }, getChannelsBrief(channelType) { const params = { userId: userUtils.getLoginUserId(), channelType, }; return rest.get(`PTask/ChannelsBrief`, params); }, |
- params 에서 어떤 것은 channel 로 시작하고 어떤 것은 ch 로 시작하는데, 변수 이름으로 사용할 용어는 통일했으면 합니다.
- ch vs channel
- ch vs channel
- userId 항상 고정인가요?
- 예를 들어 Admin 화면에서 모든 채널을 조회하고 싶은때가 있지 않을까요?
- 로그인 되지 않는 상태에서 호출되면 어떻게 되는 것인가요?
- 채널 목록을 가져올 때 Pagination 은 없나요?
- 일반적으로 목록 조회는 특별한 이유가 없으면 반드시 Pagination 을 넣습니다.
- 레파지토리마다 baseURL 멤버 변수를 갖게 하고 이를 URL 넘길 때 이를 이용했으면 합니다.
- rest.get(`${baseURL}/ChannelList`.....)
async getOrgUserList(companyCode, departmentCode) { return rest.post(`PTask/OrgUserList?action=Get`, { COMPANY_CODE: companyCode, DEPARTMENT_CODE: departmentCode, }); }, |
- 이 메소드는 왜 async 가 붙나요?
- API 설계 시 query string 관련해서 대문자 정책을 쓸 것인이 camel 정책을 쓸 것인지 정해야 합니다
- COMPANY_CODE vs companyCode
- 요청 body 나 요청 응답 형식도 마찬가지입니다.
- 대부분 camel 을 사용합니다.
setChannelUpdateInfo(param) { const response = rest.put(`PTask/Channel`, param); return response; }, |
- response 로 받아서 따로 return 할 필요는 없을 것 같습니다.
- 디버깅 때문에 그랬을 것 같은데...
- 커밋할 때는 깔끔하게 처리해주세요
- 디버깅 때문에 그랬을 것 같은데...
- 레파지토리 메소드 네이밍 컨벤션도 있어야 할 것 같습니다.
- 가능하는 HTTP 메소드를 그대로 따르는 것이 좋지 않을까?
- setChannelUpdateInfo => putChannelUpdateInfo
- get, put, post, delete
- 가능하는 HTTP 메소드를 그대로 따르는 것이 좋지 않을까?
stores/RootStore.js
const hydrate = create({ storage: localStorage, jsonify: true, });
|
- mobx-persist 의 개념에 대해서 알려주세요
- hydrate 라는 의미도요
- hydrate 라는 의미도요
class RootStore { ChannelStore = new ChannelStore(); PostStore = new PostStore(); UserStore = new UserStore(); ... } |
- 객체는 특별한 이유가 없으면 소문자로 시작하는 걸로 하시죠
Promise.all([ hydrate("channelStore", this.ChannelStore), hydrate("userStore", this.UserStore), ]).then(() => {}); |
- then 에 () => {} 를 사용하는 것보다 console.log 라도 찍는 것이 좋을 것 같습니다
stores/ChannelStore.js
@persist("object") @observable selectedChannel = {...} |
- mobx 어노테이션 붙이는 컨벤션도 정했으면 합니다.
- 개인적으로 어노테이션은 같은 라인이 아니라 윗 라인에 붙이는 것이 깔끔하다고 생각됩니다.
- 개인적으로 어노테이션은 같은 라인이 아니라 윗 라인에 붙이는 것이 깔끔하다고 생각됩니다.
console.log("data.dto.channelList", data.dto.channelList); |
- 디버그 로그는 지워주세요. 깔끔하게
data.dto.channelList?.forEach((channelItem) => { this.channels[channelItem.channelType] = channelItem; }); |
- ?. 은 간결하고 좋은 문법이긴 한테 사용에는 주의해야할 필요가 있어보입니다.
- 플로우가 눈에 잘 들어오지 않습니다.
- 예외 처리를 고민하지 않게 만들 것 같습니다.
- this.channels 가 채널인가요? 채널 타입인가요? forEach 안의 내용이 잘 이해가 안 됩니다.
const { data, status } = yield ChannelRepository.getChannelsBrief( |
- status 핸들링 하지 않을거면 빼주세요
- 만약 getChannelBrief 에서 에러가 나면 어떻게 되나요?
- 에러 핸들링 함수를 액션의 아귀먼트로 받고 이를 호출한다?
- 에러를 핸들링할 수 있는 state 를 두어서 그 값을 설정한다?
- 이 상태를 구독하는 컴포넌트는 최상위 컴포넌트여야 되겠네...
- 이 상태를 구독하는 컴포넌트는 최상위 컴포넌트여야 되겠네...
- 에러 핸들링 함수를 액션의 아귀먼트로 받고 이를 호출한다?
if (data.dto.RESULT_CD === "RST0001") { ... return true; } else { alert("즐겨찾기 실패"); return false; } |
- RESULT_CD? 먼가요? 정상 응답인데 RESULT_CD 에 따라 다른 처리가 필요하다?
- API 에러 응답에 대한 수정 필요
- API 에러 응답에 대한 수정 필요
- alert 가 아닌 에러를 처리할 수 있는 통합적인 플로우/UI 가 필요해보입니다.
addChannelMember(params) { |
- Action 함수 아귀먼트 이름으로 params, props 같은 이름은 안썼으면 합니다.
- params => member
if (this.popUserList[userType] == null) { this.popUserList[userType] = []; } |
- js 는 특별한 경우가 아니면 A == null 비교를 하지 않습니다.
- if(this.popUserList[userType]) {
- if(this.popUserList[userType]) {
- == 대신에 === 비교를 보통합니다.(타입과 값 모두 비교)
stores/PostStore.js
@observable tasksBrief = new Map(); |
- 어떨 때 Object 가 아닌 Map을 써야하나요?
- Map 에 대한 가이드 작성 필요
- Map 에 대한 가이드 작성 필요
@observable selectedChannel = { channelId: null, channelType: "join", channelName: "참여중인 채널", }; |
- selectedChannel 은 UI 와 연관이 있는 것 같은데... 꼭 필요했던 state 인가요?
- 단순 ui 관련이면 localState 로 처리해도 될 것 같다는 생각이 들어서요
- 단순 ui 관련이면 localState 로 처리해도 될 것 같다는 생각이 들어서요
- UI 상태도 저장을 해야한다면, 도메인 스토어와 UI 스토어를 분리하는 정책이 필요한 것 아닌가 생각됩니다.
@observable searchCondition = { postRead: "total", postSearchStartDate: moment().subtract(1, "month").format("YYYYMMDD"), postSearchEndDate: moment().format("YYYYMMDD"), postsNum: 20, rowNum: 1, sortType: "recent", searchWord: null, }; |
- posts 나 postSearch , search 같은 prefix 는 굳이 붙일 필요는 없어보입니다.
- startDate, endDate
- startDate, endDate
- postRead 는 어떤 조건인지 잘 와닫지 않네요.
- postsNum, rowNum 아 아니며 Pagination 으로 사용된 것 같은데요.
- pageSize, pageNum 정도로 정하고 모두 다른 곳에서도 같은 형식을 썼으면 좋겠습니다
- 정렬도 이렇게 많이 쓰입니다. 확장성도 고려할 필요가 있습니다. 멀티 키라든지...
- sortOrder
- sortKey
- sortOrder
if (this.searchCondition.rowNum == 1) { this.PostList = data.dto.postList.map((post) => new PostModel(post)); |
- 모델 클래스를 따로 두어야 하는 이유는 무엇인가요?
- Repository 응답을 이용해서 Observable 한 모델을 만들겠다 인가요?
- extendObservable 가이드 필요.
- extendObservable vs set
- Java 에서 DB 를 조회하면 이미 Model 처리가 된 상태로 넘어오는데, 이런 방식을 사용하면 어떤가요?
- Repository 단에서 모델 매핑이 이루어지게
- Repository 응답을 이용해서 Observable 한 모델을 만들겠다 인가요?
for (let i = 0; i < extraPostList.length; i++) { this.PostList.push(extraPostList[i]); } |
- 자바스크립트에서는 일반적으로 for 를 잘 쓰지 않음
- concat(extraPostList)
- [...extraPostList]
- 배열이나 이런 것 처리한 때 언더스코어로 많이 썼던 것 같은데
models/PostModel.js
'Front' 카테고리의 다른 글
코드리뷰 4 (0) | 2020.09.10 |
---|---|
MobX에서의 object vs Map 비교 (0) | 2020.09.09 |
Internet Explore 호환 주의사항 (0) | 2020.09.05 |
코드 리뷰2 (0) | 2020.08.31 |
코드 리뷰1 (0) | 2020.08.25 |