Skip to content
잼얘람 edited this page Nov 26, 2025 · 44 revisions

스터디 내용 작성


  • 4주차

useState란?

  • 컴포넌트 상태관리, 상태가 변경 될 때 화면을 다시 렌더링해야하는 모든 경우에 사용

📌 꼭 써야하는 상황 -> 컴포넌트 상태가 사용자의 상호작용이나 데이터 fetching 등 특정 이벤트에 의해 변경되고, 그 변경된 값이 화면에 즉시 반영되어야할 때

  • 폼 입력값 관리 : 회원가입, 로그인, 글쓰기 등 사용자가 입력하는 아이디, 비밀번호, 이메일 등 값 관리 시 사용

  • UI 상태관리 : 모달 창의 열림/닫힘 상태, 탭 메뉴의 활성화 상태, 아코디언 메뉴의 펼침/접힘 상태 등 사용자의 행동에 따라 UI가 바뀌어야 할 때 사용

  • 데이터 Fetching 후 상태 관리 : 서버로부터 받아온 데이터를 화면에 표시해야할 때 사용. 로딩중, 성공, 실패와 같은 데이터 fetching 상태 관리시에도 유용

  • 카운터 및 토글 : 버튼 클릭시 숫자를 증가/감소 시키거나 , 스위치를 켜고 끄는 등 간단한 상호작용 구현시 사용

📌 불필요한 상황 -> 컴포넌트가 다시 렌더링 될 필요 x, useState 특성으로 인해 불필요한 성능 저하 유발가능 경우 피하는게 좋음

  • 단순변수 : 컴포넌트가 리렌더링 되어도 값이 유지될 필요가 없는, 함수의 사용되는 임시 변수는 useState로 선언할 필요가없음. 일반적으로 let이나 const로 선언하면 됨

  • 리렌더링이 불필요한 값 : 값이 변경되어도 화면이 바뀔 필요가 없는 경우, useState 대신 useRef를 사용하는 것이 효율적. useRef는 값이 변경되어도 리렌더링 x(스크롤 위치 기억, 이전 상태 값 저장, DOM요소에 직접 접근 시)

  • 전역상태 관리 : 여러 컴포넌트에서 공유하고 사용하는 상태(예시,로그인한 유저 정보, 테마설정)을 useState만으로 관리하면 'Props Drilling'(상태를 계속해서 자식 컴포넌트로 내려주는 것) 문제 발생가능, 이경우 Context API, Recoil, Zustand, Redux와 같은 상태관리 라이브러리를 사용하는 것이 더 좋음

  • 컴포넌트 외부에서 관리되는 값 : 컴포넌트의 렌더링 주기와 상관없는 라이브러리의 인스턴스나 전역객체 등은 useState로 관리할 필요가 없음


페이지 간 데이터 전달 해결방안

  1. 전역상태관리
  • 공용창고를 만드는 방식
  • 도구 : Redux, Recoil, Zustand or Context API& useReducer
  • 작동 방식 : 입력 데이터를 공용 창고에 넣어두고, 다음 페이지에서 데이터를 꺼내어 사용
  1. URL쿼리 파라미터 이용
  • 입력된 데이터를 주소에 실어 보내기
  • 민감정보거나 데이터가 많으면 비추천
  • 사용자가 뒤로 가기/앞으로 가기 할때, 브라우저가 파라미터들을 기억하여 상태복원(검색결과 및 필터링 값 공유, 페이지네이션, 임시적인 식별자 전달_로그인안한상태에서 장바구니에 물건 담았을때)
  1. 브라우저 저장소 이용
  • 도구 : sessionStorage(브라우저 닫으면 사라짐) localStroage(영구저장)
  • 영구저장은 다크모드설정, 언어설정, 다시보지않기 설정, 자동로그인을 위한 토큰저장시사용(나갔다 들어와도 설정값을 기억하여 편의성 증가 )
  • sessionStroage는 작성중인 글, 방금봤던 광고 팝업 상태 등에서 사용 됨
  • 빠른접근성으로 서버에 매번 안물어봐도 사용자 컴퓨터에서 바로 정보르르 가져와 사이트 로딩 속도를 높임

상태선언

useState를 사용하여 UI제어 및 인력 값 트래킹을 위해 사용

