Skip to content

[Step5] hippo - API 요청과 비동기 처리 - #7

Open
meteorqz6 wants to merge 13 commits into
hippo-step4from
hippo-step5
Open

[Step5] hippo - API 요청과 비동기 처리#7
meteorqz6 wants to merge 13 commits into
hippo-step4from
hippo-step5

Conversation

@meteorqz6

@meteorqz6 meteorqz6 commented Jun 7, 2026

Copy link
Copy Markdown
Contributor

개인 목표 달성 여부

  • useEffect, useCallback가 필요한 이유 이해하기
  • fetch로 API 요청을 보내고 응답을 처리하는 방법 학습
  • async/await, Promise 객체에 대해 이해하기

리뷰어에게

특히 봐줬으면 하는 부분, 확신이 없는 코드, 논의하고 싶은 것

  • 기존의 요구사항에는 로딩 상태, 에러 상태 등을 고려하지 않는다고 적혀 있지만, 로딩 상태, 에러 상태를 구현해 보고 싶어서 구현했습니다.
  • 커스텀 훅을 언제 만들면 좋을지에 대해서 같이 논의해보면 좋을 것 같습니다.

Summary by CodeRabbit

릴리스 노트

  • 새로운 기능

    • API 연동을 통한 레스토랑 데이터 실시간 로드
    • 새로운 레스토랑 추가 시 목록 자동 새로고침
  • 개선 사항

    • 레스토랑 목록 선택 인터페이스 개선
    • 카테고리 관리 최적화
  • 문서

    • API 연동 및 비동기 처리 실습 가이드 추가

@meteorqz6
meteorqz6 marked this pull request as draft June 7, 2026 16:41
@meteorqz6 meteorqz6 changed the title docs: 5단계 미션 요구사항 추가 [Step5] hippo - API 요청과 비동기 처리 Jun 7, 2026
@meteorqz6 meteorqz6 self-assigned this Jun 8, 2026
@coderabbitai

coderabbitai Bot commented Jun 9, 2026

Copy link
Copy Markdown

Review Change Stack

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 77ec4872-ac30-4e7b-88d9-4c5bd134da43

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review

Walkthrough

로컬 상수 기반의 레스토랑 데이터를 json-server REST API로 교체했습니다. src/api.js(GET/POST 함수)와 useRestaurants 훅을 신규 추가하고, App에서 비동기 흐름으로 전환했습니다. CATEGORIES 상수를 추출해 컴포넌트 옵션을 동적 렌더링하고, RestaurantList 항목 클릭 구조를 button으로 변경했습니다.

Changes

REST API 연동 및 컴포넌트 리팩토링

Layer / File(s) Summary
CATEGORIES 상수 추출 및 동적 렌더링
src/constants/categories.js, src/components/AddRestaurantModal/AddRestaurantModal.jsx, src/components/CategoryFilter/CategoryFilter.jsx
CATEGORIES 배열을 새 상수 파일로 분리하고, AddRestaurantModalCategoryFilter의 하드코딩 옵션 목록을 CATEGORIES.map() 기반 동적 렌더링으로 교체했습니다.
api.js REST API 함수 구현
src/api.js, src/constants/restaurants.js
getRestaurants()(GET)와 createRestaurant()(POST)를 BASE_URL 기반으로 신규 구현했습니다. response.ok 검사 및 예외 재던지기를 포함하며, 로컬 RESTAURANTS 상수는 삭제되었습니다.
useRestaurants 훅 구현 및 App 비동기 전환
src/hooks/useRestaurants.js, src/App.jsx
useRestaurants 훅이 useState/useEffect/useCallback으로 목록 상태와 addRestaurant를 관리합니다. App은 로컬 상태를 훅으로 교체하고 handleRestaurantSubmitasync/await 방식으로 전환했습니다.
RestaurantList 클릭 구조를 button으로 변경
src/components/RestaurantList/RestaurantList.jsx, src/components/RestaurantList/RestaurantList.module.css
li 직접 클릭에서 내부 button(.restaurant__button) 클릭으로 구조를 변경하고, 레이아웃/패딩 스타일을 .restaurant__button으로 이관했습니다.

문서 및 설정 업데이트

