묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Next + React Query로 SNS 서비스 만들기
혹시 Search페이지에서 매개변수 누가 넘겨주는건가요?
수업을 다 듣고 저 스스로 코드를 짜던중 갑자기 놓친부분이 있는 것 같아 여쭤봅니다.혹시<search/page.tsx>export default function Search({ searchParams }: Props) {여기서 이 search/page.tsx의 매개변수는 누가 넘겨주는 걸까요?
-
미해결Next + React Query로 SNS 서비스 만들기
미리보기했을때 저는 아예안뜨는데 뭐가 문제일까요?
저는 미리보기하면 PostRecommend.tsx부분이 아예 안뜨는데 뭐가 잘못된지 모르겠어서 질문드립니다.(단, 화면에 정상적으로 post들은 문제없이 뜹니다.)<PostRecommend.tsx>의 코드는 아래입니다."use client" import Post from "../../_component/Post"; import { useQuery } from "@tanstack/react-query" import { getPostRecommends } from "../_lib/getPostRecommends" import { Post as IPost } from "@/app/model/post"; export default function PostRecommend(){ const {data} = useQuery<IPost[]>({queryKey:['posts','recommends'],queryFn:getPostRecommends}); return data?.map((post)=> <Post key={post.postId} post={post}/> ) } 또한 Post.tsx에서 넘겨받은 post를 console.log해봤는데 undefined가 나와 이것과 연관되어있지않나 싶어서 Post.tsx의 코드도 올리겠습니다.import style from './post.module.css'; import Link from "next/link"; import dayjs from 'dayjs'; import relativeTime from 'dayjs/plugin/relativeTime'; import 'dayjs/locale/ko'; import ActionButtons from "@/app/(afterLogin)/_component/ActionButtons"; import PostArticle from "@/app/(afterLogin)/_component/PostArticle"; import {faker} from '@faker-js/faker'; import PostImages from "@/app/(afterLogin)/_component/PostImages"; import { Post as IPost } from '@/app/model/post'; dayjs.locale('ko'); dayjs.extend(relativeTime) type Props = { noImage?: boolean, post:IPost, } export default function Post({ noImage,post }: Props) { const target = post; console.log("+++++++@@@@@@"+target); return ( <PostArticle post={target}> <div className={style.postWrapper}> <div className={style.postUserSection}> <Link href={`/${target.User.id}`} className={style.postUserImage}> <img src={target.User.image} alt={target.User.nickname}/> <div className={style.postShade}/> </Link> </div> <div className={style.postBody}> <div className={style.postMeta}> <Link href={`/${target.User.id}`}> <span className={style.postUserName}>{target.User.nickname}</span> <span className={style.postUserId}>@{target.User.id}</span> · </Link> <span className={style.postDate}>{dayjs(target.createdAt).fromNow(true)}</span> </div> <div>{target.content}</div> {!noImage && <div> <PostImages post={target} /> </div>} <ActionButtons/> </div> </div> </PostArticle> ) }
-
해결됨Next + React Query로 SNS 서비스 만들기
게시물 업로드 POST 메서드 Internal Sever Error
게시물 업로드할 때 status: 500 Internal Server Error가나옵니다. 게시물 업로드 함수는 아래와 같습니다. const onSubmit = async (e: React.FormEvent) => { e.preventDefault(); const formData = new FormData(); formData.append("content", content); imgPreview.forEach((img) => { img && formData.append("images", img.file); }); await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts`, { method: "post", credentials: "include", body: formData, }); };작성한 폼데이터를 전송한 응답을 출력해보니 status:500,Internal Server Error가 나옵니다. 네트워크 탭에서 확인해보니 formData는 제대로 전송되는 듯해요. 서버 로그로 확인한 결과입니다. 서버에서 문제가 발생한걸까요 ?
-
미해결Next + React Query로 SNS 서비스 만들기
해당 예제 코드는 ch4에 없는 것 같아서 질문 올립니다.
Suspense로 Streaming하여 최적화하기(feat. loading.tsx, error.tsx)해당 강의 예제 코드를 보려고 github에서 이리저리 굴러봐도 강의 예제코드와 동일한 코드가 보이지 않아서 질문 올리게 되었습니다.혹시 suspense hook / reactQuery로 suspense 사용해보기에 관한 맛만 보여주시고 깃에서는 확인 불가능한걸까요?
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
강의제공자의 답변을 원합니다 AI 답변만 있고 더이상 직접 답변을 안해주시네요?
AI 답변이 어느정도 편리할 수 있단 건 인정하지만, 질문 답변도 강의서비스에 포함된 것인데 어느 순간부터 강의제공자님의 직접답변은 달리지 않고 AI 답변만 달리네요. 그것만으로 전혀 충분하지 않은데 말이죠그리고 AI 답변은 기존 데이터가 없으면 답변을 못해줍니다. 강의제공자로부터 피드백을 받을 수 있을 것을 기대하고 강의를 수강하는데 이렇게 질문답변 조차 제대로 해결이 되지 않고 있는 것은 문제라고 봅니다.몇년 동안 강의를 걸어놓으 실 거면, 그리고 여러 API를 사용하실 거면 적어도 일년에 한번은 UI나 기능에 변화나 업데이트 가 있는지 확인하고 강의에 반영해주셔야 할 것 같은데 아직도 2022년 버전을 그대로 강의에 걸어두셔서 현재 UI와 완전달라 강의 진행이 제대로 안되고 있습니다.이게 정말 제대로 되고 있는게 맞나요? 무료 강의도 아니고 돈내고 듣는 강의에서 기본적인 내용 업데이트 및 강의에 포함된 질문 답변조차 제대로 진행 되지 않는다는 건 매우 실망 스럽습니다.강의 제공자님의 빠른 직접 답변과 피드백 부탁드립니다.
-
미해결Next + React Query로 SNS 서비스 만들기
로그아웃할때 어떻게 next-auth는 이것이 api/logout으로의 post요청을 보내는것인지 아는건가요?
http.post('/api/logout', () => { console.log('로그아웃'); return new HttpResponse(null, { headers: { 'Set-Cookie': 'connect.sid=;HttpOnly;Path=/;Max-Age=0' } }) }),위 코드가 제로초님이 로그아웃을 위한 handler를 짜놓으신 건데 정작 로그아웃을할때는 const onLogout = () => { signOut({ redirect: false }) .then(() => { router.replace('/'); }); };위와 같이 그저 signOut 함수만 사용하고있으며 로그인때와 같이 따로 providers에서 fetch 경로를 설정해준것도아닌데 next-auth에서는 어떻게 signOut의 경로가 /api/logout인지 아는건가요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
데이터 통신 실습 부분에 대해 질문있습니다.
안녕하세요 graphql 부분에서 조금 헷갈려서 질문을 드립니다.1. 이 부분에서 왼쪽부분에서 판매자 이름이 철수이고 createProductInput은 마우스, 정말 좋은 마우스 그리고 가격을 사용자가 저렇게 마우스 가격등을 input에 작성하면 name, detail, price가 생성된다라는 뜻으로 이해하면 좋을까요? 그리고 그 밑에 _id는 윗부분에 마우스라고 생성해서 나온 마우스라는 제품의 id를 보낸다는 뜻인지도 궁금합니다.
-
미해결Next + React Query로 SNS 서비스 만들기
isPending과 isLoading의 쓰임새에 대하여
isPending은 데이터를 불러오고 있을 때, true가 되고isLoading은 쿼리가 처음으로 실행될 때 true가 되는 것으로 알고 있습니다.제가 이해하기로는 두 속성의 개념이 상당히 많이 겹칠 수 있을 것 같은데, 왜 이렇게 개별로 있는 것인지 궁금합니다.
-
미해결Next + React Query로 SNS 서비스 만들기
handlers.ts에서 회원가입쪽 handler를 짤때의 질문입니다.
http.post('/api/users', async ({ request }) => { console.log('회원가입'); // return HttpResponse.text(JSON.stringify('user_exists'), { // status: 403, // }) return HttpResponse.text(JSON.stringify('ok'), { headers: { 'Set-Cookie': 'connect.sid=msw-cookie; HttpOnly;Path=/;Max-Age=0' } }) }),현재 위 코드가 제로초님의 회원가입 코드인데로그아웃을 할때 세션을 만료하기위해서 Max-Age=0을 넣는것은 이해가 되지만왜 굳이 회원가입을 할때도 Max-Age=0을 붙이신건가요?회원가입시 쿠키가 왜 필요한지와 필요하다고하더라도 왜 굳이 바로 Max-Age=0을 추가해서 바로 만료시켜버리는지가 궁금합니다!
-
미해결이미지 관리 풀스택(feat. Node.js, React, MongoDB, AWS)
강의에 사용된 코드 다운 받는 사이트 주소 있나요?
강의에 사용된 코드 다운 받는 사이트 주소 있나요?
-
미해결Next + React Query로 SNS 서비스 만들기
react-query의 useSuspense.. 사용 시 클라이언트에서 suspense가 동작을 하지 않습니다.
안녕하세요. 강사님예제를 보고 하던 중 suspense 가 동작하지 않아 질문드립니다.처음 예시로 알려주신 react-query의 isPending 을 사용한 로딩처리는 잘 동작하지만 마지막에 알려주신 useSuspense(useSuspenseInfiniteQuery, useSuspenseQuery)들을 사용하는 경우 동작하지 않네요..*팔로우 중 을 선택해도 suspense에 설정한 로딩 컴포넌트가 나오지 않고 딜레이된 시간(5초) 후 데이터가 보여집니다. 로딩 컴포넌트도 회전하지 않고 멈춰있습니다.어떤부분을 봐야할까요?ㅠㅠ반대로 이런 증상을 경험하니 이전 데이터가 먼저 보여진 후 5초 뒤에 최신 데이터로 보여지므로 사용자가 잘 못된 데이터를 표시 할 수 있다는걸 배울 수 있었습니다.😎소스코드const HomePage = async () => { return ( <HomeContextProvider> <HomeTopTab /> <WriteForm /> <Suspense fallback={<Loader />}> <TabDividerSuspense /> </Suspense> </HomeContextProvider> ); };const TabDividerSuspense = async () => { const queryClient = new QueryClient(); await queryClient.prefetchInfiniteQuery({ queryKey: ["tweet", "recommends"], queryFn: getPostRecommends, initialPageParam: 0, }); const dehydratedState = dehydrate(queryClient); return ( <HydrationBoundary state={dehydratedState}> <TabDivider /> </HydrationBoundary> ); };const TabDivider = () => { const { tab } = useContext(HomeContext); return tab === "recommended" ? <TweetList /> : <FollowingList />; };const TweetList = () => { const { ref, inView } = useInView(); const { data, fetchNextPage, hasNextPage, isFetching, isPending } = useSuspenseInfiniteQuery< Post[], object, InfiniteData<Post[]>, [string, string], number >({ queryKey: ["tweet", "recommends"], queryFn: getPostRecommends, initialPageParam: 0, getNextPageParam: (lastPage) => lastPage.at(-1)?.postId, }); useEffect(() => { if (inView) { !isFetching && hasNextPage && fetchNextPage(); } }, [fetchNextPage, hasNextPage, inView, isFetching]); const tweets = useMemo(() => { if (data) { return data.pages.flat(); } }, [data]); return ( <> {tweets?.map((tweet) => ( <Tweet post={tweet} key={tweet.postId} /> ))} {isPending && <Loader />} <div ref={ref} /> </> ); };추가 질문빌드 후 네트워크 탭에서 home을 확인해보면 post 글 들이 모두 html로 변환되어 내려 오고 있습니다!(dev에서는 템플릿?으로 표현되더라고요)저는 html이 아닌 데이터 형태로 내려와 useQuery로 해당 키로 접근해서 그냥 데이터를 가져올 줄 알았는데..그게 아닌가보네요.혹시 좀 더 자세히 설명 좀 부탁드려도 될까요?ㅠ그리고 home의 미리보기 탭에서는 post글들이 아닌 로딩 컴포넌트가 보입니다. (위의 사진에 응답 탭에서는 post글 들이 존재하고요)로딩 컴포넌트가 보이는 이유는 하이드레이션이 처리되기 전이라 그런게 맞나요? 지금 자료를 다시 찾으려니 못 찾고 있는데.. suspense를 사용할 경우 완성된 화면이 아닌 로딩화면을 먼저 내려주므로 seo에는 나쁠 수 있다라는 글을 본적이 있던 것 같은데..맞을까요?*SEO 관련해서 추가로 궁금한건 강의가 따로 있다고 영상에서 말씀하셔서 거기까지 보고 필요할 경우 질문 한번 더 드리겠습니다.👍
-
미해결한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
defaultProps 사용이 이제 불가해진다고 경고문이 왔습니다
내용을 찾아보니 defaultProps에 대한 지원은 향후 주요 릴리스의 함수 구성 요소에서 제거될 예정이고, 대신 JavaScript 기본 매개변수를 사용하세요. 라고 나와있는데defaultProps 를 사용하지 않으면 기본값은 어떻게 설정해야 할까요??
-
미해결한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
map을 이용한 EmotionItem 렌더링 질문
강의 14:00 쯤에 작성하신 map 함수를 이용한 EmotionItem 렌더링 파트에 질문이 있습니다. 강의에서는 아래처럼 작성하셨는데emotionList.map((item) => { <EmotionItem key={item.emotionId} {...item} /> });저는 map 내부 콜백함수에서 return 을 붙이지 않으면 화면에 렌더링 되지 않더라구요. 특별히 다른 이유가 있을까요?
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
Provider를 외부에 노출하는 것보다 내부 로직으로 숨기는 것은 어떤가요?
<Dropdown.Provider list={data}> <Dropdown.Container> <Dropdown.Trigger></Dropdown.Trigger> <Dropdown.List></Dropdown.List> </Dropdown.Container> </Dropdown.Provider>위와같이 Provider을 노출하는 것보다, 아래와 같이 Container 내부에 Provider을 불러와서 사용하는 것이 캡슐화 측면에서 좋지 않나요?! // DropdownContainer <DropdownContextProvider> <div className={cx("Dropdown")} onKeyDown={handleKeyDown} onClick={(e) => e.stopPropagation()} > {children} </div> </DropdownContextProvider> <Dropdown.Container list={data}> <Dropdown.Trigger></Dropdown.Trigger> <Dropdown.List></Dropdown.List></Dropdown.Container>
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 2
keyEventMap를 전역에 구현하신 이유가 궁금합니다!
const KeyEventMap: Partial<Record<KeyboardEvent<Element>['key'], KeyEventHandler>> = { ArrowUp: (e, { size, focusIndex }) => { e.preventDefault() focusIndex(prev => (size + prev - 1) % size) }, ArrowDown: (e, { size, focusIndex }) => { e.preventDefault() focusIndex(prev => (size + prev + 1) % size) }, Enter: (e, { focusedIndex, selectIndex }) => { e.preventDefault() selectIndex(focusedIndex) }, Escape: (e, { toggle }) => { toggle(false) }, } 제 짧은 지식으로는 focusIndex, selectIndex를 파라미터로 받는 것보다 context 내부에서 그냥 사용하는 것이 더 간단할 것 같다고 생각했습니다. keyEventMap을 전역에 구현하여, focusIndex와, selectIndex를 따로 파라미터로 받아서 사용하시는 이유가 있을까요?
-
미해결처음 만난 리액트(React)
jsx 코드 작성 후 터미널 연결
jsx 코드 사용 후 터미널 연결하기를 하면 아래와 같은 오류가 뜹니다.폴더 이름은 맞게 입력했는데 왜 이런 오류가 생기는지 모르겠습니다.ㅠ
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
변수, useState 부분 질문있습니다.
안녕하세요 수업 너무 잘 듣고 있습니다. 수업을 듣다 궁금한점이 생겼는데 제가 인강을 보면서 변수 let, const와, 리액트에서 useState부분을 보고 이해는 갔지만 제가 막상 혼자 코드를 친다고 했을때 let, const와 useState를 언제 작성을 하면 되는지 잘 모르겠더라구요. 혼자 코드를 작성을 한다고 할때 변수와 useState를 언제 작성을 하면된다라고 이해를 하면 쉽게 이해할수있을까요?
-
미해결Next + React Query로 SNS 서비스 만들기
link태그의 prefetching 질문
안녕하세요 선생님상세페이지에서 홈으로 이동할때 로딩화면에 관련해서Link태그의 prefetching 질문있습니다.아래와 같이 suspense를 적용했을때app/(afterLoging)/home/page.tsximport style from './home.module.scss' import Tab from "@/app/(afterLogin)/home/_component/Tab"; import TabProvider from "@/app/(afterLogin)/home/_component/TabProvider"; import PostForm from "@/app/(afterLogin)/home/_component/PostForm"; import TabDeciderSuspense from '@/app/(afterLogin)/home//_component/TabDeciderSuspense'; import { Suspense } from 'react'; import Loading from './loading'; import { auth } from '@/auth'; export default async function Home() { const session = await auth(); return ( <main className={style.main}> <TabProvider> <Tab /> <PostForm me={session} /> {/* suspense는 서버컴포넌트여야만 한다. */} {/* suspense는 부모컴포넌트여야지 자식(아래)있는 컴포넌트 감지할 수 있다. */} <Suspense fallback={<Loading />}> <TabDeciderSuspense /> </Suspense> </TabProvider> </main> ); } next.js 문서를 보면link태그가 있는 경우, 화면에 들어왔을때static한 부분은 prefetch하고, 데이터 호출이 필요한 경우는 loading.tsx까지 호출해준다고 되어있더라구요.그래서 제가 기대한 것은 상세페이지에서, 홈의 Link태그가 화면에 들어오기 대문에, 홈으로 이동했을때 첫번째 이미지가 아닌, 두번째 이미지처럼 로딩이 되어야할 것 같은데 첫번째 이미지 처럼 되더라구요. (이동한것도 30초 이내였습니다)혹시 제가 잘못이해한건지 알려주시면 감사합니다.유저 상세페이지에서 홈으로 이동할때suspense적용후 새로고침하거나 팔로우중 클릭시
-
미해결Next + React Query로 SNS 서비스 만들기
찜하기하고 해당글 상세페이지 이동시 찜 정보제대로 안내려오는 현상
안녕하세요 선생님홈에서 찜했다, 안했다 잘 작동하고상세페이지로 이동하면 찜하기 데이터가 제대로 내려오지 않는 부분을 확인했습니다.호출은 아래와 같이 하고있습니다./src/app/(afterLogin)/[username]/status/[id]/page.tsximport BackButton from "@/app/(afterLogin)/_component/BackButton"; import style from './singlePost.module.scss'; import Post from "@/app/(afterLogin)/_component/Post"; import CommentForm from "@/app/(afterLogin)/[username]/status/[id]/_component/CommentForm"; import SinglePost from '@/app/(afterLogin)/[username]/status/[id]/_component/SinglePost'; import Comments from '@/app/(afterLogin)/[username]/status/[id]/_component/Comments'; import { HydrationBoundary, QueryClient, dehydrate } from '@tanstack/react-query'; import { getSinglePost } from '@/app/(afterLogin)/[username]/status/[id]/_lib/getSinglePost'; import { getComments } from '@/app/(afterLogin)/[username]/status/[id]/_lib/getComments'; type Props = { params: { id: string} } export default async function Pasge({ params }: Props) { console.log('----------------------------- single post params', params); const { id } = params; const queryClient = new QueryClient(); await queryClient.prefetchQuery({ queryKey: ['posts', id], queryFn: getSinglePost }); await queryClient.prefetchQuery({ queryKey: ['posts', id, 'comments'], queryFn: getComments }); const dehydratedState = dehydrate(queryClient); return ( <div className={style.main}> <HydrationBoundary state={dehydratedState}> <div className={style.header}> <BackButton/> <h3 className={style.headerTitle}>게시하기</h3> </div> <SinglePost id={id} /> <CommentForm id={id} /> <div> <Comments id={id} /> </div> </HydrationBoundary> </div> ) }/src/app/(afterLogin)/[username]/status/[id]/_component/SinglePost.tsx'use client'; import { Post as IPost } from '@/models/Post' import { useQuery } from '@tanstack/react-query' import { getSinglePost } from '@/app/(afterLogin)/[username]/status/[id]/_lib/getSinglePost'; import Post from '@/app/(afterLogin)/_component/Post'; export default function SinglePost({id, noImage}: {id: string, noImage?: boolean}) { const { data: post, error } = useQuery<IPost, Object, IPost, [_1: string, _2: string]>({ queryKey: ['posts', id], queryFn: getSinglePost, staleTime: 60 * 1000, gcTime: 300 * 100, }); console.log(post, '--------------------------single post'); if (error) { return ( <div style={{ height: 100, alignItems: 'center', fontSize: 31, fontWeight: 'bold', display: 'flex', justifyContent: 'center' }}>게시글을 찾을 수 없습니다.</div> ) } if (!post) { return null; } return <Post post={post} key={post.postId} noImage={noImage} /> }찜하기 코드export default function ActionButtons({ white, post }: Props) { const queryClient = useQueryClient(); const { data: session } = useSession(); const commented = !!post.Comments?.find(d => d.userId === session?.user?.email); const reposted = !!post.Reposts?.find(d => d.userId === session?.user?.email); const liked = !!post.Hearts?.find(d => d.userId === session?.user?.email); const { postId } = post; const heart = useMutation({ mutationFn: () => { return fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/posts/${postId}/heart`, { method: 'post', credentials: 'include', }) }, onMutate() { const queryCache = queryClient.getQueryCache(); const queryKeys = queryCache.getAll().map(cache => cache.queryKey); console.log('queryKey', queryKeys); queryKeys.forEach((queryKey) => { if (queryKey[0] === 'posts') { const value: Post | InfiniteData<Post[]> | undefined = queryClient.getQueryData(queryKey); if (value && 'pages' in value) { const obj = value.pages.flat().find(d => d.postId === postId); if (obj) { // 존재는 하는지? const pageIndex = value.pages.findIndex(page => page.includes(obj)); const index = value.pages[pageIndex].findIndex(d => d.postId === postId); const shallow = produce(value, draft => { draft.pages[pageIndex][index].Hearts = [{ userId: session?.user?.email as string }]; draft.pages[pageIndex][index]._count.Hearts += 1; }) queryClient.setQueryData(queryKey, shallow); } } else if (value) { // 싱글 포스트인 경우 if (value.postId === postId) { const shallow = { ...value, Hearts: [...value.Hearts, { userId: session?.user?.email as string }], _count: { ...value._count, Hearts: value._count.Hearts + 1, } } queryClient.setQueryData(queryKey, shallow); } } } }) }, onError() { }, onSettled() { } }); 다른 찜하기 질문에서키를가지고 호출하지 않해서라고 하신걸 봤었는데,위와 같은 경우에는 클라이언트 서버에서 쿼리키를 가지고 호출했는데 데이터가 잘 안내려오는 것을 확인했습니다.찜을 눌렀을때찜을 누르고 해당글 상세로 이동했을때이러한 경우에는 찜하기를 누르고 추가적인 작업이 필요한지 궁금합니다. 예를들면 찜하기를 누르고 해당 쿼리키의 데이터를 호출해야한다는지... 혹은 제가 잘못호출한것이라면 알려주시면 감사하겠습니다.
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
3-4질문 계속합니다 ㅠㅠ 죄송합니다
계속 질문드려 죄송합니다 ㅜㅠ 들여쓰기했는데 이번에 Song.from_dict() missing 1 required positional argument: 'data' 이런오류가뜹니다.. 너무 질문이 많아 죄송합니다..