const [loginid, setLoginId] = useState(''); -> loginid는 값을 읽을 때 사용하는 이름 (상태 변수, 현재값을 담고있는 상자. 읽기전용이라 변경 불가) -> setLoginId 를 사용해야만 새로운 값으로 변경가능(업데이트 함수, 그 상자안의 값을 바꾸는 버튼, 쓰기전용이라 새 값을 인수로 넣어주면 상태변경 됨) -> useState('') 는 초기값. 처음 생성시 아무것도 없다는 것을 의미하기 위하여 빈 값으로 둠 (false, true 들어갈 수 있음)

const [isCodeSent, setIsCodeSent] = useState<boolean>(false); -> boolean 타입만 들어갈 수 있도록 명시

상태선언은

const [상태 이름, set상태 이름] = useState(초기값);


전역상태관리 (dispatch)

dispatch는 Context API 와 함께 useReducer 패턴으로 구현된 전역상태 업데이트 함수. 상태를 불변성있게 관리하며 단방향 데이터흐름을 유지. 1페이지 데이터를 Context Stroage에 저장하여 2페이지 컴포넌트가 데이터 참조가 가능하도록 상태를 영속화 함.

dipatch({ type: '액션 이름' payload: 바꿀 정보 });

액션타입

RESET_FORM UPDATE_FORM_DATA SET_FIELD SET_ERROR
모든 정보를 처음으로 되돌리기 paload에 담긴 데이터를 기존 상태에 병합하라는 명령 이름 ,규칙 식별자 하나의 정보만 변경 전역적으로 중요한 에러 메시지 저장
회원가입 최종 성공, 사용자가 회원가입을 취소할 때 사용 한 필드만 업데이트, 복잡하지않은 간단한 상태 변경시 사용 서버 인증 과정 중 발생하는 에러를 전체 앱에 공유해야할 때 사용

✏️Context 를 구현할 때 정의했던 Reducer함수 내부의 switch 문에서 사용 -> Reducer(Context 저장소 담당)는 dispatch가 보낸 액션이 도착하면 다음과 같이 동작

image

이벤트 핸들링 (아이디)

image

(e:React.ChangeEvent<HTMLInputElement>)
-> input 요소의 값이 변경 될때 발생하는 합성 이벤트를 인자로 받음. HTMLInputElemet 가 관련된 이벤트임을 명시

const value = e.target.value; setLoginId(value);
-> 이벤트 객체 (e)의 target 속성에서 현재 입력된 값 추출 (input 박스에 작성된 값을 value에 옮겨 담기) Hooks API를 통해 loginid 상태를 비동기적으로 업데이트

setIsLoginIdChecked(false)
-> 입력값이 변경되면 기존 중복 검증결과 무효처리. 재검증 유도를 위해 false로 리셋

if (!/^[a--zA-Z0-9]*$/.test(value))
-> 정규 표현식을 사용한 형식 유효성 검사. 문자열의 시작(^)부터 끝($)까지 영문 대소문자와 숫자만 포함해야 함을 의미

사용법 -> onChange속성에 이벤트 핸들러로 바인딩


전화번호 인증요청 로직

image

const handleSendCode = async (e: React.MouseEvent) => { ... } -> 비동기 작업을 포함하는 React 마우스 클릭 이벤트 핸들러. e.preventDefault(); 을 호출하여 폼 제출과 같은 기본 이벤트 동작 방지

setVerificationError(''); -> 이전 요청 에러상태 초기화

const res = await axios.post('/api/auth/signup', { phonenumber }); -> axios 라이브러리를 이용하여 POST 요청. 서버 주소 엔드포인트에 phonenumeber를 요청 본문에 담아 비동기적으로 전송

if (axios.isAxiosError(error) && error.response) -> 에러가 axios 통신 과정에서 발생했으며 서버로부터 응답을 받은 경우 확인. error.response.data 를 통해 서버가 보낸 구체적 에러 메시지를 콘솔에 로깅

사용법

  1. useState훅을 통해 상태가 정의되어있어야함
  • 휴대폰 번호상태
  • 인증번호 발송여부(재전송 확인용)
  • 에러메시지 상태 등
  1. 인증번호 발송 버튼에 onClick이벤트에 보통 연결됨

  • 5주차

