개발자

1번과 2번 중 어떤게 더 유연한 컴포넌트 설계 방법일까요?

2024년 02월 05일조회 91

1번 코드와 2번 코드 중 상황 대처에 유연하고 처음 본 사람조차 쉽게 사용할 수 있을까요? 1번 코드의 경우 컴포넌트 내부에서 UI에서 나타내야하는 값을 로직을 수행 후 사용하는 개념이고 2번 코드의 경우 부모 컴포넌트에서 UI에서 나타내야하는 값을 로직을 수행 후 Props로 넘겨 자식 컴포넌트는 부모에게 받은 값을 그대로 보여주기만 하는 개념입니다.

1//1번 코드
2import dayjs from 'dayjs';
3import React, { useState } from 'react';
4
5interface AdvertisementData {
6  payInfo_startPaidAt?: Date;
7  startDate: Date;
8  periodApply: number;
9  periodAccept: number;
10  periodReview: number;
11  //...etc
12}
13
14//Container.tsx
15const Container = () => {
16  const [state, setState] = useState<AdvertisementData>({
17    payInfo_startPaidAt: new Date(),
18    startDate: new Date(),
19    periodApply: 14,
20    periodAccept: 2,
21    periodReview: 14,
22  });
23
24  return (
25    <>
26      {/* 다른 요소들 */}
27      <Component advertisementData={state} />
28      {/* 다른 요소들 */}
29    </>
30  );
31};
32
33//Component.tsx
34const Component = ({
35  advertisementData,
36}: {
37  advertisementData: AdvertisementData;
38}) => {
39  const startDate = dayjs(
40    advertisementData.payInfo_startPaidAt || advertisementData.startDate
41  );
42  const applicationPeriodStart = startDate.format('MM.DD');
43  const applicationPeriodEnd = startDate
44    .add(advertisementData.periodApply, 'd')
45    .format('MM.DD');
46  const announcementDate = startDate
47    .add(advertisementData.periodApply + advertisementData.periodAccept, 'd')
48    .format('MM.DD');
49  const registrationPeriodEnd = startDate
50    .add(
51      advertisementData.periodApply +
52        advertisementData.periodAccept +
53        advertisementData.periodReview,
54      'd'
55    )
56    .format('MM.DD');
57
58  return (
59    <div>
60      <ul>
61        <li>
62          신청 기간 : {applicationPeriodStart}-{applicationPeriodEnd}
63        </li>
64        <li>발표 날짜 : {announcementDate}</li>
65        <li>
66          제출 기간 : {announcementDate}-{registrationPeriodEnd}
67        </li>
68      </ul>
69    </div>
70  );
71};
72
73//2번 코드
74import dayjs from 'dayjs';
75import React, { useState } from 'react';
76
77interface AdvertisementData {
78  payInfo_startPaidAt?: Date;
79  startDate: Date;
80  periodApply: number;
81  periodAccept: number;
82  periodReview: number;
83  //...etc
84}
85
86//Container.tsx
87const Container = () => {
88  const [state, setState] = useState<AdvertisementData>({
89    payInfo_startPaidAt: new Date(),
90    startDate: new Date(),
91    periodApply: 14,
92    periodAccept: 2,
93    periodReview: 14,
94  });
95
96  const startDate = dayjs(state.payInfo_startPaidAt || state.startDate);
97  const applicationPeriodStart = startDate.format('MM.DD');
98  const applicationPeriodEnd = startDate
99    .add(state.periodApply, 'd')
100    .format('MM.DD');
101  const announcementDate = startDate
102    .add(state.periodApply + state.periodAccept, 'd')
103    .format('MM.DD');
104  const registrationPeriodEnd = startDate
105    .add(state.periodApply + state.periodAccept + state.periodReview, 'd')
106    .format('MM.DD');
107
108  return (
109    <>
110      {/* 다른 요소들 */}
111      <Component
112        applicationPeriodStart={applicationPeriodStart}
113        applicationPeriodEnd={applicationPeriodEnd}
114        announcementDate={announcementDate}
115        registrationPeriodEnd={registrationPeriodEnd}
116      />
117      {/* 다른 요소들 */}
118    </>
119  );
120};
121
122interface ComponentProps {
123  applicationPeriodStart: string;
124  applicationPeriodEnd: string;
125  announcementDate: string;
126  registrationPeriodEnd: string;
127}
128
129//Component.tsx
130const Component = ({
131  applicationPeriodStart,
132  applicationPeriodEnd,
133  announcementDate,
134  registrationPeriodEnd,
135}: ComponentProps) => {
136  return (
137    <div>
138      <ul>
139        <li>
140          신청 기간 : {applicationPeriodStart}-{applicationPeriodEnd}
141        </li>
142        <li>발표 날짜 : {announcementDate}</li>
143        <li>
144          제출 기간 : {announcementDate}-{registrationPeriodEnd}
145        </li>
146      </ul>
147    </div>
148  );
149};
이 질문이 도움이 되었나요?
'추천해요' 버튼을 누르면 좋은 질문이 더 많은 사람에게 노출될 수 있어요. '보충이 필요해요' 버튼을 누르면 질문자에게 질문 내용 보충을 요청하는 알림이 가요.

