172만명의 커뮤니티!! 함께 토론해봐요.
해결됨
한 입 크기로 잘라먹는 React.js 실전 프로젝트 - SNS 편
안녕하세요 정환님! 정환님의 강의를 들으면서 코드를 따라 작성해보다가 포스트와 이미지를 최종적으로 업로드 하는 과정에서 아래의 캡쳐 사진과 같이 포스트 생성에 실패했다는 에러 메시지가 뜨게됩니다. 네트워크 탭에 보면, 포스트 부분은 잘 전달이 되는거같은데 이미지 생성에 관한 결과가 보이지 않는 것으로 보아 이미지 생성 관련 코드에서 문제가 생긴것같은데 무슨 문제일까요??..ㅠ 아래는 해당 코드들입니다. 이미지 생성 관련 코드를 가져왔는데 혹여나 다른 부분의 코드가 필요하면 추가 업로드 드리겠습니다. api/post.ts import type { PostEntity } from './../types'; import supabase from '@/lib/supabase'; export async function createPost(content: string) { const { data, error } = await supabase .from('post') .insert({ content }) .select() .single() if (error) throw error return data } export async function createPostWithImages({ content, images, userId }: { content: string images: File[] userId: string }) { // 1. 새로운 포스트 생성 (맨 위에서 생성한 포스트 비동기 함수 가져오기) const post = await createPost(content) if (images.length === 0) return post // 2. 이미지 업로드 try { const imageUrls = await Promise.all( images.map((image) => { const fileExtension = image.name.split(".").pop() || "webp" const fileName = `${Date.now()}-${crypto.randomUUID()}.${fileExtension}` const filePath = `${userId}/${post.id}/${fileName}` return uploadImage({ file: image, filePath }) }) ) // 3. 포스트 테이블 업데이트 const updatedPost = await updatePost({ id: post.id, image_urls: imageUrls }) return updatedPost } catch(error) { await deletePost(post.id) throw error } } export async function updatePost(post: Partial<PostEntity> & { id: number }) { const { data, error } = await supabase .from("post") .update(post) .eq("id", post.id) .select() .single() if (error) throw error return data } export async function deletePost(id: number) { const { data, error } = await supabase .from("post") .delete() .eq("id", id) .select() .single() if (error) throw error return data } hooks/mutations/post/use-create-post.ts import type { UseMutationCallback } from './../../../types'; import { createPost, createPostWithImages } from '@/api/post'; import { useMutation } from '@tanstack/react-query'; export function useCreatePost(callbacks?:UseMutationCallback) { return useMutation({ mutationFn: createPostWithImages, onSuccess: () => { if(callbacks?.onSuccess) callbacks.onSuccess() }, onError: (error) => { if (callbacks?.onError) callbacks.onError(error) } }) } components/modal/post-editor-modal.tsx import { Button } from '@/components/ui/button' import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog' import { useCreatePost } from '@/hooks/mutations/post/use-create-post' import { usePostEditorModal } from '@/store/post-editor-modal' import { useSession } from '@/store/session' import { ImageIcon, XIcon } from 'lucide-react' import { useRef, useState, useEffect, ChangeEvent } from 'react' import { toast } from "sonner" import { Carousel, CarouselContent, CarouselItem } from '../ui/carousel' type Image = { file: File, previewUrl: string } export default function PostEditorModal() { const session = useSession() const { isOpen, close } = usePostEditorModal() const { mutate: createPost, isPending: isCreatePostPending } = useCreatePost({ onSuccess: () => { close() }, onError: (error) => { toast.error("포스트 생성에 실패했습니다", { position: "top-center" }) } }) const [content, setContent] = useState("") const [images, setImages] = useState<Image[]>([]) const textareaRef = useRef<HTMLTextAreaElement>(null) const fileInputRef = useRef<HTMLInputElement>(null) const handleCloseModal = () => { close() } const handleCreatePostClick = () => { if (content.trim() === "") return createPost({ content, images: images.map((image) => image.file), userId: session!.user.id }) } const handleSelectImages = (e:ChangeEvent<HTMLInputElement>) => { if (e.target.files) { const files = Array.from(e.target.files) files.forEach((file) => { setImages((prev) => [ ...prev, { file, previewUrl: URL.createObjectURL(file) }, ]) }) } e.target.value = "" } const handleDeleteImage = (image:Image) => { setImages((prevImages) => prevImages.filter((item) => item.previewUrl !== image.previewUrl)) } useEffect(() => { if (textareaRef.current) { textareaRef.current.style.height = "auto" textareaRef.current.style.height = textareaRef.current.scrollHeight + "px" } }, [content]) useEffect(() => { if (!isOpen) return textareaRef.current?.focus() setContent("") setImages([]) }, [isOpen]) return ( <Dialog open={isOpen} onOpenChange={handleCloseModal}> <DialogContent className="max-h-[90vh]"> <DialogTitle>포스트 작성</DialogTitle> <textarea disabled={isCreatePostPending} ref={textareaRef} value={content} onChange={(e) => setContent(e.target.value)} className="max-h-125 min-h-25 focus:outline-none" placeholder="무슨 일이 있었나요?" /> <input onChange={handleSelectImages} ref={fileInputRef} type="file" accept="image/*" multiple className="hidden" /> {images.length > 0 && <Carousel> <CarouselContent> {images.map((image) => <CarouselItem className="basis-2/5" key={image.previewUrl}> <div className="relative"> <img src={image.previewUrl} className="h-full w-full rounded-sm object-cover" /> <div onClick={() => handleDeleteImage(image)} className="absolute top-0 right-0 m-1 cursor-pointer rounded-full bg-black/30 p-1" > <XIcon className="h-4 w-4 text-white"/> </div> </div> </CarouselItem>)} </CarouselContent> </Carousel>} <Button onClick={() => { fileInputRef.current?.click() }} variant={"outline"} className="cursor=pointer" > <ImageIcon/> 이미지 추가</Button> <Button disabled={isCreatePostPending} onClick={handleCreatePostClick} className="cursor=pointer"> 저장 </Button> </DialogContent> </Dialog> ) }
react typescript react-query supabase zustand
rkdla666
2026-07-10T09:02:45.932Z
댓글 2
좋아요 0
조회수 57
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
문자열 쓸때 %를 2번 써야 출력시 %가 나온다고 하셨는데 /같은 경우는 한번만 써도 되는건가요? 혹시 %처럼 꼭 두번 써야 되는 문자가 더 있는지 궁금합니다
python java c 정보처리기사 정보처리산업기사
가보자고
2026-07-10T08:59:24.382Z
댓글 2
좋아요 0
조회수 54
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
ptintf("\n");에서 \n이 있길래 출력값은 개행 되어 나오는 줄 알았는데요 왜 출력값이 아래와 같지 않은지 모르겠습니다, 그리고 아래와 같은 결과가 나오려면 코드가 어떻게 쓰여져야 하는지도 궁금합니다 1 2 3 4 5
python java c 정보처리기사 정보처리산업기사
가보자고
2026-07-10T08:34:46.490Z
댓글 2
좋아요 0
조회수 61
미해결
타입스크립트로 배우는 Next.js 16+ 완전 정복 : 기초부터 최신 아키텍처까지
카카오 로그인 후 이메일을 입력하고 몽고DB에 이메일과 refresh token이 저장된 것 까지 확인은 했는데 쿠키가 생성되지 않고 있네요. 강사님 네이버메일로 소스코드링크를 보냈습니다.
javascript react typescript next.js jwt
태리바이트
2026-07-10T07:24:14.898Z
댓글 3
좋아요 0
조회수 69
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
맨아래 printf("%d\n", count); 에서 \n이 있어서 그 누적합이 개행으로 아래와 같이 출력될 것 같다고 생각했는데요 이게 왜 아닌지랑, 이렇게 나오려면 코드가 어떻게 쓰여져야 하는지 궁금합니다 2 6 14 24
python java c 정보처리기사 정보처리산업기사
가보자고
2026-07-10T01:14:21.650Z
댓글 2
좋아요 0
조회수 58
미해결
클로드 코드 완벽 마스터: AI 개발 워크플로우 기초부터 실전까지
항상 잘 듣고 있습니다^^
구자
2026-07-10T01:09:17.647Z
댓글 2
좋아요 0
조회수 67
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
맨아래 printf("%d\n",count);에서 \n이 있어서 저는 출력값이 아래와 같을 줄 알았거든요 1 2 3 4 5 6 7 그런데 정답이 7이더라구요 왜 제가 생각한 것처럼 위와 같이 안 나온 건지 모르겠습니다 그리고 위와 같은 출력값이 나오려면 코드를 어떻게 써야 되는지도 궁금합니다
python java c 정보처리기사 정보처리산업기사
가보자고
2026-07-10T00:54:31.625Z
댓글 2
좋아요 0
조회수 44
미해결
클로드 코드 완벽 마스터: AI 개발 워크플로우 기초부터 실전까지
이게 맞는건가요? showClearCOntextOnPlanAccept 설정이 켜있을때만 보인다고 하던데요?
아밥퍼
2026-07-09T13:06:02.901Z
댓글 3
좋아요 0
조회수 78
미해결
타입스크립트로 배우는 Next.js 16+ 완전 정복 : 기초부터 최신 아키텍처까지
이메일 입력 후 contitnue 버튼을 누르면 JWT auth error invalid token 오류가 나네요. 몇시간째 보고 있는데 원인을 찾지 못하겠네요. 전체 소스 코드를 같이 첨부하고 싶은데 할 수 가 없네요. 일단은 EmailInfoForm 소스만 올려 봅니다. backend는 .env 빼고 소스를 특별하게 수정한 부분이 없습니다. 브라우저 application 데이터도 클리어 해보고 했지만 소용이 없네요. 확인 부탁드립니다. "use client"; import {useState} from "react"; import {MailIcon} from "../ui/Icons"; import {validateEmail} from "@/lib/validation"; import clientApi from "@/lib/api/clientApi"; import {useRouter, useSearchParams} from "next/navigation"; export default function EmailInfoForm() { const router = useRouter(); const searchParams = useSearchParams(); const accessToken = searchParams.get("access_token") ?? ""; const [email, setEmail] = useState(""); const [error, setError] = useState(""); const [isSubmitting, setIsSubmitting] = useState(false); const handleFormSubmit = async (e: React.SubmitEvent<HTMLFormElement>) => { e.preventDefault(); if (isSubmitting) return; setError(""); //이메일 검증 const validationError = validateEmail(email); if (validationError) { setError(validationError); return; } //확인 대화 상자 const confirmed = window.confirm( "한 번 입력한 이메일은 변경할 수 없습니다. 이 이메일로 저장할까요?", ); if (!confirmed) return; setIsSubmitting(true); try { const res = await clientApi("/auth/update-email", { method: "PATCH", body: JSON.stringify({email: email.trim()}), headers: { Authorization: `Bearer ${accessToken}`, }, }); if (!res.ok) { const errorData = await res.json().catch(() => null); throw new Error( (errorData && errorData.error) || "이메일 업데이트에 실패하였습니다.", ); } router.replace("/"); router.refresh(); } catch (e) { setError( e instanceof Error ? e.message : "이메일 업데이트에 실패하였습니다.", ); } }; return ( <> <form className="flex flex-col gap-5" onSubmit={handleFormSubmit}> <div className="flex flex-col gap-2"> <label htmlFor="email" className="text-sm font-medium text-foreground" > Email Address </label> <div className="relative"> <MailIcon className="absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-muted-foreground" /> <input id="email" type="email" placeholder="Enter your email" className="h-11 w-full rounded-lg border-none bg-secondary pl-10 pr-4 text-sm text-foreground placeholder-muted-foreground outline-none focus:ring-2 focus:ring-primary" value={email} onChange={(e) => setEmail(e.target.value)} /> </div> </div> {error && ( <p className="text-sm font-medium text-destructive">{error}</p> )} <div className="grid grid-cols-2 gap-3"> <button type="button" className="h-11 rounded-lg bg-secondary text-sm font-medium text-secondary-foreground transition-colors hover:opacity-90" > Cancel </button> <button type="submit" className="h-11 rounded-lg bg-primary text-sm font-medium text-primary-foreground transition-colors hover:opacity-90" > Continue </button> </div> </form> </> ); }
javascript react typescript next.js jwt
태리바이트
2026-07-09T06:31:51.286Z
댓글 2
좋아요 0
조회수 66
미해결
스프링부트로 직접 만들면서 배우는 대규모 시스템 설계 - 게시판
테스트 작성 시, 소스파일에(src) 있는 DTO를 그대로 사용하지 않고, 복사해와서 새로 정의를 하시던데 그 이유가 뭔지 궁금합니다!
java mysql spring-boot kafka redis
nick
2026-07-09T06:18:03.845Z
댓글 1
좋아요 0
조회수 53
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
4:38 scanner.nextlnt() 이건 뭔가요 중간에 . 이 붙었는데 이 개념이 어색합니다.
python java c 정보처리기사 정보처리산업기사
wkruqja
2026-07-09T02:42:50.206Z
댓글 2
좋아요 0
조회수 65
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
3:00 파라미터 라는 말이 나오는데 비전공자라서 무슨말인지 모르겠어요.. 이런것들 자막 켜면 부가 설명에 예시가 달려서 나오면 안될까요ㅠㅠ 개행도 오늘 처음들었고. 첫 강의부터 약간 옆에 검색창 띄워놓고 수강해야할것 같은 예감이 듭니다.
python java c 정보처리기사 정보처리산업기사
wkruqja
2026-07-09T02:42:04.342Z
댓글 1
좋아요 0
조회수 47
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
수강 섹션마다 옆에 자료 다운로드 버튼이 있는데. 다운받으면 무슨내용이 있는건가요?
python java c 정보처리기사 정보처리산업기사
wkruqja
2026-07-09T02:33:00.424Z
댓글 1
좋아요 0
조회수 42
미해결
자바 ORM 표준 JPA 프로그래밍 - 기본편
학습하는 분들께 도움이 되고, 더 좋은 답변을 드릴 수 있도록 질문전에 다음을 꼭 확인해주세요. [질문 내용] 강의보고 책으로 복습하다가 궁금한 점이 있어서 질문드립니다. jpa 책 105쪽에 변경감지에 관한 내용입니다. 엔티티가 영속성 컨텍스트에 보관될 때 최초의 상태(persist())를 스냅샷으로 저장해두고 플러시 시점의 엔티티를 비교해서 변경사항에 대한 수정 쿼리를 쓰기지연 sql 저장소에 보낸다고 되어있습니다. 이 메커니즘은 이해가 되는데 persist(); setName(); flush(); 여기서 persist()를 하게 되면 실제 db에 바로 반영이 되는 것이 아니라 영속 컨텍스트에 저장(1차캐시), 이후 insert 쿼리를 쓰기 지연 저장소에 저장하게 됩니다. 이후 엔티티의 이름을 변경하고 플러시할 경우 스냅샷과 플러시 시점의 엔티티 상태를 비교해서 변경 부분에 관한 수정 쿼리를 쓰기지연저장소에 보낼 때 쓰기지연저장소에는 insert와 update 두 쿼리가 있고 플러시할 때 insert, update 두가지 모두 실행되는 걸까요? 아니라면 이유가 궁금합니다! 찾아보니까 insert만 나간다고 하는데 왜 그런지 도무지 이해가 안됩니다.
gsjh2001
2026-07-09T02:13:31.587Z
댓글 1
좋아요 0
조회수 50
미해결
클로드 코드 완벽 마스터: AI 개발 워크플로우 기초부터 실전까지
Starter Kit 만들기 소스코드 부분에 있어 강의 섹션 13~14에서 변경된 코드가 하나도 적용안되 있어보여 문의드려봅니다..! 가능하면 완벽히 마무리된 상태도 확인해 보고 싶은데 다운받아 확인해 보니 오류도 있고 소개나 문서 부분 클릭시에도 제대로 나오지않아 섹션 13에서 다룬 내용이 적용되지 않은 상태로 보여서요 영상외에 제가 봐보며 코드와 디자인을 좀 자세히 보고싶은데 혹시 업로드 안된상태라면 따로 업로드나 공유가 어려운부분일지도 질문드려봅니다
모또쭌
2026-07-08T15:05:00.832Z
댓글 1
좋아요 0
조회수 49
미해결
클로드 코드 완벽 마스터: AI 개발 워크플로우 기초부터 실전까지
지금 강의하는 Cursor 버전이랑 요즘 버전이랑 완전 달라서 딴세상 이야기 같은데, 예전 버전을 받으려면 몇버전을 받아서 해야하나요?
이흠냥이
2026-07-08T14:03:53.717Z
댓글 3
좋아요 0
조회수 80
미해결
클로드 코드 완벽 마스터: AI 개발 워크플로우 기초부터 실전까지
15강 git 설정 윈도우 동일 방식으로 햇을 때 오류가 뜨는데 어떻게 할 수 있을까요. 오류 내용은 아래와같습니다. ~ : '~' 용어가 cmdlet, 함수, 스크립트 파일 또는 실행할 수 있는 프로그램 이름으로 인식되지 않습니다. 이름이 정확한지 확 인하고 경로가 포함된 경우 경로가 올바른지 검증한 다음 다시 시도하십시오.
너드코더
2026-07-08T11:43:48.816Z
댓글 2
좋아요 0
조회수 66
미해결
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
SQL 부분이 좀 약한거 같은데 SQL 기초부터 다룬 부분이 있을까요?
python java c 정보처리기사 정보처리산업기사
202020943신홍근
2026-07-08T10:55:10.231Z
댓글 1
좋아요 0
조회수 49
미해결
클로드 코드 완벽 마스터: AI 개발 워크플로우 기초부터 실전까지
4강 영상이 안보이고 하얀화면만 나옵니다!
Jay Byeongjoo Kim
2026-07-08T10:12:45.999Z
댓글 1
좋아요 0
조회수 50
해결됨
(2026 최신!) 일주일만에 합격하는 정보처리기사 실기
왼쪽 코드 맨아래 설명을 생략하신거 같은데요 NULL은 숫자 0이 아니잖아요 그래서 NULL==0은 거짓이니까 0이라고 생각했습니다 그래서 저는 출력 시 NULL==0의 결과: 0 이라고 생각했거든요 그런데 오른쪽 출력값에 1이라고 나와있더라구요 오타인가요? 아니면 제가 이해를 잘 못한건가요??
python java c 정보처리기사 정보처리산업기사
가보자고
2026-07-08T08:51:04.129Z
댓글 2
좋아요 0
조회수 62