연동준비

  1. 데이터 및 상태 정의 -> value 값과 erd 값 맞추기, useState로 미리 정의된 값 사용

  2. 통신 방법 및 규칙 정의 (백/프론트 협의) -> HTTP 메서드 정의, CRUD에 맞는 메서드 정의 -> API 주소 설정하기 (각 기능별 엔드포인트 주소 확정, 프론트엔드에서 사용할 주소를 명확히하기 -> 요청(Reques)시 보낼 데이터 구조와 필수값 확정, 응답 (Response)로 받을 데이터의 구조와 성공/실패 메시지 확정 -> 에러코드 및 형식 확정(HTTP상태코드를 백엔드로부터 받아서(4xx,5xx) 에러메시지 JSON 형식 정의)

  3. 인증/인가 -> 로그인 후 사용자 식별을 위해 JWT토큰을 사용할지, 세션/쿠키를 사용할지 확정하고 토큰 저장소 결정 -> 헤더 설정 정의 (API 요청시 인증토큰을 HTTP헤더의 Authorization 필드에 어떻게 넣을지 (Bearer<토큰>) 정의

  4. 환경설정 및 연동 구조 -> 프록시 설정 (개발 환경에서 CORS 문제 해결을 위해 next.config.js 파일에 rewriters 설정 완료


도메인

인터넷상의 집 주소 -> 백엔드에서 처리


Swagger(스웨거)

API를 설계, 구축, 문서화 및 사용하는데 도움을 주는 도구 및 기술


ERD

데이터베이스에 저장될 데이터의 구조와 관계를 시각적으로 표현한 것


JWT 토큰

JSON Web Token의 약자로, 웹앱에서 인증과 정보교환을 위해 사용되는 전자 서명 된 토큰 사용자가 로그인했을 때 서버가 발급하고, 브라우저(클라이언트) 가 이를 저장했다가 API 요청시 서버에 함께 보내 본인임을 증명하는데 사용


HTTP 메서드

메서드 GET POST PUT PATCH DELETE
RESTfull용도 READ(조회) CREATE(생성) UPDATE(전체수정) UPDATE(부분수정) DELETE(삭제)
사용목적 서버의 특정 자원이나 목록을 가져올 때 사용, 서버상태변경X 서버에 새로운 자원 생성,매 요청마다 새로운 자원 생성 가능 특정 자원을 완전히 새로운 데이터로 덮어쓸 때, 같은요청 여러번 보내도 결과는 동일 특정 자원의 일부 필드만 수정 할때. PUT보다 효율적 서버의 특정 자원을 제거할때, 같은 요청 여러번 보내도 최종결과는 삭제된 상태로 동일
데이터전송방법 URL파라미터(필터링,정렬기준 등) Body(생성할 자원의 데이터,회원가입 정보 등) Body(자원의 모든 필드 데이터) Body(수정할 필드와 값만 포함) URL파라미터(삭제할 자원의 ID)

아이디 중복요청, 닉네임 중복 요청 등 민감 정보를 요청해야하는경우 파라미터 값으로 보내는 GET요청 보다는 POST를 주로 사용함


데이터 전송방식

A. URL 파라미터

  • 주로 GET이나 DELETE요청시, 서버가 어떤 자원을 처리해야할지 식별하거나 추가적인 옵션을 제공할 때 사용

  • 데이터가 URL에 노출 되므로, 비밀번호 같은 민감정보는 사용 안함

  • 유형 a. 쿼리 파라미터

    • URL 끝에 ?를 붙이고 key=value 형태로 전송. 여러개는 &로 연결
    • 예시 : /products**?category=shoes&limit=10** (상품 목록 필터링/페이징)

    b.경로 변수(Path Variable)

    • URL의 경로 자체에 값을 포함하여 자원을 식별
    • 예시 : /users/12345 (ID가 12345인 사용자 조회)

B. 요청본문(Request Body)

  • 주로 POST,PUT,PATCH요청시 , 서버에 새로 만들거나 수저할 데이터 덩어리를 보낼 때 사용
  • URL에 데이터가 노출되지 않으며 크기 제한도 거의 없음
  • 가장 일반적인 형식은 JSON
image
  • PUT : 자원 식별자는 경로변수로 보내고 수정 데이터는 Body로 보냄. 값이 없어도 필드를 포함해야됨
  • PATCH : 특정 자원의 데이터 중 일부 필드만 수정할 때 사용. 자원 식별바는 경로변수로 보내고 수정할 필드만 Body로 보냄
  • DELETE : 경로변수로 보내고 보통 Body 사용 x
image

TypeScript

문법 JavaScript(useState('') TypeScript(useState('')
차이 타입이 동적으로 결정됨 타입이 명시적으로 string 으로 고정
안정성 안정성은 낮지만 유연 안정성 높고, 오류 미리 찾기 가능

변수와 상태 컴포넌트 속성에 연결하기

  • 변수, 함수, 혹은 상태(State)값을 연결하려면 중괄호를 반드시 이용해야함

{}를 안쓴다면...

코드 React 인식 방식 결과
value ={username} JS변수username에 저장된 실제 값 상태(State)와 인풋값이 연동되어 값이 변함
value="username" 'username"이라는 문자열 인풋 값은 항상"username"으로 고정됨

🔑 {}의 역할: JSX에서 JS사용하기

  • React의 JSX문법에서 중괄호 {}는 일종의 이스케이프 문자역할을 함
  • "이 따옴표 안의 내용은 HTML 텍스트가 아닌 실행해야할 JavaScript코드입니다" 라고 React에게 알려주는 유일한 방법
목적 코드 설명
변수 값 연결 value = {username} username 변수의 값을 인풋의 값으로 결정
함수 연결 onChange={e => setName(e.target.value)} onChange이벤트가 발생했을 때 지정된 함수를 실행
조건부 렌더링 {isLoggendIn && 로그아웃 isLoggedIn 이 참(True)일때만 을 렌더링

동적으로 변화하는 상태나 실행할 로직을 연결하려면 반드시 {}을 사용해야함


next.config.js

const nextConfig = { ... }; -> Next.js 설정 옵션을 담는 자바스크립트 객체

module.export = nextConfig -> Node.js 환경에서 이 객체를 Next.js 프레임워크가 읽을 수 있도록 모듈로 내보내기

  1. rewrites 함수

async rewrites() {. . .} -> Next.js 서버가 요청을 받은 후, 지정된 규칙에 따라 **요청 경로를 변경(재작성)**하도록 지시하는 비동기 함수

const backendUrl = process.env.BACKEND_URL; -> .env 파일 등에 정의된 환경 변수의 값 읽어오기. 이 값은 백엔드 실제주소임. 보안상 클라이언트에 노출 X

if (!backendUrl) {...} -> 백엔드 주소 환경 변수가 설정되지 않았을 경우를 대비한 안전장치. 콘솔에 경고 출력, 프록시 규칙 없이 빈 배열 [] 을 반환하여 Next.js서버의 정상 작동 보장

return [ {. . .} ] -> 재작성 규칙의 배열 반환. 하나 이상의 규칙 정의

  1. 프록시 규칙 상세 정의

source: '/api/:path*' -> 요청을 가로챌 경로 패턴 정의 api로 시작하는 모든 요청을 Next.js가 잡아냄. :path*는 /api/ 뒤에오는 모든 하위 경로를 변수로 캡처

destination -> source에서 캡처된 요청을 실제 전달할 목적지를 정의 ${backendUrl}에 /api/:path* 를 붙여서, 프론트엔드가 보낸 요청을 백엔드 서버의 동일한 경로로 전달. ex) 프론트에서 /api/users요청 → Next.js 서버에서${backendUrl}/api/users\로 요청을 전송.

여러경로를 등록할 경우 {}에 담아 똑같이 정의해주면 됨


데이터 전송객체

하나의 객체 상태로 관리하면 더 깔끔하고 확장성도 좋아짐

  1. 객체정의
image
  1. onChange 핸들러 사용 (범용 핸들러)
image

...prevData -> 이 문법은 기존 formData의 모든 필드 복사하여 유지 하게 해줌

[name]: value -> 이거로 name이랑 value값 연결 가능 (아이디 필드에서 입력시 name은 userId, 코드는 {userId :'입력된 값'}

: React.ChangeEvent<HTMLInputElement | HTMLSelectElement> -> 이벤트 e 타입 명시적으로 지정. input, select 요소에서 발생한 값 변경 이벤트라는것을 알려줌

const { name, value } = e.target; -> 실제로 발생한 HTML 요소를 가리킴

  1. 입력 필드에 연결
image
  1. handleSubmit에서 객체 전송 로직 추가
image

try { const response = await axios.post(ID_CHECK_ENDPOINT, { params: { loginId: loginId, } }); console.log('생성 성공:', response.data); } catch (error) { console.error('생성 실패:', error.response.data); }