173만명의 커뮤니티!! 함께 토론해봐요.
해결됨
Next + React Query로 SNS 서비스 만들기
서버 컴포넌트에서 server actions 사용 중 네트워크 탭에서 응답이 안담기는 문제가 있어서 질문 드립니다. 강의에 나와있는대로 코드를 따라했는데 뭐가 문제인지 잘 모르겠습니다. 아래는 signupModal의 코드입니다. import style from "./signup.module.css"; import onSubmit from "../_lib/signup"; import BackButton from "@/app/(beforelogin)/_component/BackButton"; import { useFormState, useFormStatus } from "react-dom"; import { redirect } from "next/navigation"; function showMessage(messasge: string | null | undefined) { if (messasge === "no_id") { return "아이디를 입력하세요."; } if (messasge === "no_name") { return "닉네임을 입력하세요."; } if (messasge === "no_password") { return "비밀번호를 입력하세요."; } if (messasge === "no_image") { return "이미지를 업로드하세요."; } if (messasge === "user_exists") { return "이미 사용 중인 아이디입니다."; } return ""; } export default function SignupModal() { //const [state, formAction] = useFormState(onSubmit, { message: null }); //const { pending } = useFormStatus(); const formAction = async (formData: any) => { "use server"; let shouldRedirect = false; try { const response = await fetch( `${process.env.NEXT_PUBLIC_BASE_URL}/api/users`, { method: "post", body: formData, credentials: "include", } ); console.log(response.status); console.log(await response.json(), "abc"); if (response.status === 403) { console.log("???"); return { message: "user_exists" }; } shouldRedirect = true; } catch (err) { console.log(err); } if (shouldRedirect) { redirect("/home"); // try/catch문 안에서 X } }; return ( <> <div className={style.modalBackground}> <div className={style.modal}> <div className={style.modalHeader}> <BackButton /> <div>계정을 생성하세요.</div> </div> <form action={formAction}> <div className={style.modalBody}> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="id"> 아이디 </label> <input id="id" name="id" className={style.input} type="text" placeholder="" required /> </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="name"> 닉네임 </label> <input id="name" name="name" className={style.input} type="text" placeholder="" required /> </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="password"> 비밀번호 </label> <input id="password" name="password" className={style.input} type="password" placeholder="" required /> </div> <div className={style.inputDiv}> <label className={style.inputLabel} htmlFor="image"> 프로필 </label> <input id="image" name="image" required className={style.input} type="file" accept="image/*" /> </div> </div> <div className={style.modalFooter}> <button type="submit" className={style.actionButton}> 가입하기 </button> </div> </form> </div> </div> </> ); } 아래는 핸들러 세팅입니다. 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", // }, // }); }), 여기서 회원가입을 누를시에 console.log() 처리한 부분은 잘 찍히고 서버쪽에서 찍은 회원가입 콘솔도 잘 찍히는 모습입니다. 네트워크탭에서 페이로드는 잘 담겼는데, 응답이 없습니다. 회원가입 누를 때 콘솔이 찍히는 것으로 보아서 포트도 9090으로 제대로 열려있고, 403응답이 오는 것으로 보아 핸들러 쪽은 제대로 작동하는 것 같습니다. 그리고 서버액션 쪽 콘솔 "???"가 찍히는 것으로 보아서 status도 403으로 잘 오는 것 같은데 리턴 메시지가 제대로 안되는 것인지 응답이 왜 없는 것인지 궁금합니다.
react next.js react-query next-auth msw
강주호
2024-05-04T05:13:07.820Z
댓글 1
좋아요 0
조회수 604
미해결
[리뉴얼] React로 NodeBird SNS 만들기
게시글을 끝까지 스크롤하고, 다른 페이지에 다녀오면 다른 페이지갔다가 오면 게시글 불러와지는 이슈를 발견했습니다. index.js에서 게시글 불러오는 부분에 mainposts의 조건을 붙여서 실행하면될거같은데 차후 강의에서 해결해주시는 이슈인지 궁금합니다. 아니면 저만 그런건지 여쭤봅니다! 감사합니다.
react redux node.js express next.js
챠챠_
2024-05-03T23:52:00.059Z
댓글 1
좋아요 0
조회수 169
미해결
[리뉴얼] React로 NodeBird SNS 만들기
강의를 보고 따라하다가 오늘 보니 저번 달 사용량에 관련된 요금이 결제되었다고 메일을 받았습니다.. Amazon Virtual Private Cloud 에서 좀 많이 나왔고,, Amazon Route 53에도 요금이 나왔네요.. 총 만원정도 과금이 되었는데 어떤건지 몰라서 어디부분을 삭제해야 비용이 발생하지 않는걸까요? 강의를 잘 보고 따라했는데.. 당황스럽습니다...
react redux node.js express next.js
hyuri
2024-05-03T09:27:25.779Z
댓글 2
좋아요 0
조회수 419
미해결
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
안녕하세요!! 과제 완료해서 피드백 부탁드리고자 올렸습니다! 앞으로 잘 부탁 드립니당~ <html> <!DOCTYPE html> <html lang="ko"> <head> <title>회원가입</title> <link rel="stylesheet" href="./02-signup.css"> </head> <body> <div class="signUpContent"> <h2> 회원 가입을 위해<br> 정보를 입력해주세요 </h2> <label for="email" class="label text">* 이메일</label> <input id="email" class="input_text" type="text"> <label for="name" class="label text">* 이름</label> <input id="name" class="input_text" type="text"> <label for="password" class="label text">* 비밀번호</label> <input id="password" class="input_text" type="password"> <label for="password_chk" class="label text">* 비밀번호 확인</label> <input id="password_chk" class="input_text" type="password"> <div class="signUpChk"> <input id="gender_w" class="input_radio" type="radio" name="gender"> <label for="gender_w" class="label gender">여성</label> <input id="gender_m" class="input_radio" type="radio" name="gender"> <label for="gender_m" class="label gender">남성</label> </div> <div class="agreeChk"> <input type="checkbox" id="input_chk"> <span class="agree_text"> 이용약관 개인정보 수집 및 이용, 마케팅 활용 선택에 모두 동의합니다. </span> </div> <div class="out-line"> <div class="line"></div> </div> <button> <span>가입하기</span> </button> </di> </body> </html> <css> * { box-sizing: border-box; } h2 { font-size: 32px; color: #0068FF; font-weight: 700; line-height: 47px; } .out-line{ padding: 30px 0px; } .line { border-bottom: 1px solid #E6E6E6; } .label{ font-size: 16px; font-weight: 400; line-height: 24px; } .signUpContent{ width: 670px; height: 960px; border: 1px solid #AACDFF; border-radius: 20px; box-shadow: 7px 7px 39px rgba(0, 104, 255, .25) ; display: flex; flex-direction: column; padding: 72px 100px 70px 100px; } .label.text{ padding: 20px 20px 0 0; color: #797979; } .input_text{ border-style: none; border-bottom: 1px solid #CFCFCF; height: 60px; } .signUpChk{ display:flex; justify-content: center; align-items: center; padding: 50px 0; } .input_radio{ margin: 0 5px 0 0; width: 20px; height: 20px; } .label.gender{ padding-right: 30px; } .agreeChk{ display: flex; justify-content: center; align-items: center; } .agree_text{ height: 22px; font-size: 14px; font-weight: 400; line-height: 20px; } button{ width: 470px; height: 75px; background-color: #FFF; border: 1px solid #0068FF; border-radius: 10px; } button > span { font-size: 18px; font-weight: 400; color: #0068FF; }
react node.js seo graphql next.js
개발하는 알파카
2024-05-03T06:52:35.874Z
댓글 2
좋아요 0
조회수 304
미해결
[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요 회원가입 후에 로그인이 된 상태여야 하는데 로그인이 풀리는 현상을 확인했습니다. 왜 인지 찾아보니 프론트에선 회원가입 후 더미데이터를 가지고 로그인 하고 있었음 백단에서는 회원가입 유저의 정보를 내려주지 않고 있었음. 이런 경우때문인 것 같았습니다. 그래서 회원가입 후 메인 페이지로 라우팅 되면 메인페이지에서 로그인 유무를 판단하는 로직이 실행되고, 더미데이터로 있던 데이터를 로그인 풀어버려서 그런게 아닐까 합니다. 그러면 /back/routes/user.js const user = await User.create({ email, nickname, password: hashedPassword, }); 여기서 user정보를 내려줘야할거 같은데 여기서 더 필요한 post, image같은 이미지는 어떻게 추가해야하는지 궁금합니다.
react redux node.js express next.js
챠챠_
2024-05-03T00:51:33.349Z
댓글 1
좋아요 0
조회수 167
미해결
[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요 센셕4 게시물 불러오기 postcard.js에서 post.User.nickname[0]에러가 발생해서 처음엔 간단하게 /components/postcard.js <Card.Meta avatar={<Avatar>{post.User?.nickname[0]}</Avatar>} title={post.User?.nickname} description={<PostCardContent postData={post.content} />} /> 이런식으로 해결했었습니다. 아 같은 파일 위치에서 {id && post.User?.id === id ? ( <> <Button type='primary' key='modify'> 수정 </Button> <Button type='danger' key={"delete"} onClick={onRemovePost} loading={removePostLoading}> 삭제 </Button> </> ) : ( <Button type='dashed' key={"report"}> 신고 </Button> )} post.User?.id 이것도 같은 식으로 처리했었습니다. 그런데 제로초님 코딩을 몇번 다시봤더니 비슷한 에러가 코멘트에서 났었는데 /routes/posts.js const express = require("express"); const router = express.Router(); const { Post, User, Image, Comment } = require("../models"); // GET /posts 여러 게시글 가져오기 router.get("/", async (req, res, next) => { try { const posts = await Post.findAll({ limit: 10, include: [ { model: User, attributes: ["id", "nickname"], }, { model: Image, }, { model: Comment, include: [ { model: User, attributes: ["id", "nickname"], }, ], }, ], }); res.status(200).json(posts); } catch (error) { console.error(error); next(error); } }); module.exports = router; 이런식으로 데이 필요한 id, nickname을 넣어주셔서 ?를 붙이지 않고 해결하셨더라구요. 혹시 저 nickname부분도 위와같이 백단에서 코드를 수정해서 고칠수 있을까요? 따라서 해봤는데 잘 안되서 여쭤봅니다.
react redux node.js express next.js
챠챠_
2024-05-02T16:10:50.051Z
댓글 3
좋아요 0
조회수 356
해결됨
Next + React Query로 SNS 서비스 만들기
안녕하세요. 인피니티스크롤 을 따라하는데 잘안되서요. const queryClient = new QueryClient(); await queryClient.prefetchInfiniteQuery({ queryKey: ["member", "sales", sawonCode], queryFn: getSales, initialPageParam: 0, }) const dehydratedState = dehydrate(queryClient); return <> <Suspense fallback={<Loading />}> <HydrationBoundary state={dehydratedState}> <SalesList sawonCode={sawonCode} /> </HydrationBoundary> </Suspense> </> const { data, fetchNextPage, hasNextPage, isFetching, } = useInfiniteQuery<Item[], Object, InfiniteData<Item[]>, [_1: string, _2: string, _3: number], number>({ queryKey: ["member", "sales", sawonCode], queryFn: getSales, initialPageParam: 0, getNextPageParam: (lastPage) => lastPage.at(-1)?.page, staleTime: 60 * 1000, // fresh -> stale, 5분이라는 기준 gcTime: 300 * 1000, }); const { ref, inView } = useInView({ threshold: 0, delay: 0, }); useEffect(() => { if(inView) { console.log(data); !isFetching && hasNextPage && fetchNextPage(); } }, [inView, isFetching, hasNextPage, fetchNextPage]); useEffect에 콘솔에찍은 data는 undefined 이 찍히고 그후에 getSales에 찍은 api 로 가져온 데이터가 찍힙니다. 어떤게 잘못되서 data에 값이 안들어가는지 몇시간을 봐도 잘모르겠네요..ㅜㅜ
react next.js react-query next-auth msw
11m48a2c
2024-05-02T14:48:01.784Z
댓글 1
좋아요 0
조회수 253
미해결
Next + React Query로 SNS 서비스 만들기
return { name: user.nickname, email: user.email, image: user.profileImage, ...user, }; 강의에서 user를 그대로 리턴해서 사용하지 않고 user를 커스텀해준 것을 보았습니다. 현재 return하는 값은 Typescript에서 지정한 User 타입을 그대로 사용하면서 수정해서 값을 할당해줬다고 이해했는데 추가로 들어가는 ...user 는 어디에서 사용할 수 있는지 궁금합니다. 추가로 제 코드에는 반환하는 정보가 더 많은데 어떤 식으로 값을 할당해서 사용할 수 있는지 궁금합니다. 타입을 하나 만들어서 확장해서 사용하고 싶은데 따로 파일을 만들어줘야 할까요?
react next.js react-query next-auth msw
이우열
2024-05-02T03:18:29.860Z
댓글 1
좋아요 0
조회수 282
미해결
[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요 제로초님 강의를 따라가다 보니 로그인 부분이 엄청 복잡하더라구요, 개인적으로 next-auth을 사용하면 되게 간편했던걸로 기억하는데 제로초님은 로그인 기능을 만들게 된다면 next-auth와 수업에서 처럼 직접 구현하는 것 어떤걸 더 추천하실지 궁금합니다. 직접구현하는게 로그인이 어케 이뤄지는지 이해할수있어서 좋은거같은데 여쭤보고 싶었습니다!
react redux node.js express next.js
챠챠_
2024-05-01T22:56:49.000Z
댓글 1
좋아요 0
조회수 291
해결됨
기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
HeaderBgChanger라는 컴포넌트는 단순히 서버 컴포넌트에서 react hook을 사용할 수 없기 때문에 만드는 컴포넌트인지 궁금합니다. 또 이렇게 컴포넌트를 만들 경우에 렌더링 될 때 영향을 주는 부분은 없는지 궁금합니다.
react 인터랙티브-웹 클론코딩 next.js tailwind-css zustand
김택수
2024-05-01T17:52:11.576Z
댓글 2
좋아요 1
조회수 295
미해결
Next + React Query로 SNS 서비스 만들기
Nextjs fetch도 캐시가 지원되고, react-query도 캐시가 지원되는걸로 이해를 했는데요 문득 궁금한 점이 생겨서 질문 드립니다. Nextjs fetch와 react-query에서의 캐시는 같은 개념인가요? 아니면 서로 다른 개념인가요? 왜 Nextjs fetch를 안 쓰고 react-query를 쓰는 걸까요? Nextjs fetch는 어떨 때 쓰고 react-query는 어떨 때 쓰는 건가요? 감사합니다.
react next.js react-query next-auth msw
주니어에요
2024-05-01T13:37:05.205Z
댓글 1
좋아요 0
조회수 456
해결됨
Next + React Query로 SNS 서비스 만들기
안녕하세요. Suspense 컴포넌트의 fallback 요소로 서버 컴포넌트 전달은 문제가 없는데, 내부적으로 useEffect와 타이머를 사용하는 클라이언트 컴포넌트를 전달했더니 해당 훅과 관련된 내용은 모두 스킵되고 그냥 초기 렌더링 내용만 나오는 것 같은데, 애초에 클라이언트 컴포넌트는 전달이 불가능한걸까요? 클라이언트 컴포넌트 사용 의도는 1초마다 로딩바 게이지가 증가하는 모습을 보여주고 싶어서 사용해보려고 했습니다. 공식 문서를 봐도 해당 내용에 대해서는 언급이 없는 것 같습니다. 감사합니다.
react next.js react-query next-auth msw
Yu Byung Suk
2024-05-01T11:35:05.485Z
댓글 1
좋아요 0
조회수 360
미해결
Next + React Query로 SNS 서비스 만들기
"use client"; import { useQuery } from "@tanstack/react-query"; import { getPostRecommends } from "@/app/(afterLogin)/home/_lib/getPostRecommends"; import Post from "@/app/(afterLogin)/_component/Post"; import { Post as IPost } from "@/model/Post"; export default function PostRecommends() { const { data, error, isLoading } = useQuery<IPost[]>({ queryKey: ["posts", "recommends"], queryFn: getPostRecommends, // gcTime은 staleTime보다 길어야한다 staleTime: 5 * 1000, // 새로 가져온 데이터를 몇 초 후에 fresh에서 stale로 바꿀 것인지 gcTime: 300 * 1000, }); if (isLoading) { return <div>Loading...</div>; } if (error) { return <div>Failed to load posts</div>; } return data?.map((post) => <Post key={post.postId} post={post} />); } react query에서 에러가 발생합니다 이유는 모르겠지만 useQuery부분에서 에러가 발생하는 것 같습니다 getPostRecommend.ts는 이렇게 작성한 상태입니다 export async function getPostRecommends() { const res = await fetch(`http://localhost:9090/api/postRecommends`, { next: { tags: ["posts", "recommends"], }, //캐시를 저장하라고 지정하는 태그 // 너무 강력하게 캐싱을 하면 새로운 데이터가 안불러와 질 수 있다 // 이런 일을 방지하기위해 새로고침을 해야하는 이때 tags를 사용한다 }); // The return value is *not* serialized // You can return Date, Map, Set, etc. if (!res.ok) { // This will activate the closest `error.js` Error Boundary throw new Error("Failed to fetch data"); } // 이렇게 하면 recommends를 키로 가지고 있는 서버에 있는 캐시가 날아감 // revalidateTag("recommends") // home으로 온 요청이 왔을때 페이지 전체의 캐시를 새로고침한다 // revalidatePath('/home') return res.json(); } 근데 getPostRecoomed.ts가 잘못된거 같지는 않은것이 처음 작동하는 queryClient.prefetchQuery 는 잘 작동합니다
react next.js react-query next-auth msw
i1004gy
2024-05-01T09:20:43.939Z
댓글 2
좋아요 0
조회수 342
미해결
Next + React Query로 SNS 서비스 만들기
Unhandled Runtime Error Error: Hydration failed because the initial UI does not match what was rendered on the server. Warning: Did not expect server HTML to contain a <a> in <div>. See more info here: https://nextjs.org/docs/messages/react-hydration-error 이런 에러가 발생하는데 초반 랜더링과 뭐가 다르거나 랜덤 데이터를 사용하면 오류가 나온다는 것 같아서 혹시 faker를 사용해서 생긴느 에러인지 궁금합니다 "use client"; import { useQuery } from "@tanstack/react-query"; import { getPostRecommends } from "@/app/(afterLogin)/home/_lib/getPostRecommends"; import Post from "@/app/(afterLogin)/_component/Post"; import { Post as IPost } from "@/model/Post"; export default function PostRecommends() { const { data } = useQuery<IPost[]>({ queryKey: ["posts", "recommends"], queryFn: getPostRecommends, // gcTime은 staleTime보다 길어야한다 staleTime: 60 * 1000, // 새로 가져온 데이터를 몇 초 후에 fresh에서 stale로 바꿀 것인지 }); return data?.map((post) => <Post key={post.postId} post={post} />); } 여기에서 queryFn: getPostRecommends 이 부분을 지워도 정상 작동하는데 queryFn: getPostRecommends 이것이 하는 기능이 무엇인가요? 또 여기에서 Retech와 invalidate를 눌러도 트윗이 변하지 않습니다 혹시 위 에러와 관련이 있나요?
react next.js react-query next-auth msw
i1004gy
2024-05-01T07:27:39.309Z
댓글 2
좋아요 0
조회수 498
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
플레이 그라운드에서 스크랩 해오면 코드에서 인식이 안돼는것 같은데 원인을 못찾겠습니다 ㅠ
react node.js seo graphql next.js
박수민
2024-04-30T08:31:22.262Z
댓글 2
좋아요 0
조회수 333
해결됨
[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
안녕하세요 오늘 이 프론트엔드 부트캠프 수업을 결제해서 시작했는데 노션 수업자료를 준다라고 알고 있는데 이 노션 수업자료는 어디서 받아보면 되나요?
react node.js seo graphql next.js
부드러운 족제비
2024-04-30T07:59:31.001Z
댓글 1
좋아요 0
조회수 207
미해결
[리뉴얼] React로 NodeBird SNS 만들기
안녕하세요 제로초님 여쭤보고 싶은게 있습니다. 강의를 따라가다가 데브툴에서 액션, 데이터들을 확인하시는 모습을 봤는데, 저도 따라해보니 액션명칭도, state tree의 데이터들도 제대로 안나오는것 같더라구요. 그래서 좀 테스트해보니까 아래의 로직처럼 put에 액션 함수를 실행하면 데브툴에서 액션 명칭니 나오고예시: put(액션명(데이터)), 기존처럼 put({type: 액션명, payload: 데이터}) 호출하게되면 undefined로 나오는것 같습니다. function* addPost(action) { try { yield delay(1000); const id = shortid.generate(); yield put(addPostSuccessAction({ id, content: action.payload.text, }) ); yield put({ type: addPostToMe, payload: id }); } catch (err) { yield put({ type: addPostFailureAction, error: err.response.data }); } } 아무래도 toolkit과 saga를 사용할때 저렇게 사용하는게 아닌가 싶은데 undefined로 나오는 부분은 개선했다고 하더라도 action 부분이 제로초님과 다르게 나오더라구요. 액션명만 나오는게 아니라 reducer의 위치도 함께나온느데 이렇게 나와도 괜찮은건지 여쭙고 싶습니다. 다른 부분은 잘 작동하는것 같습니다. import { HYDRATE } from "next-redux-wrapper"; import { createSlice } from "@reduxjs/toolkit"; import shortId from "shortid"; export const initialState = { mainPosts: [ { id: "1", User: { id: "1", nickname: "zzimzzim", }, content: "첫 번째 게시글 #해시태그, #익스프레스", Images: [ { id: shortId.generate(), src: "https://loremflickr.com/cache/resized/65535_53669042936_630c778818_320_240_nofilter.jpg", }, { id: shortId.generate(), src: "https://loremflickr.com/cache/resized/65535_52982053835_12fc661207_320_240_nofilter.jpg", }, { id: shortId.generate(), src: "https://loremflickr.com/cache/resized/65535_52905479084_303bf25ec0_320_240_nofilter.jpg", }, ], Comments: [ { id: shortId.generate(), User: { nickname: "찜찜", }, content: "얼른 사고싶어요~", }, { id: shortId.generate(), User: { nickname: "hero", }, content: "리액트 넥스트 고수가 될테다~", }, ], createdAt: {}, }, ], imagePaths: [], addPostLoading: false, addPostDone: false, addPostError: null, addCommentLoading: false, addCommentDone: false, addCommentError: null, }; const dummyPost = ({ id, content }) => { return { id, content, User: { id: "1", nickname: "WlaWla", }, Images: [], Comments: [], }; }; const dummyComment = (content) => ({ id: shortId.generate(), content: content, User: { id: "1", nickname: "WlaWla", }, }); const postSlice = createSlice({ name: "post", initialState, reducers: { addPostRequestAction: (state, action) => { state.addPostLoading = true; state.addPostDone = false; state.addPostError = null; }, addPostSuccessAction: (state, action) => { state.addPostLoading = false; state.addPostDone = true; state.mainPosts.unshift(dummyPost(action.payload)); }, addPostFailureAction: (state, action) => { state.addPostLoading = false; state.addPostError = action.error; }, addCommentRequestAction: (state, action) => { state.addCommentLoading = true; state.addCommentDone = false; state.addCommentError = null; }, addCommentSuccessAction: (state, action) => { const { content, userId, postId } = action.payload; const post = state.mainPosts.find((d) => d.id === postId); post.Comments.unshift(dummyComment(content)); state.addCommentLoading = false; state.addCommentDone = true; }, addCommentFailureAction: (state, action) => { state.addCommentLoading = false; state.addCommentError = action.error; }, }, extraReducers: (builder) => builder .addCase(HYDRATE, (state, action) => ({ ...state, ...action.payload.post, })) .addDefaultCase((state) => state), }); export const { addPostRequestAction, addPostSuccessAction, addPostFailureAction, addCommentRequestAction, addCommentSuccessAction, addCommentFailureAction } = postSlice.actions; export default postSlice.reducer; 사가 코드입니다. import { all, fork, delay, put, takeLatest } from "redux-saga/effects"; import axios from "axios"; import { addPostRequestAction, addPostSuccessAction, addPostFailureAction, addCommentRequestAction, addCommentSuccessAction, addCommentFailureAction } from "../reducers/post"; import { addPostToMe, removePostOfMe } from "../reducers/user"; import shortid from "shortid"; function addPostAPI(data) { return axios.post("/api/post/", data); } function* addPost(action) { try { // const result = yield call(addPostAPI, action.data); console.log("addPost saga", action); yield delay(1000); const id = shortid.generate(); yield put( addPostSuccessAction({ id, content: action.payload.text, }) ); yield put({ type: addPostToMe, payload: id }); } catch (err) { yield put({ type: addPostFailureAction, error: err.response.data }); } } function addCommentApi(data) { return axios.post(`/api/post/${data.postId}/comment`); } function* addComment(action) { try { // const result = yield call(addPostAPI, action.data); console.log("addComment saga", action); yield delay(1000); yield put({ type: addCommentSuccessAction, payload: action.payload, }); } catch (err) { console.log(err); yield put({ type: addCommentFailureAction, error: err.response.data, }); } } function* watchAddPost() { yield takeLatest(addPostRequestAction, addPost); } function* watchAddComment() { yield takeLatest(addCommentRequestAction, addComment); } export default function* postSaga() { yield all([fork(watchAddPost), fork(watchAddComment)]); }
react redux node.js express next.js
챠챠_
2024-04-29T13:56:33.262Z
댓글 2
좋아요 0
조회수 255
해결됨
Next + React Query로 SNS 서비스 만들기
안녕하세요 제로초님, 특정인 정보 api(api/users/{id}) response 관련 질문이 있습니다. response에 Followers 배열이 있어 해당 유저를 팔로우 한 다른 사용자들을 얻고자 했습니다. 처음 시도 는 강의에서 진행했던대로 prefetchQuery + useQuery 조합 으로 데이터를 끌어오고자 했습니다. 하지만 이 경우에 Followers 배열이 빠진 상태로 응답이 돌아오고 있습니다. 한 100번 새로고침하면 1~2번만 붙어서 옵니다. 아래는 prefetchQuery + useQuery 조합 코드입니다. // page.tsx import Link from "next/link"; import { QueryClient, HydrationBoundary, dehydrate } from "@tanstack/react-query"; import getUserInfo from "./_lib/getUserInfo"; import getUserPosts from "./_lib/getUserPosts"; import Nav from "./_component/Nav"; import ProfileUserData from "./_component/ProfileUserData"; import UserPosts from "./_component/UserPosts"; import { Container, Userzone, Profile, HeaderPhotoZone } from "./page-style"; type Props = { params: { username: string }; }; export default async function Username({ params }: Props) { const { username } = params; console.log("username : ", username); const queryClient = new QueryClient(); await queryClient.prefetchQuery({ queryKey: ["user", username], queryFn: getUserInfo, }); await queryClient.prefetchQuery({ queryKey: ["posts", "user", username], queryFn: getUserPosts, }); return ( <Container> <HydrationBoundary state={dehydrate(queryClient)}> <Nav username={username} /> <Userzone> <Profile> <HeaderPhotoZone> <Link href="/home">{/* <Image src={이미지} alt="header_photo"></Image> */}</Link> </HeaderPhotoZone> <ProfileUserData username={username} /> </Profile> <UserPosts username={username} /> </Userzone> </HydrationBoundary> </Container> ); } //Nav.tsx "use client"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import getUserInfo from "../_lib/getUserInfo"; import BackBtn from "../../_component/BackBtn"; import { Navigation } from "./style"; import { User } from "@/model/User"; type Prop = { username: string; }; export default function Nav({ username }: Prop) { const { data } = useQuery<User, Object, User, [_1: string, _2: string]>({ queryKey: ["user", username], queryFn: getUserInfo }); console.log("네비게이션 유저 데이터 : ", data); return ( <Navigation> <BackBtn></BackBtn> {data === undefined ? ( <div>프로필</div> ) : ( <div> <div>{data?.nickname}</div> <div>0 게시물</div> </div> )} </Navigation> ); } //ProfileUserData.tsx "use client"; import { useQuery, useQueryClient } from "@tanstack/react-query"; import Link from "next/link"; import { useSession } from "next-auth/react"; import Tab from "./Tab"; import FollowButton from "../../_component/FollowButton"; import { ProfileUserdataMid, UserName, SignupDate, AboutFollower, ProfileUserdata, NoAccountId, NoAccountMsg, ProfileUserdataTop, AbsoluteProfileContainer } from "./style"; import { User } from "@/model/User"; import getUserInfo from "../_lib/getUserInfo"; type Prop = { username: string; }; export default function ProfileUserData({ username }: Prop) { const { data: session } = useSession(); const { data } = useQuery<User, Object, User, [_1: string, _2: string]>({ queryKey: ["user", username], queryFn: getUserInfo }); console.log("프로필 유저 데이터 : ", data); // const createdDate = new Date(data?.createdAt!); if (data === undefined) { return ( <> <NoAccountId>@{username}</NoAccountId> <NoAccountMsg>계정이 존재하지 않음</NoAccountMsg> </> ); } // return null; // 팔로우, 팔로잉 데이터 추가 필요 return ( <ProfileUserdata> <ProfileUserdataTop> <AbsoluteProfileContainer> <div>아 몰랑</div> </AbsoluteProfileContainer> {/* 팔로우 버튼 확인 */} {/* <Link href="/settings/profile">프로필 수정</Link> */} {/* {session?.user?.email === data?.id ? <Link href="/settings/profile">프로필 수정</Link> : <FollowButton user={data} />} */} </ProfileUserdataTop> <ProfileUserdataMid> <UserName> <div>{data?.nickname}</div> <div>@{data?.id}</div> </UserName> <SignupDate> <svg viewBox="0 0 24 24" aria-hidden="true" height="1.25rem"> <g> <path d="M7 4V3h2v1h6V3h2v1h1.5C19.89 4 21 5.12 21 6.5v12c0 1.38-1.11 2.5-2.5 2.5h-13C4.12 21 3 19.88 3 18.5v-12C3 5.12 4.12 4 5.5 4H7zm0 2H5.5c-.27 0-.5.22-.5.5v12c0 .28.23.5.5.5h13c.28 0 .5-.22.5-.5v-12c0-.28-.22-.5-.5-.5H17v1h-2V6H9v1H7V6zm0 6h2v-2H7v2zm0 4h2v-2H7v2zm4-4h2v-2h-2v2zm0 4h2v-2h-2v2zm4-4h2v-2h-2v2z"></path> </g> </svg> {/* <div>{`가입일 ${createdDate.getFullYear()}년 ${createdDate.getMonth() + 1}월`}</div> */} </SignupDate> <AboutFollower> <Link href="/follow"> <span>{data._count.Followings}</span> 팔로우 중 </Link> <Link href="/followers"> <span>{data._count.Followers}</span> 팔로워 </Link> </AboutFollower> <Tab></Tab> </ProfileUserdataMid> </ProfileUserdata> ); } react-query 결과 때문에 다른 방법으로 prefetchQuery를 사용하지 않고 useQuery만을 사용 해서 특정인 정보를 가져오는 시도를 했는데 이 경우에는 모두 Followers 배열이 같이 날아오더군요. 왜 이런 현상이 일어나는지 궁금해 질문 남깁니다. 아래는 useQuery만 사용한 코드는 page.tsx에 prefetchQuery만 빠진 것 이외에 다른 부분은 동일합니다. //page.tsx import Link from "next/link"; import { QueryClient, HydrationBoundary, dehydrate } from "@tanstack/react-query"; import getUserInfo from "./_lib/getUserInfo"; import getUserPosts from "./_lib/getUserPosts"; import Nav from "./_component/Nav"; import ProfileUserData from "./_component/ProfileUserData"; import UserPosts from "./_component/UserPosts"; import { Container, Userzone, Profile, HeaderPhotoZone } from "./page-style"; type Props = { params: { username: string }; }; export default async function Username({ params }: Props) { const { username } = params; console.log("username : ", username); const queryClient = new QueryClient(); // await queryClient.prefetchQuery({ // queryKey: ["user", username], // queryFn: getUserInfo, // }); await queryClient.prefetchQuery({ queryKey: ["posts", "user", username], queryFn: getUserPosts, }); // 개인 사용자 데이터 가져오는 것으로 수정해ㅑ함 // 이거 서버 컴포넌트인데 Nav 같은거는 client란 말이야 그래서 깜박거리는데 어카지; return ( <Container> <HydrationBoundary state={dehydrate(queryClient)}> <Nav username={username} /> <Userzone> <Profile> <HeaderPhotoZone> <Link href="/home">{/* <Image src={이미지} alt="header_photo"></Image> */}</Link> </HeaderPhotoZone> <ProfileUserData username={username} /> </Profile> <UserPosts username={username} /> </Userzone> </HydrationBoundary> </Container> ); } react - query 결과 useQuery만 사용했을 때의 네트워크 탭 getUserInfo.tsx 는 다음과 같습니다. import { QueryFunction } from "@tanstack/query-core"; import { User } from "@/model/User"; const getUserInfo: QueryFunction<User, [_1: string, _2: string]> = async ({ queryKey }) => { const [_1, username] = queryKey; const response = await fetch(`${process.env.NEXT_PUBLIC_BASE_URL}/api/users/${username}`, { credentials: "include", }); if (response.ok) return response.json(); }; export default getUserInfo;
react next.js react-query next-auth
김지환
2024-04-29T13:52:32.635Z
댓글 1
좋아요 0
조회수 229
미해결
[리뉴얼] React로 NodeBird SNS 만들기
제로쵸 님의 강의를 여러개 듣고 있는 코딩 입문자입니다 ㅜ 간단한 사진첩 클릭 사이트를 만들었는데요. 스샷처럼 한쪽 사진만 계속 선택 했을 때는 함수가 한번만 실행되며 제가 원하는 아웃풋이 나오는데, 다른 사진을 선택하면 함수가 여러번 실행이 되네요... 왜이러는걸까요? ㅜㅜ 소스는 html+js+부트스트랩 로 짰습니다. 원본소스의 링크는 아래 올려놨습니다. https://drive.google.com/file/d/1Ov0Qik9ofDHli-TsblLw5OkUz7uCXTDo/view?usp=drive_link
react redux node.js express next.js
오르골
2024-04-29T05:57:16.163Z
댓글 1
좋아요 0
조회수 200
미해결
Next + React Query로 SNS 서비스 만들기
패러렐 라우트 강의 중 폴더 이동하는 부분이 있는데 i/flow/signup 페이지가 notFound로 나옵니다 http://localhost:3000/ 경로에서도 해당 페이지 ui 가 나오지 않는데 어떤 문제일까요
react next.js react-query next-auth msw
mjoh
2024-04-29T04:26:13.588Z
댓글 1
좋아요 0
조회수 244