-
[Nextjs]SSG,SSR react-query로 Dynamic Routes에 적용Next.js 2022. 12. 22. 16:07728x90
_app.tsx
import '../styles/globals.css'; import React from 'react'; import type { AppProps } from 'next/app'; import { Hydrate, QueryClient, QueryClientProvider } from 'react-query'; import { RecoilRoot } from 'recoil'; function MyApp({ Component, pageProps }: AppProps) { const queryClient = React.useRef(new QueryClient()); //const [queryClient] = React.useState(() => new QueryClient()) return ( <QueryClientProvider client={queryClient.current}> {/* <QueryClientProvider client={queryClient}> */} <Hydrate state={pageProps.dehydratedState}> <RecoilRoot> <Component {...pageProps} /> </RecoilRoot> </Hydrate> </QueryClientProvider> ); } export default MyApp
[postId].tsx
import type { GetServerSideProps, GetStaticPaths, GetStaticProps, InferGetStaticPropsType, NextPage } from 'next' import Image from 'next/image'; import Format from '../../layout/format'; import Author from '../../components/_child/author'; import Ralated from "../../components/_child/ralated" import { ParsedUrlQuery } from 'querystring'; import { dehydrate, QueryClient, useQuery } from 'react-query'; import { useRouter } from 'next/router'; import Error from '../../components/_child/error'; import Spinner from '../../components/_child/spinner'; interface PostsProps { id:Number; title:string; subtitle:string; category:string; img:string; description:string; published:string; author:{ name:string; img:string; designation:string; } } const page = () => { const router = useRouter(); const { postId } = router.query; //const { data, isLoading, isError } = useQuery(["post"], () => getPost(postId ? postId : 1)); const { data, isLoading, isError } = useQuery<PostsProps>(["post"], () => getPost(postId ? postId : 1)); //const {id, title, subtitle, description, category, img, published, author } = posts; if (isLoading) { return <Spinner></Spinner>; } if (isError) { return <Error></Error>; } //const {id, title, subtitle, description, category, img, published, author } = data; //const {id, title, subtitle, description, category, img, published, author }:PostsProps = data; return ( <Format> <section className=" container mx-auto md:px-2 py-16 lg:w-1/2"> <div className=" flex justify-center "> { data?.author ? <Author author={data?.author}></Author> : null } </div> <div className="post py-10"> <h1 className=" font-bold text-4xl text-center pb-5">{data?.title || null}</h1> <p className=" text-gray-500 text-xl text-center">{data?.subtitle || null}</p> <div className="py-10"> <Image src={data?.img || "/"} width={900} height = {600}></Image> </div> <div className="content text-gray-600 text-lg flex flex-col gap-4"> {data?.description || null} </div> </div> <Ralated></Ralated> </section> </Format> ); } export default page; interface IParams extends ParsedUrlQuery { postId: string } const getPost = async (postId:string | string[] | number) => await (await fetch(`http://localhost:3000/api/posts/${postId}`)).json(); // export const getServerSideProps: GetServerSideProps = async (context) => { // const queryClient = new QueryClient(); // const { postId } = context.params as IParams; // await queryClient.prefetchQuery<PostsProps>(["post", postId], () => getPost(postId ? postId : 1)); // return { // props: { // dehydratedState: dehydrate(queryClient), // } // } // } // export const getServerSideProps: GetServerSideProps = async (context) => { // const baseURL = "http://localhost:3000/api/posts/"; // const { postId } = context.params as IParams; // const res = await fetch(`${baseURL}${postId}`); // const posts: PostsProps = await res.json(); // return{ // props: { // posts // } // } // } export const getStaticProps: GetStaticProps = async (context) => { const queryClient = new QueryClient(); const { postId } = context.params as IParams; await queryClient.prefetchQuery<PostsProps>(["post"], ()=> getPost(postId ? postId : 1)); return { props: { dehydratedState: dehydrate(queryClient), } } } export const getStaticPaths: GetStaticPaths = async () => { const baseURL = "http://localhost:3000/api/posts/"; const res = await fetch(`${baseURL}`); const posts: PostsProps[] = await res.json(); const paths = posts.map((value)=>{ return{ params:{ postId: value.id.toString() } } }) return { paths, fallback:false, }; } // export const getStaticProps: GetStaticProps<{ posts: PostsProps }> = async (context) => { // // export async function getStaticProps: GetStaticProps<{posts:PostsProps[]}>(){ // const baseURL = "http://localhost:3000/api/posts/"; // const { postId } = context.params as IParams; // const res = await fetch(`${baseURL}${postId}`); // const posts: PostsProps = await res.json(); // return{ // props: { // posts // } // } // } // export const getStaticPaths: GetStaticPaths = async () => { // const baseURL = "http://localhost:3000/api/posts/"; // const res = await fetch(`${baseURL}`); // const posts: PostsProps[] = await res.json(); // const paths = posts.map((value)=>{ // return{ // params:{ // postId: value.id.toString() // } // } // }) // return { // paths, // fallback:false, // }; // }
오류 디버깅
error - unhandledRejection: TypeError: Cannot read properties of null (reading 'useRef')
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
Missing queryFn
Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array insteadUnhandled Runtime Error
Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons: 1. You might have mismatching versions of React and the renderer (such as React DOM) 2. You might be breaking the Rules of Hooks 3. You might have more than one copy of React in the same app See https://reactjs.org/link/invalid-hook-call for tips about how to debug and fix this problem.
오류 원인
1. 아래 빨간색 오류는 부모 컴포넌트인 page 컴포넌트 화살표 함수에다가 async 쳐 박아서 에러남;;
2. 부모에 해당하는 페이지 컴포넌트 page()에다가 async 쳐박은 이유 react-query에 useQuery 훅에 2번째 인자값 getPost함수가 await 넣으라고 오류가 떠서 넣어서Error: Objects are not valid as a React child (found: [object Promise]). If you meant to render a collection of children, use an array instead.
const getPost = async (postId:string | string[] | number) => await (await fetch(`http://localhost:3000/api/posts/${postId}`)).json();
PostId에 따라 다이나믹 라우터로 게시글 가져오는 fetch함수인데 요놈 호출할때 await 대신 ()=>로 바꿔서 처리함.
오류 코드
const page = async() => { const router = useRouter(); const { postId } = router.query; const { data, isLoading, isFetching } = useQuery<PostsProps>(["post", postId], await getPost(postId ? postId : 1)); ... ...
수정코드
const page = () => { const router = useRouter(); const { postId } = router.query; const { data, isLoading, isFetching } = useQuery<PostsProps>(["post", postId], () => getPost(postId ? postId : 1));
https://react-query-v3.tanstack.com/examples/nextjs
https://prateeksurana.me/blog/mastering-data-fetching-with-react-query-and-next-js/
728x90'Next.js' 카테고리의 다른 글
Nextjs에서 Nestjs로 accessToken header로 요청할때 오류 (0) 2022.12.26 Recoil, react-query 로그인 오류 (0) 2022.12.24 [Nextjs]상태관리 (2) 2022.12.22 [Nextjs 스와이프] Swiper 사용 (0) 2022.07.23 [Nextjs 시작] (0) 2022.07.19