isPending은 데이터를 불러오고 있을 때, true가 되고 isLoading 은 쿼리가 처음으로 실행될 때 true 가 되는 것으로 알고 있습니다. 제가 이해하기로는 두 속성의 개념이 상당히 많이 겹칠 수 있을 것 같은데, 왜 이렇게 개별로 있는 것인지 궁금합니다.
안녕하세요. 강사님 예제를 보고 하던 중 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 관련해서 추가로 궁금한건 강의가 따로 있다고 영상에서 말씀하셔서 거기까지 보고 필요할 경우 질문 한번 더 드리겠습니다. 👍
안녕하세요 수업 너무 잘 듣고 있습니다. 수업을 듣다 궁금한점이 생겼는데 제가 인강을 보면서 변수 let, const와, 리액트에서 useState부분을 보고 이해는 갔지만 제가 막상 혼자 코드를 친다고 했을때 let, const와 useState를 언제 작성을 하면 되는지 잘 모르겠더라구요. 혼자 코드를 작성을 한다고 할때 변수와 useState를 언제 작성을 하면된다라고 이해를 하면 쉽게 이해할수있을까요?
안녕하세요 선생님 상세페이지에서 홈으로 이동할때 로딩화면에 관련해서 Link태그의 prefetching 질문있습니다. 아래와 같이 suspense를 적용했을때 app/(afterLoging)/home/page.tsx import 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적용후 새로고침하거나 팔로우중 클릭시
Supabase, Next 풀 스택 시작하기 (feat. 슈파베이스 OAuth, nextjs 14)
강의를 보고 같이 프로젝트도 만들어봤는데 문제가 생겨 글을 작성합니다. response 값을 확인하려고 네트워크 탭을 확인하니 프리플라이트가 같이 생성되고 클릭할 시 아래와 같은 메시지가 나옵니다. {"message":"No API key found in request","hint":"No apikey request header or url param was found."} 혹시 이 문제를 해결할 수 있는 방법을 알고 계신가요? 처음부터 supabase 설정을 다시 해야될까요?
prefetchQuery 서버컴포넌트에서 데이터를 한번 불러오면, 정상적으로 불러왔는지 확인할 수 있나요?? 서버 컴포넌트에서 prefetchQuery한 다음에 클라이언트컴포넌트에서 useQuery로 불러오게 되면(queryKey 동일) 이미 데이터가 저장 되어 있는거로 알고 있는데, console.log를 찍어보게 되면, undefined가 뜬 다음에 데이터가 호출 됩니다. prefetchQuery가 정상적으로 동작 안하는게 아닌가 싶습니다. export default function TestClient() { const { data } = useQuery({ queryKey: ['typeData'], queryFn: getTypeData, }); console.log(typeData); ... export default async function TestServer() { const queryClient = new QueryClient(); await queryClient.prefetchQuery({ queryKey: ['typeData'], queryFn: getTypeData }); const dehydratedState = dehydrate(queryClient); return ( <> <HydrationBoundary state={dehydratedState}> <TestClient /> </HydrationBoundary> </> ); }
현재 리액트부분을 시작했는데 리액트를 설치할때 yarn add next@12.1.0 react@17.0.2 react-dom@17.0.2 --exact 이러한 명령어를 사용하는데 이렇게 설치하고 나니 제가 알고있는 폴더들이나 내용이 좀 다르더라구요. 제가 알고있는 건 npx create-react-app ./ 이러한 명령어로 리액트를 설치했는데 이거와 전혀 다른 명령어 인가요?
login은 인터셉팅 라우터가 잘 되는데, signup은 (.)i로 인터셉팅이 안되고 버튼 클릭을 하면 그냥 i/flow/signup/page.tsx로만 보여지는 문제가 있습니다. 왜 signup은 인터셉팅 라우터가 작동이 안되는 것일까요?? 경로는 이렇게 잘 설정되어있고 안에 파일 내용은 아래와 같습니다. 아래는 @modal/(.)i/flow/signup/page.tsx 아래는 i/flow/signup/page.tsx 홈 버튼 링크는 아래와 같이 되어있습니다. 혹시 제가 빠뜨린 무엇이 있을까요?
안녕하세요. 강의 잘 보고 있습니다.!! 👍 👍 react-query를 적용 중 오류가 표시되어 오류와 궁금한 부분이 있어서 문의 드립니다. Text content did not match. 오류가 발생하는데 어느 부분이 문제인지 잘 모르겠습니다 ㅠㅠ prefetchQuery 를 사용하여 서버에서 post(트윗)데이터를 프리패치 후 TweetList컴포넌트에서 useQuery 를 사용하게 만들었습니다. Post의 데이터는 msw에서 알려주신 faker를 통해서 요청마다 content를 동적으로 생성하게 했구요. 콘솔로 출력한 데이터와 reactQuery개발 도구의 데이터는 동일한데 화면에 표기된 데이터는 전혀 다른 데이터로 표시되네요.. 그리고 방식이 prefetchQuery 를 사용한 데이터는 staleTime과 상관없이 Fresh상태로 되어 useQuery 호출 시 데이터가 아직 fresh한 상태이므로 서버를 호출하지 않고 캐쉬에서 가져와 보여주는 방식이 맞나요? 오류로그 app-index.js:33 Warning: Text content did not match. Server: "Tener adulatio decens conitor. Thesis apostolus ago at decerno. Iste uberrime commodo. Verus amitto quas cometes delicate. Cognomen alii curto ciminatio. Solitudo complectus tristis. Teneo sum vindico. Adhuc decimus triumphus ipsa arguo umquam addo adulatio cresco. Sponte degenero non trado cauda beneficium laboriosam approbo." Client: "Tremo collum sint terror templum summisse viduo usque unus benevolentia. Eligendi substantia concido amissio uredo turpis aperte. Admoneo titulus audeo conicio fuga." at div at div at div at article at TweetWrapper (webpack-internal:///(app-pages-browser)/./src/app/(afterLogin)/home/_components/TweetWrapper.tsx:11:11) at Tweet (webpack-internal:///(app-pages-browser)/./src/app/(afterLogin)/home/_components/Tweet.tsx:31:11) at TweetList (webpack-internal:///(app-pages-browser)/./src/app/(afterLogin)/home/_components/TweetList.tsx:16:93) at HydrationBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/@tanstack+react-query@5.39.0_react@18.2.0/node_modules/@tanstack/react-query/build/modern/HydrationBoundary.js:14:11) at HomeContextProvider (webpack-internal:///(app-pages-browser)/./src/app/(afterLogin)/home/_components/Provider.tsx:17:11) at InnerLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:242:11) at RedirectErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/redirect-boundary.js:74:9) at RedirectBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/redirect-boundary.js:82:11) at NotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/not-found-boundary.js:84:11) at LoadingBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:340:11) at ErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/error-boundary.js:162:11) at InnerScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:152:9) at ScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:227:11) at RenderFromTemplateContext (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/render-from-template-context.js:16:44) at OuterLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:359:11) at InnerLayoutRouter (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:242:11) at RedirectErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/redirect-boundary.js:74:9) at RedirectBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/redirect-boundary.js:82:11) at NotFoundBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/not-found-boundary.js:84:11) at LoadingBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:340:11) at ErrorBoundary (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/error-boundary.js:162:11) at InnerScrollAndFocusHandler (webpack-internal:///(app-pages-browser)/./node_modules/.pnpm/next@14.1.4_@babel+core@7.24.4_react-dom@18.2.0_react@18.2.0/node_modules/next/dist/client/components/layout-router.js:152:9) at ScrollAndFocu 소스코드 (Tweet이 Post입니다! 나중에 바꿔야겠네여) [page.tsx] /home import React from "react"; import HomeTopTab from "./_components/HomeTopTab"; import WriteForm from "./_components/WriteForm"; import TweetList from "./_components/TweetList"; import HomeContextProvider from "./_components/Provider"; import { QueryClient, dehydrate, HydrationBoundary, } from "@tanstack/react-query"; import getPostRecommends from "./_lib/getPostRecommends"; const HomePage = async () => { const queryClient = new QueryClient(); await queryClient.prefetchQuery({ queryKey: ["tweet", "recommends"], queryFn: getPostRecommends, }); const dehydratedState = dehydrate(queryClient); return ( <HomeContextProvider> <HomeTopTab /> <WriteForm /> <HydrationBoundary state={dehydratedState}> <TweetList /> </HydrationBoundary> </HomeContextProvider> ); }; export default HomePage; TweetList.tsx "use client"; import React from "react"; import Tweet from "./Tweet"; import getPostRecommends from "../_lib/getPostRecommends"; import { Post } from "./TweetWrapper"; import { QueryClient, useQuery } from "@tanstack/react-query"; const TweetList = () => { const { data: tweets } = useQuery<Post[]>({ queryKey: ["tweet", "recommends"], queryFn: getPostRecommends, enabled: false, }); console.log("🚀 _ TweetList _ tweets:", tweets); return tweets?.map((tweet) => <Tweet post={tweet} key={tweet.postId} />); }; export default TweetList;
geolocation부분에 const askForLocation = function () { navigator.geolocation.getCurrentPosition((position) => { console.log(position); }); }; askForLocation(); 이렇게 함수가 있는데 여기서 궁금한점이 askForLocation(); 함수 호출부분에 인자로 전달하는 것이 없는데 매개변수로 position에 위치정보 객체형식으로 콘솔에 나오는 이유가 뭔지 궁금합니다.
따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
sudo iptables -A PREROUTING -t nat -i eth0 -p tcp --dport 80 -j REDIRECT --to-port 3000 까지 하고 3000번 포트로 잘 들어가지는데 3000번포트를 지우고 들어가봐도 뒤에 :80을 붙여 넣어 들어가봐도 사이트에 연결할 수 없음이 뜨네요 왜 그럴까요??
함수, 변수의 호이스팅 강의 영상 부분에 if (storageData?.complete) { newLi.classList.add("complete"); } 이 코드에서 storageData 뒤에 ? 이 물으표가 없으면 매개변수를 받아오지 않게 되니 undefined라고 강사님이 말씀하시는데 이게 무슨 말인지 잘 모르겠습니다. 그리고 ToDoList에서 리스트에 추가를 하고 더블클릭 삭제, 전체 삭제까지는 어느정도 이해가 되는데 로컬스트리지 전체 부분이 조금 이해도 어려운데 어떻게 이해를 하면서 공부를 하면 좋을까요?
Next.js와 Spring boot를 사용해서 소셜 로그인을 추가하려고 합니다. 소셜 로그인의 경우 코드와 토큰을 프론트에서 관리하지 않는 것이 좋다고 하여 백엔드에서 모든 로직을 처리하고 있습니다. 현재 프론트에서 window.location.href = "http://localhost:8080/oauth2/authorization/google"; 위와 같은 경로로 백엔드로 소셜 로그인 요청을 보내고 백엔드에서는 소셜 로그인을 진행한 뒤에 유저 정보를 생성하고 JWT를 생성한 뒤 응답의 헤더에 쿠키 형태로 JWT를 넣어 response.sendRedirect("http://localhost:3000/auth/social"); 로 리다이렉트하고 있습니다. 프론트에서는 /auth/social 페이지에서 쿠키에 있는 JWT를 꺼내 유저 정보를 가져오는 API를 다시 호출해 유저 정보를 가져오고 있습니다. 이 후 auth.js 라이브러리를 통한 session 관리를 하고자 하는데 session을 업데이트 하려면 어떻게 해야 하나요..? (session.user가 있는지 없는지를 통한 로그인 체크를 위해 사용한다고 이해했습니다.) 서버 컴포넌트에서 import { auth } from "@/auth"; 를 통해 가져온 session에 데이터를 넣어보았지만 데이터가 제대로 들어가지 않는 것 같아 조언을 구해봅니다..