Layer / File(s) Summary
CodeRabbit 설정 파일 추가
.coderabbit.yaml
언어(ko-KR), 리뷰 프로필(chill), 자동 리뷰, 채팅 자동응답 등 봇 동작을 구성했습니다.
실습 문서 및 루트 README 업데이트
05-effects/README.md, README.md
05-effects/README.md에 json-server 기반 REST API 실습 가이드를 신규 추가했습니다. 루트 README.md는 학습 목표와 리팩토링 섹션을 API 비동기 처리 관점으로 전면 교체했습니다.

Sequence Diagram(s)

sequenceDiagram
  rect rgba(70, 130, 180, 0.5)
    Note over App: 초기 렌더링
    App->>useRestaurants: useRestaurants() 호출
    useRestaurants->>api.js: getRestaurants()
    api.js->>json-server: GET /restaurants
    json-server-->>api.js: 레스토랑 목록 반환
    api.js-->>useRestaurants: restaurants 배열
    useRestaurants-->>App: { restaurants, addRestaurant }
  end
  rect rgba(60, 179, 113, 0.5)
    Note over App: 레스토랑 추가
    App->>useRestaurants: addRestaurant(newRestaurant) await
    useRestaurants->>api.js: createRestaurant(newRestaurant)
    api.js->>json-server: POST /restaurants
    json-server-->>api.js: 201 응답
    api.js-->>useRestaurants: 완료
    useRestaurants->>api.js: getRestaurants() 재호출
    api.js->>json-server: GET /restaurants
    json-server-->>api.js: 갱신된 목록
    api.js-->>useRestaurants: 갱신된 restaurants
    useRestaurants-->>App: 모달 닫기
  end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • pair-study/final-project#13: 두 PR 모두 저장소 루트의 .coderabbit.yaml에 리뷰 언어/프로필/자동 리뷰 등 CodeRabbit 봇 동작 설정을 추가·수정하는 동일한 구성 파일 변경이 포함되어 있습니다.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed PR 제목은 '[Step5] hippo - API 요청과 비동기 처리'로, 주요 변경사항인 API 연동과 비동기 처리 구현을 명확하게 요약하고 있습니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch hippo-step5

Comment @coderabbitai help to get the list of available commands and usage tips.

@meteorqz6
meteorqz6 marked this pull request as ready for review June 14, 2026 09:48
@meteorqz6

Copy link
Copy Markdown
Contributor Author

@coderabbitai review

@coderabbitai

coderabbitai Bot commented Jun 14, 2026

Copy link
Copy Markdown
✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
05-effects/README.md (1)

59-63: ⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

코드 펜스에 언어를 지정하세요.

Line 59-63의 코드 블록이 언어 없이 선언되어 있습니다. 마크다운 린터 경고를 해결하고 구문 강조를 활성화하려면 언어를 지정해야 합니다.

🔧 제안 수정
 ### `async/await`를 어디에 붙여야 하는가
 
 `await`는 Promise를 반환하는 함수 앞에 붙인다. `await`를 쓰는 함수 자신은 반드시 `async`여야 한다. 이 규칙이 호출 체인을 따라 전파된다.
 
-```
+```text
 fetch()                    → Promise 반환
 getRestaurants()           → 내부에서 await fetch() → async 필요
 handleRestaurantSubmit()   → 내부에서 await getRestaurants() → async 필요
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@05-effects/README.md` around lines 59 - 63, The code block on lines 59-63 in
the README.md file is missing a language identifier in the markdown code fence.
Add the language identifier "text" immediately after the opening triple
backticks to enable syntax highlighting and resolve markdown linter warnings.
Change the opening fence from triple backticks with no language to triple
backticks followed by "text" before the code block containing the fetch,
getRestaurants, and handleRestaurantSubmit function descriptions.

Source: Linters/SAST tools

🧹 Nitpick comments (4)
src/api.js (2)

15-27: ⚡ Quick win

생성된 레스토랑 데이터 반환을 고려하세요.

createRestaurant가 생성된 데이터를 반환하지 않습니다. 서버가 id나 타임스탬프를 할당하는 경우, 반환값을 활용하면 전체 목록을 다시 조회하지 않고도 UI를 즉시 업데이트할 수 있어 네트워크 효율성이 향상됩니다.

♻️ 제안하는 개선 방안
 export async function createRestaurant(restaurant) {
   try {
     const response = await fetch(`${BASE_URL}/restaurants`, {
       method: "POST",
       headers: { "Content-Type": "application/json" },
       body: JSON.stringify(restaurant),
     });
     if (!response.ok) throw new Error(`서버 오류: ${response.status}`);
+    const createdRestaurant = await response.json();
+    return createdRestaurant;
   } catch (error) {
     console.error("음식점 추가 실패:", error);
     throw error;
   }
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api.js` around lines 15 - 27, The createRestaurant function does not
return the restaurant data created by the server. To improve network efficiency
and enable immediate UI updates, parse the response body as JSON in the
createRestaurant function and return the created restaurant object (which will
include server-assigned data like id and timestamp) so the caller can use it
without refetching the entire list. This change should occur after the response
validation in the try block, before the catch block.

