From 0d262a8612a47fb7bce0e624b892d2bf66116dbc Mon Sep 17 00:00:00 2001 From: wo-o29 Date: Tue, 14 Oct 2025 10:37:27 +0900 Subject: [PATCH] docs: clean up and fix debug documentation --- fundamentals/debug/pages/diagnose/map.md | 14 ++++++------- fundamentals/debug/pages/fix/correct.md | 4 ++-- fundamentals/debug/pages/fix/dead-code.md | 2 +- fundamentals/debug/pages/fix/pure.md | 14 +++++++------ fundamentals/debug/pages/prevent/util.md | 4 ++-- fundamentals/debug/pages/reproduce/repeat.md | 6 +++--- fundamentals/debug/pages/reproduce/simply.md | 21 +++++++++++--------- fundamentals/debug/pages/reproduce/trace.md | 2 +- 8 files changed, 36 insertions(+), 31 deletions(-) diff --git a/fundamentals/debug/pages/diagnose/map.md b/fundamentals/debug/pages/diagnose/map.md index 4c2b0a17..90377132 100644 --- a/fundamentals/debug/pages/diagnose/map.md +++ b/fundamentals/debug/pages/diagnose/map.md @@ -31,25 +31,25 @@ 아래 코드에는 치명적인 오류가 있는데요, 작업 지도를 하나씩 검증하며 어디에 문제가 발생하는지 살펴보아요. ```tsx 8,15,19,26 -import React, { useState } from "react"; +import { useState } from "react"; -const ValidatedInput = () => { +function ValidatedInput() { const [input, setInput] = useState(""); const [isValid, setIsValid] = useState(true); const validate = (value) => { - //2. 입력이 바뀔 때마다 유효성 검사 함수가 실행돼요:" + // 2. 입력이 바뀔 때마다 유효성 검사 함수가 실행돼요 const valid = value.length < 5; return valid; }; const handleChange = (e) => { const value = e.target.value; - //1. 사용자가 검색 입력창에 키워드를 입력해요 + // 1. 사용자가 검색 입력창에 키워드를 입력해요 setInput(value); const result = validate(value); - //3. 검사 결과에 따라 true/false를 반환해요 + // 3. 검사 결과에 따라 true/false를 반환해요 setIsValid(result); }; @@ -60,7 +60,7 @@ const ValidatedInput = () => { {isValid &&
Error message
} ); -}; +} export default ValidatedInput; ``` @@ -68,7 +68,7 @@ export default ValidatedInput; ## 에러 도출 -검증 결과, `isValid &&` 조건으로 작성된 에러 UI 렌더링 부분에 **논리 오류**가 있었어요.`isValid === false`로 작성해야 하는데, `isValid &&`로 되어 있어서, **정상적인 UI가 아닌, 잘못된 조건에 의해 오류 메시지가 렌더링**되고 있었어요. +검증 결과, `isValid &&` 조건으로 작성된 에러 UI 렌더링 부분에 **논리 오류**가 있었어요.`isValid === false &&`로 작성해야 하는데, `isValid &&`로 되어 있어서, **정상적인 UI가 아닌, 잘못된 조건에 의해 오류 메시지가 렌더링**되고 있었어요. ```tsx 4 return ( diff --git a/fundamentals/debug/pages/fix/correct.md b/fundamentals/debug/pages/fix/correct.md index b180ce38..ff9139c1 100644 --- a/fundamentals/debug/pages/fix/correct.md +++ b/fundamentals/debug/pages/fix/correct.md @@ -54,7 +54,7 @@ console.log(selectedUser?.name ?? "사용자 없음"); ```tsx function SearchBox() { const [query, setQuery] = useState(""); - const [result, setResult] = useState(""); + const [results, setResults] = useState([]); useEffect(() => { if (!query) return; @@ -62,7 +62,7 @@ function SearchBox() { fetch(`/api/search?q=${query}`) .then((res) => res.json()) .then((data) => { - setResult(data); + setResults(data); }); }, [query]); diff --git a/fundamentals/debug/pages/fix/dead-code.md b/fundamentals/debug/pages/fix/dead-code.md index f80963b8..49de8213 100644 --- a/fundamentals/debug/pages/fix/dead-code.md +++ b/fundamentals/debug/pages/fix/dead-code.md @@ -56,7 +56,7 @@ A/B 테스트가 끝났는데 분기 코드가 남아 있으면, 독자가 “ ```tsx export function RecommendationBanner({ variant }: { variant: "A" | "B" }) { - //TODO:: 종료된 실험 제거 (실험안 A으로 종료) + //TODO: 종료된 실험 제거 (실험안 A로 종료) if (variant === "A") { return ; } else { diff --git a/fundamentals/debug/pages/fix/pure.md b/fundamentals/debug/pages/fix/pure.md index 8ce4fdde..93ebac85 100644 --- a/fundamentals/debug/pages/fix/pure.md +++ b/fundamentals/debug/pages/fix/pure.md @@ -72,11 +72,11 @@ function OrderSummary({ ## 예시: React Hook을 활용해 팝업창을 보여줄 때 -react의 hook예시도 들어볼게요. 모달을 보여주는 로직이에요. +react의 hook 예시도 들어볼게요. 모달을 보여주는 로직이에요. ### 기존코드 -`localStorage`, `isTodayShown`등과 같은 여러 로직이 `useEffect` 내부에 흩어져 있어 모듈화되어 있지 않아요. 그래서 가독성도 떨어지고, 테스트도 어려워요3. +`localStorage`, `isTodayShown`등과 같은 여러 로직이 `useEffect` 내부에 흩어져 있어 모듈화되어 있지 않아요. 그래서 가독성도 떨어지고, 테스트도 어려워요. ```tsx const STORAGE_KEY = "notification-modal-shownAt"; @@ -141,6 +141,8 @@ export function setLocalStorageValue(key: string, value: string): void { **utils/modal.ts** ```tsx +import { getLocalStorageValue, setLocalStorageValue } from "./localStorage"; + export function getIsModalShownToday(modalKey: string) { const lastShown = getLocalStorageValue(modalKey); const todayDateString = new Date().toDateString(); @@ -158,7 +160,7 @@ export function setModalShownToday(modalKey: string) { ```tsx import { useEffect, useState } from "react"; -import { useNotificationAgreementState } from "./useNotificationAgreementState"; // 필요 시 경로 조정 +import { getIsModalShownToday, setModalShownToday } from "./utils/modal"; const MODAL_KEY = "test1"; export function useIsModalShow() { @@ -170,7 +172,7 @@ export function useIsModalShow() { setModalShownToday(MODAL_KEY); setShowModal(true); } - }, [isAgreed]); + }, []); const close = () => { setShowModal(false); @@ -186,7 +188,7 @@ export function useIsModalShow() { **HomePage.tsx** ```tsx -import { useIsModalShow } from './hooks/useIsModalShow'; +import { useIsModalShow } from "./hooks/useIsModalShow"; function HomePage() { const { showModal, close } = useIsModalShow(); @@ -194,7 +196,7 @@ function HomePage() { return ( <>

