본문 바로가기

React & TypeScript28

웹앱 하이브리드 푸시 알림 (리마인더) 구현 정리 전체 아키텍처웹앱(Next.js) ←→ Supabase DB ←→ GitHub Actions → Expo Push API → FCM → 기기1. DB 테이블 (Supabase)reminders — 리마인더 저장id, user_id, contact_id, contact_name, title, remind_at, is_sent, created_atpush_tokens — 기기 토큰 저장id, user_id, token, platform, updated_at2. 웹앱 (Next.js)파일역할src/features/reminders/actions/create-reminder.ts리마인더 DB 저장src/features/reminders/actions/get-reminders.ts리마인더 조회src/feature.. 2026. 4. 7.
Nextjs 토스페이먼츠 결제기능 테스트하기 목차환경 및 준비물토스페이먼츠 테스트 키 발급Supabase 스키마 수정SDK 설치 및 환경변수 설정결제 버튼 컴포넌트 (Client)결제 확인 서버 액션결제 성공 페이지결제 실패 페이지요금제 화면에 연결테스트 카드 번호전체 흐름 요약자주 나오는 에러 모음1. 환경 및 준비물Next.js 15+ (App Router)Supabase (DB + Auth)NextAuth v4@tosspayments/tosspayments-sdk2. 토스페이먼츠 테스트 키 발급developers.tosspayments.com 접속 후 회원가입/로그인상단 내 개발정보 클릭테스트 탭 선택클라이언트 키 (test_ck_...) 와 시크릿 키 (test_sk_...) 복사⚠️ 주의: 클라이언트 키와 시크릿 키는 다릅니다. 둘 다 복.. 2026. 3. 24.
웹뷰 하이브리드 앱에서 뒤로가기 제대로 구현하기 (react-hammerjs + WebView BackHandler) React 웹 + RN Expo 웹뷰 하이브리드 구조에서 삽질한 내용 정리프로젝트 구조이 글은 아래 구조를 전제로 한다.RN+Expo 앱└── WebView └── React 웹앱 (react-router-dom)웹이랑 앱 따로 개발하고, 앱에서 웹뷰로 웹을 띄우는 방식이다. 처음엔 단순해 보였는데 뒤로가기 하나 구현하는 데 꽤 헤맸다.웹 쪽 - react-hammerjs로 스와이프 뒤로가기모바일 웹에서 오른쪽 스와이프로 뒤로가기를 구현하려면 react-hammerjs를 쓰면 된다.설치npm install react-hammerjs 타입 에러가 날 텐데 npm i --save-dev @types/hammerjs 를 해도 안되면 아래처럼 세팅 해준다 // declarations.d.ts 생성decla.. 2026. 3. 12.
문자열 리터럴 타입이란? as const TypeScript 문자열 리터럴 타입 완벽 정리React Native로 개발하다 보면 fontWeight 같은 속성에서 타입 에러를 만나게 됩니다. 이 글에서는 문자열 타입과 문자열 리터럴 타입의 차이를 알아보겠습니다.문제 상황// ❌ TypeScript 에러 발생const customStyle = { textStyle: { fontWeight: "500" // Error: 'string' 형식은 할당할 수 없습니다 }};문자열 타입 vs 문자열 리터럴 타입1. 문자열 타입 (string)let name: string = "철수";name = "영희"; // ✅ OKname = "민수"; // ✅ OKname = "아무거나"; // ✅ OK특징: 어떤 문자열이든 다 들어갈 수 .. 2026. 1. 15.
안 쓰는 import 자동으로 제거하기 참고한 블로그https://feb-dain.tistory.com/23 [vscode] 안 쓰는 import 자동 제거하는 방법ctrl + shift + p (windows) / command + shift + p (mac)를 눌러 User Settings (JSON) 파일을 연다. 그리고 editor.codeActionsOnSave에 "source.removeUnusedImports": true를 추가해주면 끝이다! // settings.json { ... "editor.codeActionsOnSave"feb-dain.tistory.com "[typescript]": { "editor.defaultFormatter": "esbenp.prettier-vscode", "editor.formatOnSave.. 2025. 7. 28.
[React] 새 프로젝트 설치 + tailwindcss 설치 npm create vite@latest [프로젝트명] --template react-ts 위 설치 후 아래의 공식문서 그대로 따라하기 https://tailwindcss.com/docs/installation/using-vite Installing with Vite - InstallationIntegrate Tailwind CSS with frameworks like Laravel, SvelteKit, React Router, and SolidJS.tailwindcss.com 2025. 2. 21.
Redux 사용법 Redux의 핵심 개념Store : 애플리케이션의 전역 상태를 보관Action : 상태를 변경하기 위한 "의도"를 나타내는 객체Reducer : Action에 따라 상태를 업데이트하는 순수 함수Dispatch : Aciton을 Store로 보내는 메서드Selector : 상태를 조회하기 위한 함수 Redux 사용법1. Redux 설치npm install @reduxjs/toolkit react-redux @reduxjs/toolkit은 Redux를 쉽게 사용할 수 있도록 도와주는 공식 도구 2. 간단한 예제 Store 설정// src/store/counterSlice.tsimport { createSlice } form '@reduxjs/toolkit';const counterSlice = createS.. 2025. 1. 12.
[React] React 라이프 사이클 이해하기 + useEffect의 동작 순서 React의 렌더링이란?React 애플리케이션 트리 안에 있는 모든 컴포넌트들이 현재 자신들이 가지고 있는 props와 state의 값을 기반으로 어떻게 UI를 구성하고 이를 바탕으로 어떤 DOM 결과를 브라우저에 제공할 것인지 계산하는 일련의 과정을 의미한다. 만약 컴포넌트가 props와 state와 같은 상태값을 가지고 있지 않다면 오직 해당 컴포넌트가 반환하는 JSX 값에 기반해 렌더링이 일어난다. 쉽게 말해, 브라우저 화면에 요소를 보여주는 것을 렌더링이라고 한다.React의 컴포넌트들은 모두 이 생명주기를 가지고 있다. 렌더링 과정mount : 처음 화면에 보여주는 최초 렌더링이다.update : 화면의 요소 하나라도 바뀌면 업데이트 된 것이다. ex) 0 -> 1로 변경unmount : 보여줄.. 2024. 12. 17.
[React] 페이지 이동 시 스크롤 위치가 하단에 있을 때 ScrollToTop 사이드 프로젝트에서 푸터를 만들고 난 뒤하단에 스크롤 위치한 상태에서 다른 카테고리 페이지로 이동하면그 페이지 역시 스크롤이 하단에 위치한 채 렌더링되는 문제가 생겼다. 그래서 렌더링될때 스크롤이 항상 상단에 위치시키기 위한 컴포넌트를 만들었다.import { useEffect } from "react";import { useLocation } from "react-router-dom";function ScrollToTop() { const { pathname } = useLocation(); useEffect(() => { window.scrollTo(0, 0); }, [pathname]); return null;}export default ScrollToTop;"/"와 같은 pathnam.. 2024. 12. 16.
React 프로젝트 성능 및 최적화 개선하기 사이드 프로젝트를 어느 정도 마무리하고 성능을 확인해봤는데 ....... 왜이리 점수가 짜나요....랜딩페이지와 디자인에 힘을 많이 주는 프로젝트라 이미지 최적화가 시급했다.최적화 방법을 찾아보던 중 코드 스플리팅을 주로 사용한다는 것을 알았다.아래는 개선 전 코드 .. import { createBrowserRouter } from "react-router-dom";import App from "../App";import Home from "../pages/home";import Login from "../pages/auth/components/Login";import Signup from "../pages/auth/components/Signup";import Recipes from "../pages.. 2024. 12. 12.
[TIL] zustand 사용 시 state.state와 getState()의 차이 1. useUserStore((state) => state.isLoggedIn)특징React 컴포넌트에서 주로 사용: 이 방식은 Zustand 상태를 React 컴포넌트에 연결합니다.Zustand의 상태(isLoggedIn)를 구독(subscribe) 합니다.상태가 변경되면 컴포넌트가 자동으로 다시 렌더링됩니다.상태 관리와 React의 재렌더링 메커니즘이 결합됩니다.예시function Header() { const isLoggedIn = useUserStore((state) => state.isLoggedIn); return {isLoggedIn ? "Logged In" : "Logged Out"};}장점React와 상태의 동기화가 자동으로 이루어짐.상태가 변경되었을 때 React 컴포넌트를 다시 렌.. 2024. 11. 17.
[React] input 값을 useState로 상태 관리 할 때 defaultValue를 왜 사용하면 안될까? 사이드프로젝트 하는 중 마이페이지에서 닉네임을 가져와야하는데 작은 문제가 생겼다.처음에 로그인한 유저의 닉네임을 그대로 가져오기 위해 input 태그에 defaultValue={user.nickname}을 하고,닉네임 변경하기 위해 새로운 닉네임 값으로 value={nickname}을 속성에 넣었더니 아래처럼 에러 메세지가 찍혔다. value와 defaultValue를 같이 쓰지 말라는 거였다. 왜 안될까? 이유는 value와 defaultValue가 서로 다른 방식으로 동작하기 때문이다.defaultValue: 컴포넌트가 처음 렌더링될 때만 적용되는 초기 값. 상태가 아닌, 기본적으로 입력될 값으로 한 번만 설정된다.value: 컴포넌트의 상태를 직접적으로 반영한다. useState로 상태를 관리하고.. 2024. 11. 15.