3-27: 에러 핸들링 접근 방식에 대한 피드백

PR 설명에서 try/catch 에러 핸들링 접근 방식에 대한 피드백을 요청하셨습니다. 현재 구현은 올바른 패턴입니다:

잘된 점:

  • API 모듈에서 에러를 잡아 로깅한 후 다시 던지는 것은 라이브러리 코드의 표준 패턴입니다
  • 호출하는 쪽(useRestaurants, App)에서 에러를 처리할 수 있도록 제어권을 전달합니다
  • response.ok 체크로 HTTP 에러를 명시적으로 처리합니다

💡 선택적 개선 사항:

  • 에러에 더 많은 컨텍스트를 추가할 수 있습니다 (예: error.message에 URL 포함)
  • 특정 HTTP 상태 코드별로 다른 에러 타입을 던질 수 있습니다 (401, 404, 500 등)

현재 패턴이 학습 목적과 이 프로젝트 규모에 적합합니다. 더 정교한 에러 핸들링이나 커스텀 에러 클래스 생성을 원하시면 도움을 드릴 수 있습니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/api.js` around lines 3 - 27, To implement the optional error handling
improvements, enhance both getRestaurants() and createRestaurant() functions
with more detailed error context and status code-specific handling. For error
context, include the request URL in the error message passed to console.error
and the thrown Error object. For status-specific handling, check the
response.status before throwing to create different error types or messages for
common HTTP errors like 401 (Unauthorized), 404 (Not Found), and 500 (Server
Error), allowing calling code to handle different failure scenarios
appropriately. This maintains the current pattern of logging and re-throwing
while providing richer debugging information and more granular error handling
capabilities.
src/components/RestaurantList/RestaurantList.module.css (1)

13-24: 💤 Low value

스타일 린터 경고를 해결하세요.

Stylelint에서 선언 전 빈 줄에 대한 경고를 발생시키고 있습니다 (lines 17, 20). 이는 기능에 영향을 주지 않지만 코드 스타일 일관성을 위해 수정하는 것이 좋습니다.

🎨 제안하는 수정 방안
 .restaurant__button {
   display: flex;
   align-items: flex-start;
-
   width: 100%;
   padding: 16px 8px;
-
   background: none;
   border: none;
   cursor: pointer;
   text-align: left;
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/RestaurantList/RestaurantList.module.css` around lines 13 -
24, The `.restaurant__button` CSS class has empty lines before property
declarations that are triggering Stylelint warnings. Remove the blank lines that
appear before the `width` property and before the `background` property to
maintain consistent formatting without unnecessary blank lines between CSS
property declarations within the rule.

Source: Linters/SAST tools

src/hooks/useRestaurants.js (1)

4-22: 커스텀 훅 생성에 대한 피드백

PR 설명에서 커스텀 훅을 언제, 어떻게 만들어야 하는지에 대한 피드백을 요청하셨습니다. 현재 useRestaurants 훅은 매우 잘 설계되었습니다!

커스텀 훅을 만들기 좋은 경우 (현재 케이스가 해당):

  • 관련된 상태와 로직을 함께 캡슐화 (restaurants 상태 + fetch/add 로직)
  • 여러 컴포넌트에서 재사용 가능한 로직
  • 비즈니스 로직을 UI 로직과 분리
  • 복잡한 effect나 여러 hook의 조합을 단순화

잘된 점:

  • useCallback으로 fetchRestaurants를 최적화
  • useEffect에서 초기 데이터 로딩
  • 명확한 인터페이스 (restaurants, addRestaurant)

💡 개선 제안:

  • 로딩 상태 추가: const [loading, setLoading] = useState(false)
  • 에러 상태 추가 (위 코멘트 참조)
  • 반환값 확장: { restaurants, addRestaurant, loading, error }

