Next.js Server Actions를 활용한 캐시 재검증 문제 해결
Dev Log
문제 상황프로젝트를 진행하던 중 사용자가 팔로우/언팔로우 버튼을 클릭할 때, 프로필 정보가 즉시 업데이트되지 않고 페이지를 새로고침해야만 변경 사항이 반영되는 문제가 발생했다.이 문제는 사용자 경험을 저하시키는 상황이기때문에 반드시 개선이 필요했다.원인 분석팔로우 버튼을 클릭하면 팔로우 상태를 변경하는 함수가 Sanity의 데이터를 업데이트한다. 하지만 이 변경 사항이 클라이언트 화면에 즉시 반영되지 않았다.Next.js는 성능 최적화를 위해 서버에서 가져온 데이터를 캐싱한다. 팔로우 상태가 변경되어도 Next.js는 여전히 이전에 캐싱된 데이터를 사용하고 있었기 때문에, 사용자가 보는 화면은 업데이트되지 않은 상태로 유지되었다.서버 사이드에서 데이터 변경이 발생한 후, 클라이언트의 캐시를 재검증(rev..
[CS50] 자료구조 - 연결 리스트 개념과 구현
TIL
복잡한 프로그램을 구현하다 보면 기본적인 포인터 구조만 이용해서 메모리를 관리하기에는 다소 번거로울 때가 많다.메모리를 좀 더 효율적으로 관리하고 사용할 수 있는 데이터 구조의 개념과 연결 리스트를 알아보자.데이터 구조란데이터 구조(Data Structure)는 우리가 컴퓨터 메모리를 더 효율적으로 관리하기 위해 새로 정의하는 구조체다.일종의 메모리 레이아웃, 또는 지도라고 생각할 수 있다. 데이터 구조 중 하나인 연결 리스트에 대해 알아보자. 연결 리스트의 개념배열의 한계배열에서는 각 인덱스의 값이 메모리상에서 연이어 저장되어 있다.배열: [1][2][3]주소: 100 104 108 ← 연속된 메모리하지만 꼭 그럴 필요가 있을까? 연결 리스트의 아이디어각 값이 메모리상의 여러 군데 나뉘어져 있다고 ..
[CS50] 배열의 크기 조정하기
TIL
컴퓨터 안의 메모리는 마치 사물함 같은 구조다.우리가 사용하고자 하는 사물함의 개수를 한 번 정한 이후에는, 공간이 모자란다고 해서 주변의 사물함을 마음대로 더 사용할 수는 없다.이미 다른 목적으로 사용되고 있을 수도 있기 때문이다. 이미 일정한 크기의 메모리가 할당되어 있는 상황에서 그 크기를 늘리는 일은 생각만큼 단순하지 않다.포인터와 malloc의 개념을 응용해서 이미 정의된 배열의 크기를 바꿔보자.배열의 크기 조정하기배열 크기를 늘리는 방법일정한 크기의 배열이 주어졌을 때, 그 크기를 키우려면 어떻게 해야 할까? 단순히 현재 배열이 저장되어 있는 메모리 위치의 바로 옆에 덧붙이면 될 것 같지만, 실제로는 다른 데이터가 저장되어 있을 확률이 높다.따라서 새로운 공간에 큰 크기의 메모리를 다시 할당하..
웹 애플리케이션의 렌더링 방식과 Next.js
Frontend
웹 애플리케이션을 개발할 때 가장 중요한 선택 중 하나는 렌더링 방식이다.각 방식은 고유한 장단점을 가지고 있으며, Next.js를 통해 이러한 방식들을 유연하게 활용할 수 있다.렌더링 방식CSR (Client Side Rendering)클라이언트 사이드 렌더링은 웹 페이지의 렌더링을 사용자의 브라우저가 담당하는 방식이다. 사용자가 웹 페이지를 요청하면 서버는 가장 기본적인 HTML 구조인 텅 빈 index.html을 먼저 전달하고, 이후 필요한 자바스크립트 파일과 리액트 컴포넌트 등을 클라이언트로 전송한다.동작 과정사용자가 웹 페이지에 접속하면 서버는 초기 구조만 있는 index.html을 전송브라우저는 이 HTML 파일을 받은 후, 리액트 라이브러리와 컴포넌트들을 서버로부터 다운로드리액트가 로드되고 ..
[PeaNutter] Vercel 배포 시 하위 라우터 404 오류 해결
Dev Log
문제 상황Vercel로 프로젝트를 배포한 후, '/profile/edit'과 같은 하위 라우터에서 새로고침을 하니 404 Not Found 오류가 발생했다. 원인 분석SPA와 전통적인 웹 애플리케이션의 차이전통적인 웹 애플리케이션사용자가 각 페이지에 접근할 때마다 서버에서 해당 페이지의 HTML을 제공한다.'/posts', '/profile' 등의 페이지를 요청하면, 서버는 각각의 요청에 맞는 HTML 파일을 찾아서 보내주는 방식이다. 싱글 페이지 애플리케이션(SPA)초기 접근 시 단 하나의 HTML 파일인 index.html을 로드하고, 그 이후의 모든 페이지 전환은 브라우저에서 JavaScript를 사용하여 동적으로 내용을 변경한다.사용자가 '/profile/edit' 같은 URL로 이동하더라도 실제..
React 컴포넌트 분리와 연동된 state 업데이트
TIL
원-달러 환율 변환기를 구현했다.사용자가 한 화폐 단위의 금액을 입력하면, 사전에 정의된 환율을 사용해 다른 화폐 단위로 변환된 금액을 동시에 보여준다.구현 과정컴포넌트 분리입력 필드를 재사용 가능한 CurrencyInput 컴포넌트로 분리한다.const CurrencyInput = ({ value, onChange, currencyUnit }) => { return ( {currencyUnit} onChange(currencyUnit, e.target.value)} /> );};currencyUnit: 화폐 단위(krw 또는 usd)를 받아 라벨과 id로 사용한다.value: 현재 입력값을 props로 받아 표시한다.onChange: 입력값이 변경될 때 화..
React 객체 state 관리와 useRef 활용하기
TIL
이전 글에서 다뤘던 배달 음식 주문 폼을 개선해봤다.여러 개로 분리된 state를 하나로 통합하고, useRef를 활용해 입력 유효성 검사 기능을 추가했다.구현 과정State 통합하기기존에 분리되어 있던 3개의 state를 객체 형태의 하나의 state로 합친다.기존 코드const [menu, setMenu] = useState("");const [address, setAddress] = useState("");const [request, setRequest] = useState(""); 변경 후const [state, setState] = useState({ menu: "", address: "", request: "",}); 이에 맞춰 JSX의 value 속성도 수정한다.return ( ..
React로 사용자 입력 관리하기
TIL
React로 간단한 배달 음식 주문 페이지를 구현했다.메뉴, 배달 주소, 요청사항을 입력받고 주문 완료 시 입력값을 확인할 수 있도록 만들었다.구현 과정마크업 구조먼저 주문에 필요한 입력 폼들을 구성한다. 메뉴 선택을 위한 select,주소 입력을 위한 input, 요청사항 입력을 위한 textarea, 그리고 주문 완료 button을 배치한다.export default function OrderEditor() { return ( 배달의민족 주문 아이스크림 젤리 초콜릿 배달 주소 배달 요청사항 주문 완료 );} state 관리각 입력 필드의 값을 관리하기 위한 state를..
[CS50] 메모리 - 파일 입출력
TIL
사용자에게 입력을 받는 함수는 어떻게 구현할 수 있을까? 파일을 읽고 쓰는 방법을 알아보자. 메모리 구조를 다시 한 번 살펴보면,메모리 영역머신 코드: 프로그램이 컴파일된 바이너리글로벌: 프로그램 안에서 저장된 전역 변수힙: malloc으로 할당된 메모리의 데이터스택: 프로그램 내의 함수와 관련된 것들힙 영역에서는 malloc에 의해 메모리가 더 할당될수록 아래로 늘어나고, 스택 영역에서는 함수가 더 많이 호출될수록 위로 늘어난다. 제한된 메모리 용량 하에서 점점 늘어나다 보면 기존의 값을 침범하는 상황이 발생하는데, 이를 힙 오버플로우 또는 스택 오버플로우라고 한다. 사용자에게 입력 받기get_int 구현#include int main(void){ int x; printf("x: "); ..
[CS50] 메모리 - 메모리 교환, 스택, 힙
TIL
각각 사이다와 콜라가 들어있는 컵 두 개가 있을 때, 사이다와 콜라를 바꿔 담고 싶으면 어떻게 해야 할까?아마 교환을 도와줄 새로운 컵이 잠시 필요할 것이다. 메모리에 저장된 값들을 교환할 때도 이와 비슷하게 할 수 있을까?잘못된 값 교환다음 코드를 보자.#include void swap(int a, int b);int main(void){ int x = 1; int y = 2; printf("x is %i, y is %i\n", x, y); swap(x, y); printf("x is %i, y is %i\n", x, y);}void swap(int a, int b){ int tmp = a; a = b; b = tmp;}// 출력// x is 1, y is 2..