본문 바로가기

Front

코드 리뷰2

App.js

 

const rootStore = new RootStore();

....

+    <Provider modelView={rootStore} KanbanStore={rootStore.kanban}>

+      <HashRouter>

+        {/* GNB에 추가된 LIST 임시로 화면을 보여드리기위해 추가됬습니다.

       적용 시 삭제 부탁드립니다. */}

  • App.js 에서 글로벌 상태 모델을 생성하고 을 제공했으면 합니다.
    • 이름을 MVVM 의 modelView 로 통일
  • 다음에 KanbanStore 를 추가적으로 매핑을 할 수는 있는데...

 

components/kanban/ChannelCategories.js

 

-    const { match } = this.props;

+    const { channelType, channelId } = this.props;

     this.state = {

-      selectedChannelType: match.params.channelType,

-      selectedChannelId: match.params.channelId

-        ? match.params.channelId

-        : match.params.channelType,

+      selectedChannelType: channelType,

+      selectedChannelId: channelId || channelType,

     };

 

 

  • props 는 반드시 decomposition 을 사용했으면 합니다.
  • 라우터에 매핑되는 컴포넌트는 하나만 두었으면 합니다.
    • 여기서는 하나의 URL 에 여러 컴포넌트들이 매핑이 되고 있음

 

 