답변 1

포크코딩님의 프로필 사진

구조를 꼭 저렇게 해야 한다면 첫 번째 코드를 기반으로 수정을 권합니다. 컨테이너는 다른 요소도 담고 있기 때문에 컴포넌트 관련된 로직을 처리할 이유가 없습니다. 이는 컴포넌트의 책임입니다. 수정한 컴포넌트 코드는 아래와 같습니다. dayjs 사용하는 부분이 꽤 장황하여 커스텀 훅을 사용해 줍시다. 커스텀 훅으로 따로 빼두면 가독성 상승과 함께 표시 내용 추가시 쉽게 대응할 수 있습니다.

1//Component.tsx
2import { useAdsDate } from "@/hooks/useAdsDate"; // 날짜 처리 로직 -> 커스텀 훅
3
4const Component = ({
5    advertisementData,
6}: {
7    advertisementData: AdvertisementData;
8}) => {
9    const [
10        applicationPeriodStart,
11        applicationPeriodEnd,
12        announcementDate,
13        registrationPeriodEnd,
14    ] = useAdsDate(advertisementData);
15
16    return (
17        <div>
18            <ul>
19                <li>
20                    신청 기간 : {applicationPeriodStart}-{applicationPeriodEnd}
21                </li>
22                <li>발표 날짜 : {announcementDate}</li>
23                <li>
24                    제출 기간 : {announcementDate}-{registrationPeriodEnd}
25                </li>
26            </ul>
27        </div>
28    );
29};
30
31// hooks/useAdsDate.ts
32import dayjs from "dayjs";
33import { useState } from "react";
34
35export const useAdsDate = (advertisementData: AdvertisementData) => {
36    const startDate = dayjs(
37        advertisementData.payInfo_startPaidAt || advertisementData.startDate
38    );
39    const applicationPeriodStart = startDate.format("MM.DD");
40    const applicationPeriodEnd = startDate
41        .add(advertisementData.periodApply, "d")
42        .format("MM.DD");
43    const announcementDate = startDate
44        .add(
45            advertisementData.periodApply + advertisementData.periodAccept,
46            "d"
47        )
48        .format("MM.DD");
49    const registrationPeriodEnd = startDate
50        .add(
51            advertisementData.periodApply +
52                advertisementData.periodAccept +
53                advertisementData.periodReview,
54            "d"
55        )
56        .format("MM.DD");
57    return [
58        applicationPeriodStart,
59        applicationPeriodEnd,
60        announcementDate,
61        registrationPeriodEnd,
62    ];
63};

지금 가입하면 모든 질문의 답변을 볼 수 있어요!

현직자들의 명쾌한 답변을 얻을 수 있어요.

또는

이미 회원이신가요?

AI 답변
커리어리 AI 봇 프로필 이미지

커리어리 AI 봇

GPT가 달아주는 답변입니다.

2024년 02월 05일

2번 코드가 더 유연한 설계 방법일 것입니다. 이유는 다음과 같습니다: 1. **단일 책임 원칙(Single Responsibility Principle)**: 2번 코드는 각 컴포넌트가 하나의 책임만을 가지도록 설계되어 있습니다. `Container` 컴포넌트는 상태 관리와 연산 로직을 담당하고, `Component` 컴포넌트는 UI를 표현하는 역할만 담당합니다. 반면, 1번 코드에서 `Component` 컴포넌트는 상태 조회와 연산 로직, 그리고 UI 표현까지 모두 담당하므로 단일 책임 원칙에 어긋납니다. 2. **재사용성(Reusability)**: 2번 코드의 `Component` 컴포넌트는 props를 통해 받은 값을 그대로 UI에 표현하기 때문에, 다른 부모 컴포넌트에서도 재사용이 가능합니다. 반면, 1번 코드의 `Component` 컴포넌트는 내부적으로 연산 로직을 가지고 있으므로 동일한 로직을 다른 곳에서 재사용하려면 코드 복사가 필요합니다. 3. **읽기 쉽고 유지보수하기 용이함**: 2번 코드는 컴포넌트의 역할이 명확하고 분리되어 있으니, 처음 코드를 보는 사람도 쉽게 이해할 수 있습니다. 또한 각 컴포넌트가 단일 책임 원칙을 따르기 때문에 유지보수도 용이합니다. 결론적으로, 두 번째 방식은 유연성, 재사용성, 가독성, 유지보수성 등 여러 면에서 우위에 있습니다. 이는 리액트의 주요 개념인 "컴포넌트 간의 관심사 분리(Separation of Concerns between Components)"를 잘 보여주는 사례로 볼 수 있습니다.

목록으로

지금 가입하면 모든 질문의 답변을 볼 수 있어요!