Welcome!

- } + ); } diff --git a/fundamentals/debug/pages/prevent/util.md b/fundamentals/debug/pages/prevent/util.md index 88a84edb..d45b89fd 100644 --- a/fundamentals/debug/pages/prevent/util.md +++ b/fundamentals/debug/pages/prevent/util.md @@ -70,7 +70,7 @@ module.exports = { }; ``` -## 린린트 룰에 더미텍스트 확인 추가 +## 린트 룰에 더미텍스트 확인 추가 ### 문제 @@ -78,7 +78,7 @@ UI 개발 도중 사용한 더미 이름, 가짜 텍스트(“김토스님”, ### 해결방법 -ESLint로 특정 문자열(“김토스”, “홍길동”, “테스트용” 등) 포함 시 에러 발생하도록 설정해요. `no-restricted-syntax`는특정 구문(Syntax)을 아예 사용하지 못하도록 제한하는 ESLint 규칙이에요. +ESLint로 특정 문자열(“김토스”, “홍길동”, “테스트용” 등) 포함 시 에러 발생하도록 설정해요. `no-restricted-syntax`는 특정 구문(Syntax)을 아예 사용하지 못하도록 제한하는 ESLint 규칙이에요. ```js 6 module.exports = { diff --git a/fundamentals/debug/pages/reproduce/repeat.md b/fundamentals/debug/pages/reproduce/repeat.md index 48bf5963..c5199adb 100644 --- a/fundamentals/debug/pages/reproduce/repeat.md +++ b/fundamentals/debug/pages/reproduce/repeat.md @@ -11,7 +11,7 @@ 예를 들어, 동일한 요청이 여러 번 반복될 때 비정상적인 화면이 보여지는 버그 리포트를 받았다고 가정해 볼게요. 이 문제를 재현하기 위해, 다음처럼 **자동 클릭 함수**를 만들어 반복적인 클릭 상황을 만들어 볼 수 있어요. 그리고 디버거를 걸어서 중간 중간 값이 어떻게 변경되는지 추적해볼 수 있어요. ```tsx -import React, { useState } from "react"; +import { useState } from "react"; function simulateRapidClicks( target: HTMLElement, @@ -26,7 +26,7 @@ function simulateRapidClicks( }, interval); } -const DoubleClickTest = () => { +function DoubleClickTest() { const [count, setCount] = useState(0); const [disabled, setDisabled] = useState(false); @@ -53,7 +53,7 @@ const DoubleClickTest = () => { ); -}; +} export default DoubleClickTest; ``` diff --git a/fundamentals/debug/pages/reproduce/simply.md b/fundamentals/debug/pages/reproduce/simply.md index 7a2bca14..dd3ff28e 100644 --- a/fundamentals/debug/pages/reproduce/simply.md +++ b/fundamentals/debug/pages/reproduce/simply.md @@ -8,14 +8,14 @@ 예를 들어, 숫자 배열에서 짝수만 필터링하는 로직에 문제가 생겼다고 가정해볼게요. 원래 코드에서는 컴포넌트에서 하는 일이 많아서 어디서부터 문제가 발생한 건지 알기 어려워요. -현재 컴포넌트에서는 데이터 fetching, 필터링 로직, 상태 업데이트, 사용자 이벤트 처리가 하나의 함수 안에 모여 있어요. 이처럼 책임이 분리되지 않으면, 특정 결과(filteredNumbers)가 잘못되었을 때 어떤 로직에서 문제가 발생했는지 파악하기가 어려워요. 특히 여러 상태 변화가 엮여 있을 경우, 상태 간의 상호작용이나 렌더 타이밍까지 함께 고려해야 하므로 디버깅이 복잡해질 수 있어요. +현재 컴포넌트에서는 데이터 fetching, 필터링 로직, 상태 업데이트, 사용자 이벤트 처리가 하나의 함수 안에 모여 있어요. 이처럼 책임이 분리되지 않으면, 특정 결과(`filteredNumbers`)가 잘못되었을 때 어떤 로직에서 문제가 발생했는지 파악하기가 어려워요. 특히 여러 상태 변화가 엮여 있을 경우, 상태 간의 상호작용이나 렌더 타이밍까지 함께 고려해야 하므로 디버깅이 복잡해질 수 있어요. ```tsx -import React, { useState, useEffect } from "react"; +import { useState, useEffect } from "react"; function filterEvenNumbers(numbers) { return numbers.filter((num) => { - return num % 2 === 1; + return num % 2 === 0; }); } @@ -73,28 +73,31 @@ export default ComplexComponent; ### 간단하게 줄여보기 -위 코드를 아래 코드처럼 간단하게 줄여서 테스트해볼 수 있어요. 원래 컴포넌트의 상태 관리, 비동기 호출, UI 요소를 제거하고, 핵심 로직인 filterEvenNumbers 함수만 간단한 배열로 테스트할 수 있도록 최소한의 코드로 줄였어요. +위 코드를 아래 코드처럼 간단하게 줄여서 테스트해볼 수 있어요. 원래 컴포넌트의 상태 관리, 비동기 호출, UI 요소를 제거하고, 핵심 로직인 `filterEvenNumbers` 함수만 간단한 배열로 테스트할 수 있도록 최소한의 코드로 줄였어요. 이렇게 코드를 단순화하면 복잡한 상태 관리나 네트워크 요청 없이도 문제가 발생하는 조건만으로 에러를 재현할 수 있어요. 이런 방식으로 문제를 단순하게 재현하고, 원인을 찾은 다음 원래 코드에 다시 반영하면 돼요. ```tsx -import React, { useEffect } from "react"; +import { useState, useEffect } from "react"; function filterEvenNumbers(numbers) { return numbers.filter((num) => { - return num % 2 === 1; + return num % 2 === 0; }); } -const SimpleComponent = () => { +function SimpleComponent() { + const [filteredNumbers, setFilteredNumbers] = useState([]); + useEffect(() => { const testArray = [1, 2, 3, 4, 5, 6]; const result = filterEvenNumbers(testArray); + setFilteredNumbers(result); }, []); - return
테스트 중...
; -}; + return
filteredNumbers: {filteredNumbers.join(", ")}
; +} export default SimpleComponent; ``` diff --git a/fundamentals/debug/pages/reproduce/trace.md b/fundamentals/debug/pages/reproduce/trace.md index da67c39d..b7c107e8 100644 --- a/fundamentals/debug/pages/reproduce/trace.md +++ b/fundamentals/debug/pages/reproduce/trace.md @@ -16,4 +16,4 @@ **이전 상태가 현재 동작에 영향을 줄 수 있어요** -- 버그가 발생한 화면만 보지 말고, **그 전에 어떤 상태였는지를 함께 살펴봐야 해요.** 예를들어, `A 화면에서 특정 항목을 선택한 후, B 화면으로 넘어왔을 때만 발생함`처럼, **이전 컨텍스트가 버그의 중요한 재현 조건이 되는 경우**가 많아요. +- 버그가 발생한 화면만 보지 말고, **그 전에 어떤 상태였는지를 함께 살펴봐야 해요.** 예를 들어, `A 화면에서 특정 항목을 선택한 후, B 화면으로 넘어왔을 때만 발생함`처럼, **이전 컨텍스트가 버그의 중요한 재현 조건이 되는 경우**가 많아요.