+  static getDerivedStateFromProps(nextProps) {

+    return {

+      selectedChannelType: nextProps.channelType,

+      selectedChannelId: nextProps.channelId || nextProps.channelType,

+    };

+  }

 

  • componentWillRecieiveProps 대신에 getDerivedStateFromProps 를 사용합니다.
    • Deprecated 되었음
    • 원래 아귀먼트는 nextProps, prevProps  두 개를 받는 함수임.
    • 새로 마운트하지 않고 Props 가 변경되었을 때 호출됨.

 

     const renderchannelCategoryInfo = channelCategoryInfos.map(

-      (channelCategoryInfo, index) => (

+      (channelCategoryInfo) => (

         <ChannelCategory

-          key={`${selectedChannelId}_${index}`}

+          key={`${channelCategoryInfo.channelType}`}

 

 

  • Html 목록 아이템을 생성할 때는 배열 인덱스를 이용하지 않습니다.

 

 

+ChannelCategories.defaultProps = {

+  channelId: "",

 };

 

  • Props 에 대한 검증은 가능하면 추가하고(PropTypes), 필요하면 디폴트 값도 설정했으면 합니다.
    • 설정 안 하면 린트 에러

 

 

components/kanban/ChannelCategory.js

 

 

+      return (

+        <li key={channel.channelId}>

           <Link

             key={channel.channelId}

             to={() => {

-              if (this.props.channelType === channel.channelType) {

-                return `/kanban/${channel.channelType}`;

-              } else {

-                return `/kanban/${this.props.channelType}/${channel.channelId}`;

-              }

+              return channel.channelId === channelType

+                ? `/kanban/${channelType}`

+                : `/kanban/${channelType}/${channel.channelId}`;

             }}

-            onClick={() => this.handleSelectedChannelClick(channel)}

           >

             {channel.channelName}

           </Link>

  • Link 에서 onClick 은 뺐으면 합니다.

 

 

+      <li

+        className={ClassNames({

+          top: true,

+          [ClassByChannelType[channelType]]: true,

+          on: selectedChannelType === channelType,

+        })}

+      >

  • className 은 객체로 class 를 설정할 수 있는 것이 핵심

 

 

components/kanban/KanbanBoard.js

 

 

+@inject("modelView")

+@observer

 class KanbanBoard extends Component {

   constructor(props) {

     super(props);

     this.state = {

-      channelCnt: "",

-      channelsBrief: [],

 

  • 어느 시점에 모델을 바인딩할 지 선택해야함.
    • 여기서는 URL 과 바인딩 된 페이지 아래에서 처리를 하고 있음
  • 쓰지 않는 코드는 제발 삭제 부탁

 

 

   async componentDidMount() {

...

+    const { modelView, channelType } = this.props;

+    await modelView.kanban.fetchChannelsBrief({

+      channelType,

+    });

   }

 

  • 서버로 부터 모델을 업데이트하는 코드는 componentDitMount 와 getDerivedStateFromProps 에서

 

 

   render() {

+    const { modelView, channelType } = this.props;

+    const { data } = this.state;

     const MemberPopup = PopupWrapper(Members);

...

+

     return (

       <main className="main kanban-main">

         <div className="kanban">

-          {this.state.channelsBrief?.map((value, index) => {

+          {modelView.kanban.channelsBrief?.map((value) => {

  • 글로벌 스토어에 대한 접근은 modelView 를 이용하여서 접근

 

repositories/KanbanRepository.js

 

 class KanbanRepository {

-  getTasksBrief(props) {

+  static getTasksBrief(props) {

     const params = {

       userId: props.userId,

 

  • 메소드를 일반 메소드로 할 것인지 static 메소드할 것인지 잘 구분

 

routes/Kanban.js

 

 

+function Kanban() {

+  return (

+    <div>

+      <Switch>

+        <Route

+          exact

+          path="/kanban/:channelType"

+          component={KanbanChannelListPage}

+        />

+        <Route

+          path="/kanban/:channelType/:channelId"

+          component={KanbanChannelDetailPage}

+        />

+      </Switch>

+    </div>

+  );

  • routes 를 단순화 시킴
    • URL 에 하나의 페이지가 매핑되는 형식으로 구조 수정

 

stores/KanbanStore.js

 

 

     this.channelCategoryInfos = data.dto.channelList.map(

       (channelCategoryInfo) => {

+        const mappedCategoryInfo = { ...channelCategoryInfo };

...

-        channelCategoryInfo.data = channelCategoryInfo.data

+        mappedCategoryInfo.data = mappedCategoryInfo.data

           ? [...defaultCategoryInfoData, ...channelCategoryInfo.data]

           : [...defaultCategoryInfoData];

 

-        return channelCategoryInfo;

+        return mappedCategoryInfo;

       }

  • map 을 하는데, 자기 스스로를 업데이트하는 코드가 있다?

 

+  @asyncAction

+  async *fetchChannelsBrief(props) {

+    this.channelsBrief = [];

+

+    const { data } = yield KanbanRepository.getChannelsBrief(props);

+    this.channelCnt = data.dto.channelCnt;

+    this.channelsBrief = data.dto.channelsBrief

+      ? [...data.dto.channelsBrief]

+      : [];

   }

  • 배열인 경우 왜 상태를 항상 [] 으로 초기화를 하고, 다시 설정하는 지?
  • 왜 비동기 액션에서 왜 generator 를 쓰고  있는 지?

 

 

 

-KanbanStore = new KanbanStore();

-

 export default KanbanStore;

  • 스토어나 컴포넌트를 특별한 목적이 아니면 내부에서 new 를 하지 않았으면 함.

 

stores/RootStore.js

 

 

 

import autobind from "autobind-decorator";

import AuthStore from "./AuthStore";

import KanbanStore from "./KanbanStore";

@autobind

class RootStore {

   constructor() {

      this.auth = new AuthStore(this);

      this.kanban = new KanbanStore(this);

   }

}

export default RootStore;

  • 멀티플 스토어 엮는 방법 제안

 

stores/AuthStore.js

 

 

 

import { observable } from "mobx";

import autobind from "autobind-decorator";

@autobind

class AuthStore {

@observable userId = "8c0a49be-d9de-4a70-99dd-3bc3de71d49a";

constructor(parentStore) {

this.parentStore = parentStore;

}

}

export default AuthStore;

  • 현재 사용자의  인증 정보 담음.

'Front' 카테고리의 다른 글

코드리뷰 3  (0) 2020.09.07
Internet Explore 호환 주의사항  (0) 2020.09.05
코드 리뷰1  (0) 2020.08.25
front 개발하면서 가장 많이 하는 노가다를 정리해보자  (0) 2020.04.11
min.css / min.js 등 min이란 무엇인가  (0) 2020.04.08