이러한 개선사항을 구현하는 데 도움이 필요하시면 말씀해 주세요!

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/hooks/useRestaurants.js` around lines 4 - 22, The useRestaurants hook
needs to track loading and error states to provide more complete state
management. Add two new state variables using useState for loading and error
states. Update the fetchRestaurants function to set loading to true before the
async call, false after completion, and capture any errors that occur during the
getRestaurants call. Apply the same loading and error handling pattern to the
addRestaurant function. Finally, expand the return object to include the new
loading and error states alongside restaurants and addRestaurant so consuming
components can handle pending and failed states appropriately.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/api.js`:
- Line 1: The BASE_URL constant is hardcoded with a local development value,
which limits flexibility across different deployment environments. Replace the
hardcoded string value in BASE_URL with a reference to the environment variable
using import.meta.env.VITE_API_URL, which will allow the API URL to be
configured differently for development, staging, and production environments
through environment configuration files.

In `@src/App.jsx`:
- Around line 41-44: The handleRestaurantSubmit function lacks error handling
for the addRestaurant call, causing silent failures where the modal closes
regardless of success or failure, leaving users unaware of issues. Wrap the
await addRestaurant(restaurant) call in a try-catch block, only calling
setIsAddRestaurantModalOpen(false) in the success path (try block), and handle
the catch block by either displaying an error message to the user via a toast
notification or managing an error state so users receive feedback about what
went wrong.

In `@src/hooks/useRestaurants.js`:
- Around line 16-19: The addRestaurant function in the useRestaurants hook lacks
error handling, which means when createRestaurant or fetchRestaurants fails, the
error propagates silently without user notification. Add a try/catch block
within the addRestaurant function to catch any errors from createRestaurant or
fetchRestaurants, then re-throw the error so that the calling component (App)
can handle it with proper error handling and user notification. This ensures
users are informed when restaurant addition fails.
- Around line 7-14: The fetchRestaurants callback function lacks error handling
when calling getRestaurants(), which means any API errors propagate silently
without user notification or state tracking. Wrap the getRestaurants() call in a
try-catch block, capture any errors that occur, and store them in an error state
variable using a new useState hook for error management. Return the error state
along with restaurants from the useRestaurants hook so that calling components
can properly handle and display errors to users. This prevents failures from
going undetected while leaving restaurants as an empty array.

---

Outside diff comments:
In `@05-effects/README.md`:
- Around line 59-63: The code block on lines 59-63 in the README.md file is
missing a language identifier in the markdown code fence. Add the language
identifier "text" immediately after the opening triple backticks to enable
syntax highlighting and resolve markdown linter warnings. Change the opening
fence from triple backticks with no language to triple backticks followed by
"text" before the code block containing the fetch, getRestaurants, and
handleRestaurantSubmit function descriptions.

---

Nitpick comments:
In `@src/api.js`:
- Around line 15-27: The createRestaurant function does not return the
restaurant data created by the server. To improve network efficiency and enable
immediate UI updates, parse the response body as JSON in the createRestaurant
function and return the created restaurant object (which will include
server-assigned data like id and timestamp) so the caller can use it without
refetching the entire list. This change should occur after the response
validation in the try block, before the catch block.
- Around line 3-27: To implement the optional error handling improvements,
enhance both getRestaurants() and createRestaurant() functions with more
detailed error context and status code-specific handling. For error context,
include the request URL in the error message passed to console.error and the
thrown Error object. For status-specific handling, check the response.status
before throwing to create different error types or messages for common HTTP
errors like 401 (Unauthorized), 404 (Not Found), and 500 (Server Error),
allowing calling code to handle different failure scenarios appropriately. This
maintains the current pattern of logging and re-throwing while providing richer
debugging information and more granular error handling capabilities.

In `@src/components/RestaurantList/RestaurantList.module.css`:
- Around line 13-24: The `.restaurant__button` CSS class has empty lines before
property declarations that are triggering Stylelint warnings. Remove the blank
lines that appear before the `width` property and before the `background`
property to maintain consistent formatting without unnecessary blank lines
between CSS property declarations within the rule.

In `@src/hooks/useRestaurants.js`:
- Around line 4-22: The useRestaurants hook needs to track loading and error
states to provide more complete state management. Add two new state variables
using useState for loading and error states. Update the fetchRestaurants
function to set loading to true before the async call, false after completion,
and capture any errors that occur during the getRestaurants call. Apply the same
loading and error handling pattern to the addRestaurant function. Finally,
expand the return object to include the new loading and error states alongside
restaurants and addRestaurant so consuming components can handle pending and
failed states appropriately.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 18342010-de44-499c-a510-16820c1f967c

📥 Commits

Reviewing files that changed from the base of the PR and between 1693b41 and f9cc036.

📒 Files selected for processing (12)
  • .coderabbit.yaml
  • 05-effects/README.md
  • README.md
  • src/App.jsx
  • src/api.js
  • src/components/AddRestaurantModal/AddRestaurantModal.jsx
  • src/components/CategoryFilter/CategoryFilter.jsx
  • src/components/RestaurantList/RestaurantList.jsx
  • src/components/RestaurantList/RestaurantList.module.css
  • src/constants/categories.js
  • src/constants/restaurants.js
  • src/hooks/useRestaurants.js
💤 Files with no reviewable changes (1)
  • src/constants/restaurants.js

Comment thread src/api.js
Comment thread src/App.jsx
Comment thread src/hooks/useRestaurants.js
Comment thread src/hooks/useRestaurants.js
Comment thread src/api.js
headers: { "Content-Type": "application/json" },
body: JSON.stringify(restaurant),
});
if (!response.ok) throw new Error(`서버 오류: ${response.status}`);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
리드미에서 에러 처리를 고민하신 걸 봤는데, 최종적으로 api는 어차피 호출부에 throw를 해줘야 하니까 catch를 제거해서 불필요한 코드를 삭제하신 부분 좋은 것 같아요! '에러를 처리할 수 있는 곳에서만 잡는다'는 원칙도 좋은 기준인 것 같습니다!

}, []);

useEffect(() => {
void fetchRestaurants();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
fetchRestaurants()void로 호출하신 부분 좋은 것 같아요. async 함수를 useEffect 안에서 호출하면 Promise가 반환되는데, React는 cleanup 함수(또는 undefined)만 기대하기 때문에 void로 반환값을 명시적으로 버리는 패턴이군요! 저도 적용해보겠습니다.

Comment on lines +16 to +18
} finally {
setIsLoading(false);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
요구사항에 없는 로딩 상태까지 구현하신 게 인상적이에요! setIsLoading(false)try/catch 양쪽에 중복으로 쓰는 대신 finally로 한 번만 쓴 것도 깔끔하고 좋은 것 같아요. 성공/실패와 무관하게 반드시 실행돼야 하는 코드는 finally에 두는 패턴 좋은 기준인 것 같아요.

@@ -1 +1,2 @@
export const ALL_CATEGORY = "전체";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
저번 미션에서 매직 스트링을 리팩토링했으면서도 "전체" 문자열이 매직 스트링이라고 인지를 못하고 있었어요. 카테고리 상수에서 관리하는 것 좋은 것 같아요! 저도 적용해보겠습니다!

Comment on lines +5 to +12
useEffect(() => {
function handleKeyDown(e) {
if (e.key === "Escape") onClose();
}
document.addEventListener("keydown", handleKeyDown);
return () => document.removeEventListener("keydown", handleKeyDown);
}, [onClose]);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
키보드 사용자도 모달을 닫을 수 있도록 접근성까지 고려한 게 진짜 꼼꼼하신 것 같아요! cleanup 함수로 이벤트 리스너를 제거하지 않으면 모달을 열고 닫을 때마다 리스너가 누적된다는 건 미처 생각 못했는데, 컴포넌트가 사라져도 자동으로 정리되지 않는 것들은 반드시 cleanup이 필요하다는 것 덕분에 알게 됐어요.

onClick={onAddButtonClick}
>
<img src={addButton} alt="음식점 추가" />
<img src={addButton} />

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
그러고 보니 버튼에 aria-label이 있는데 이미지에도 alt가 있으면 스크린 리더가 중복해서 읽게 되겠네요. 템플릿을 옮겨오는 과정에서 별 생각 없이 적용한 코드였는데, 접근성까지 챙겨서 리팩토링하신 부분이 인상깊어요. 저도 제거해볼게요!

Comment thread src/api.js
@@ -0,0 +1,16 @@
const BASE_URL = "http://localhost:3000";

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

[배움]
http://localhost:3000이 두 곳에 반복되는 걸 상수로 추출하신 부분 실무에서도 자주 쓰이는 패턴인 것 같아요. 저도 적용해볼게요!

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.

2 participants