inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

172만명의 커뮤니티!! 함께 토론해봐요.

로그아웃 시 메서드 거절이 발생합니다.

미해결

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)

auth LoginView/LogoutView에 success_url_allowed_hosts 설정 추가하여, 로그인/로그아웃 후에 지정 호스트로의 이동 허용 현재 로그인/로그아웃후 지정 호스트로 이동을 허용하는 부분을 실습하고 있는데 막히는부분이 있어서 질문 드립니다. 이부분 코드를 붙여넣고 실행하였더니 로그아웃 부분에서 아래와 같은 에러가 발생하였습니다. (프로필 페이지로 이동은 잘 됩니다.) 찾아보니 GET 메서드가 거절된 것같은데, 이전 강의에서 장고에서 과거에는 GET으로 받았으나, 이제는 POST 요청만 허용한다는 내용을 들은적이 있었던것같은데, 그것과 관련된 것인지 궁금합니다. 다른 분들은 잘되셔서 넘어가셨을텐데, 저가 잘못된것 같긴한데 혹시나해서 여쭈어봅니다. 아래는 로그아웃 구현된 부분입니다.

  • react
  • python
  • django
  • web-api
  • htmx
백종성 댓글 2 좋아요 0 조회수 147

11-15) 프로필 수정에서 이미지 저장 시 문제

해결됨

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)

질문을 온전히 이해할 수 있도록, 모든 맥락을 전달해주세요. 질문은 질문자가 번거로워야 보다 좋은 답변을 얻으실 수 있습니다. 시행착오를 알려주시면 곧바로 원하는 문제에 집중할 수 있습니다. 오류 메시지는 일부만 알려주시기보다 전체 오류 메시지를 캡처해서 주시면, 오류 파악에 도움이 됩니다. 당신의 파이썬/장고 페이스메이커가 되겠습니다. ;-) 인프런 서비스 운영 관련 문의는 1:1 문의하기를 이용해주세요. 11-15 강의에서 구현한 프로필 수정 폼에서 이미지를 올린 경우, 다시 프로필 수정 페이지에 들어가면 정상적으로 이전에 등록된 이미지가 현재 란에 보여집니다. 이렇게 구현된 모델은 문제가 몇 가지 있는데요. 수정하지 않고 저장 을 누를 경우 이전 강의에서 교육하신 내용처럼 접미사가 계속 바뀌어가면서 같은 내용의 파일이 spamming 되는 문제가 발생합니다. 우리가 만약 프로필에 다른 항목이 추가된다면, 다른 항목만 수정하지 않고 나가는 유저가 있을텐데 해당 문제를 해결하려면 어떻게 해야할까요? 수정 혹은 취소 체크 박스를 선택하여 삭제를 할 경우 여전히 경로 안에 파일이 남아 있습니다. signal을 이용하면 될 것 같은데, 하기와 같은 방법을 생각해 볼 수 있을까요? @receiver(pre_save, sender=Profile) def edit_delete_on_profile(instance=Profile, **kwargs): instance.avatar.delete(save=False) 수업 내용과는 상관없지만, 기본 제공되는 이미지 업로드 양식이 어색합니다. 특히 취소 체크 박스를 체크하여 제거하는 방식은 너무 어색한데요. 더 좋은게 없을까요? 예를들어 아래는 네이버 '치지직' 에서 프로필 수정 양식입니다.

  • react
  • python
  • django
  • web-api
  • htmx
pplkjh2 댓글 3 좋아요 0 조회수 241

그래프큐엘 패치보드 질문

해결됨

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

포트폴리오 과제중 BoardDetail 작성글 페이지에서 패치보드가 안불러와져서 계속 코드 고쳐보다가 결국 강사님이 올려주시는 포트폴리오리뷰 파일 불러와서 코드보고 똑같이 따라쳐도 제 파일에서만 패치보드가 안불러와져서 오류가 계속나네요.. 혹시 좀 봐주실수 있을까요?(_app.js에서 아폴로 주소 확인도 했습니다) 아래는 패치보드 로드 실패로 나오는 창입니다

  • react
  • node.js
  • seo
  • graphql
  • next.js
cyh1908 댓글 1 좋아요 0 조회수 157

fetch 함수에 searchParams.toString() 사용 관련

미해결

Next + React Query로 SNS 서비스 만들기

export const getSearchResult : QueryFunction<Post[], [_1 : string, _2 : string, searchParams : {q : string, pf? : string, f? : string> = async ({queryKey}) =>{ const res = await fetch(` http://localhost:9090/api/search/$ {searchParams.toString()? ${searchParams.toString()}` 여기서 searchParams는 객체 타입인데 toString() 처리가 가능한지 궁금합니다.

  • react
  • next.js
  • react-query
  • next-auth
  • msw
그린티라떼 댓글 1 좋아요 0 조회수 188

2.1 프로젝트 설치 alias 부분

해결됨

한 입 크기로 잘라먹는 Next.js

이 부분 진행할 때 "default alias를 쓸 거냐? No" 라고 말씀해 주셨는데 반대로 말씀해 주신 거 같아요! default alias를 쓴다는 선택이니까요. default import alias 대신 custmize으로 쓰겠냐는 질문에 No라고 선택한 걸로 보입니다!

  • react
  • typescript
  • next.js
주니어에요 댓글 2 좋아요 0 조회수 290

댓글 비밀번호 입력 오류

해결됨

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

안녕하세요, 댓글 삭제 기능을 구현하던 도중 Modal에서 입력받은 비밀번호가 제가 댓글을 생성할 때 입력했던 비밀번호와 동일함에도 비밀번호가 틀렸다는 에러 메시지가 나옵니다. 제가 작성한 코드에서 어떠한 오류가 있는 건지 가르쳐주시면 감사하겠습니다... BoardComment Container import { useState } from "react"; import { useRouter } from "next/router"; import { useMutation, useQuery } from "@apollo/client"; import BoardCommentsUI from "./BoardComments.presenter"; import { FETCH_BOARD, CREATE_BOARD_COMMENT, FETCH_BOARD_COMMENTS, DELETE_BOARD_COMMENT, } from "./BoardComments.queries"; import { MouseEvent, ChangeEvent, MouseEventHandler } from "react"; import { IMutation, IMutationCreateBoardCommentArgs, IMutationDeleteBoardCommentArgs, IQuery, IQueryFetchBoardArgs, IQueryFetchBoardCommentsArgs, } from "../../../../commons/types/generated/types"; export default function BoardComments() { const [writer, setWriter] = useState(""); const [password, setPassword] = useState(""); const [contents, setContents] = useState(""); const [rating, setRating] = useState(0); const [user, setUser] = useState(""); const [boardCommentId, setBoardCommentId] = useState(""); const [modalPassword, setModalPassword] = useState(""); const [contentLength, setContentLength] = useState(0); const [isOpen, setIsOpen] = useState(false); const router = useRouter(); if (typeof router.query.boardId !== "string") { router.query.boardId = Array.isArray(router.query.boardId) ? router.query.boardId[0] : String(router.query.boardId); } const { data } = useQuery<Pick<IQuery, "fetchBoard">, IQueryFetchBoardArgs>( FETCH_BOARD, { variables: { boardId: router.query.boardId, }, } ); const { data: commentData, refetch } = useQuery< Pick<IQuery, "fetchBoardComments">, IQueryFetchBoardCommentsArgs >(FETCH_BOARD_COMMENTS, { variables: { boardId: router.query.boardId, }, }); const [createBoardComment] = useMutation< Pick<IMutation, "createBoardComment">, IMutationCreateBoardCommentArgs >(CREATE_BOARD_COMMENT); const [deleteBoardComment] = useMutation< Pick<IMutation, "deleteBoardComment">, IMutationDeleteBoardCommentArgs >(DELETE_BOARD_COMMENT); const onChangeWriter = (event: ChangeEvent<HTMLInputElement>) => { setWriter(event.target.value); }; const onChangePassword = (event: ChangeEvent<HTMLInputElement>) => { setPassword(event.target.value); }; const onChangeContents = (event: ChangeEvent<HTMLTextAreaElement>) => { setContents(event.target.value); setContentLength(event.target.value.length); }; const onChangeRating = (value: number) => { setRating(value); }; const onChangeUser = (event: ChangeEvent<HTMLInputElement>) => { setUser(event.target.value); }; const onChangeModalPassword = (event: ChangeEvent<HTMLInputElement>) => { setModalPassword(event.target.value); }; const showModal = (event: MouseEvent<HTMLImageElement>): void => { setBoardCommentId(event.currentTarget.id); setIsOpen(true); console.log(boardCommentId); }; const handelOk = (): void => { setIsOpen(false); }; const handelCancel = (): void => { setIsOpen(false); }; const onClickSubmitComment: MouseEventHandler< HTMLButtonElement > = async () => { try { if (typeof router.query.boardId !== "string") { return; } await createBoardComment({ variables: { boardId: router.query.boardId, createBoardCommentInput: { writer, password, contents, rating, }, }, }); refetch(); } catch (error) { console.log(error.message); } setRating(0); setWriter(""); setPassword(""); setContents(""); }; const onClickDeleteComment = async ( event: MouseEvent<HTMLButtonElement> ): Promise<void> => { try { await deleteBoardComment({ variables: { boardCommentId, password: modalPassword, }, }); refetch(); } catch (error) { alert(error.message); } setIsOpen(false); setModalPassword(""); }; return ( <BoardCommentsUI data={data} commentData={commentData} writer={writer} password={password} contents={contents} modalPassword={modalPassword} contentLength={contentLength} rating={rating} user={user} isOpen={isOpen} onChangeWriter={onChangeWriter} onChangePassword={onChangePassword} onChangeRating={onChangeRating} onChangeContents={onChangeContents} onChangeUser={onChangeUser} onChangeModalPassword={onChangeModalPassword} onClickSubmitComment={onClickSubmitComment} onClickDeleteComment={onClickDeleteComment} showModal={showModal} handelOk={handelOk} handelCancel={handelCancel} /> ); } BoardComment Presenter import * as S from "./BoardComments.styles"; import { IBoardCommentsUIProps } from "./BoardComments.types"; import { Rate } from "antd"; export default function BoardCommentsUI(props: IBoardCommentsUIProps) { return ( <S.Container> <S.PasswordCheck open={props.isOpen} onOk={props.onClickDeleteComment} onCancel={props.handelCancel} > 비밀번호 입력:{" "} <input type="text" onChange={props.onChangeModalPassword} /> </S.PasswordCheck> <S.CommentTitleWrapper> <S.CommentIcon src="/icon/rate_review.png" /> 댓글 </S.CommentTitleWrapper> <S.CommentInputWrapper> <S.CommentInputWrapperHeader> <S.CommentWriter type="text" placeholder="작성자" onChange={props.onChangeWriter} value={props.writer} /> <S.CommentPassword type="password" placeholder="비밀번호" onChange={props.onChangePassword} value={props.password} /> <Rate onChange={props.onChangeRating} value={props.rating} /> </S.CommentInputWrapperHeader> <S.CommentInputWrapperBody> <S.CommentInputWrapperBottom placeholder="개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다." onChange={props.onChangeContents} maxLength={99} value={props.contents} /> <S.CommentTextCount>{props.contentLength}/100</S.CommentTextCount> <S.CommentSubmitButton onClick={props.onClickSubmitComment}> 등록하기 </S.CommentSubmitButton> </S.CommentInputWrapperBody> </S.CommentInputWrapper> <S.CommentListWrapper> {props.commentData?.fetchBoardComments.map((el) => ( <S.CommentListItemWrapper key={el._id}> <S.CommentListProfileWrapper> <S.CommentListProfileImage src="/icon/profile.png" /> </S.CommentListProfileWrapper> <S.CommentListContentsWrapper> <S.CommentListContentsHeader> <S.CommentListWriter>{el.writer}</S.CommentListWriter> <Rate disabled defaultValue={el.rating} /> </S.CommentListContentsHeader> <S.CommentListContents>{el.contents}</S.CommentListContents> <S.CommentListDate>2024-07-27</S.CommentListDate> </S.CommentListContentsWrapper> <S.CommentListItemButtonWrapper> <S.CommentListItemButton src="/icon/mode.png" //onClick={() => props.onClickDeleteComment(el._id)} /> <S.CommentListItemButton src="/icon/clear.png" //onClick={() => props.onClickDeleteComment(el._id)} id={el._id} onClick={props.showModal} /> </S.CommentListItemButtonWrapper> </S.CommentListItemWrapper> ))} </S.CommentListWrapper> </S.Container> ); }

  • react
  • node.js
  • seo
  • graphql
  • next.js
Levi 댓글 2 좋아요 0 조회수 188

이 강의는 Next.js 어떤 버전으로 진행되나요?

해결됨

한 입 크기로 잘라먹는 Next.js

일단 결제하고 미리보기인 첫번째 영상도 봤는데 페이지 라우터 다루다가 앱 라우터로 들어간다는 것까진 확인이 되었습니다. 그래도 버전은 제대로 알고 강의 듣고 싶어서 이렇게 질문 남깁니다!

  • react
  • typescript
  • next.js
HyeJung 댓글 1 좋아요 0 조회수 230

리액트 dockderfile 작성 시 COPY 질문

미해결

따라하며 배우는 리액트 A-Z[19버전 반영]

따라하며 배우는 리액트 A-Z 강의 중 리액트를 위한 도커 파일 작성하기 강의 중 궁금한 것이 있어 질문 드립니다 COPY 부분에 package.json 파일을 복사를 하는데 package-lock.json 파일은 왜 복사를 하지 않나요? package-lock.json 파일이 더 버전 명시가 확실히 되어있어 안전하지 않나요?

  • react
  • redux
  • tdd
  • typescript
  • next.js
  • 소프트웨어-테스트
mun9927 댓글 1 좋아요 0 조회수 161

가상환경 활성화 했을때 이름 설정

미해결

파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)

원래는 강의에서처럼 터미널에서 (venv)가 있어야 할 자리에 mydjango가 있었습니다 그런데 제가 로컬에서 다른 가상환경을 만들고 진행하니 이제 모든 파이참 환경에서 가상환경 설정할 때마다(venv)라고 활성화 되서 나오네요 얼마전엔 가상환경이름을 venv라고 설정해도 각각에 프로젝트에 맞는 이름들이 (django) 이런식으로 등장했는데 어떻게 원래대로 되돌릴 수 있는지 모르겠습니다. 프로그램 실행에 지장이 있는건 아니지만 알려주시면 감사하겠습니다.

  • react
  • python
  • django
  • web-api
  • htmx
신정환 댓글 1 좋아요 0 조회수 143

강의 자료 링크가 어딨는지 모르겠습니다

해결됨

한 입 크기로 잘라먹는 Next.js

예제 코드 및 강의 자료 안내 탭에서 강의 자료 확인하기에서 강의 자료가 어딨는지 모르겠네요 파비콘 및 썸네일 파일 링크만 보이고 pdf는 링크가 따로 안보입니다

  • react
  • typescript
  • next.js
eko09 댓글 2 좋아요 0 조회수 459

패레럴 라우트와 인터셉터 라우트를 공부하다 생긴 의문점입니다.

미해결

Next + React Query로 SNS 서비스 만들기

안녕하세요 제로초님 강의를 듣다 의문점이 하나 생겨 질문드립니다. 패레럴 라우트와 인터셉터 라우트를 사용해서 모달을 띄우는 방법을 알려주셨는데 기존의 react에서 사용하던 방식으로 모달의 띄우는게 더 코드도 단순하고 간단하게 구현할 수 있을것 같은데 nextjs에서는 페레럴 라우트와 인터셉터 라우트를 사용해서 모달을 구현하는게 어떤 이점이 있는지 궁금합니다. 기존의 모달을 띄우는 방법은 여러가지가 있지만 state를 통해서 구현하거나 queryString을 사용해서 구현할 수 있을것 같습니다. queryString을 사용하면 뒤로가기 버튼클릭시 모달을 띄우기전 url로도 이동할 수 있고 새로고침을 해도 모달과 뒤의 배경을 같이 보여줄 수 있을 것 같습니다. 혼자서 생각도 해보고 인터넷에서 자료도 찾아봤지만 정확한 이유를 잘 모르겠어서 질문드립니다. 오늘도 좋은 하루 되셨으면 좋겠습니다. 감사합니다.

  • react
  • next.js
  • react-query
  • next-auth
  • msw
tsg 댓글 2 좋아요 0 조회수 403

인터셉팅 라우트

미해결

Next + React Query로 SNS 서비스 만들기

인터셉팅 라우트의 본 목적은 아닌 것 같으나 제 생각으론 가능하지 않을까 하는 생각이 드는데 진짜 가능한 건지 궁금해서 여쭤봅니다,,ㅠㅠ 인터셉팅 시에 모달이 뜨면서 children이 변경되도록 하고 싶은데,,, 가능한 건가요,,? 그러면 폴더 경로를 어떻게 설정 해야 할까요,,?

  • react
  • next.js
  • react-query
  • next-auth
  • msw
댓글 1 좋아요 0 조회수 209

서버 컴포넌트 렌더링 질문

미해결

Next + React Query로 SNS 서비스 만들기

안녕하세요 선생님. "Suspense로 Streaming하여 최적화하기(feat. loading.tsx, error.tsx)" 강의 내용중에 궁금한점이 있어 질문드립니다. 강의에서 5:42 ~ 6:35 시간 구간에서의 내용에 관해서 이해가 잘 안되는 부분이 있는데요. 홈 화면에 처음 들어올 때에는 로딩스피너가 안보이고 탐색하기 등 다른 페이지에서 홈 화면으로 들어오면 로딩스피너가 보이는 이유를 설명해주시는 부분입니다. 홈 화면에 처음 들어왔을 때에는 홈 화면에 해당하는 page.tsx를 서버에서 다 그려주기 때문에 로딩 상태가 없어서 로딩스피너가 안보이고, explore에 있다가 클라이언트에서 홈으로 넘어갈 때에는 explore에서 홈 페이지를 새로 로딩을 하기 때문에 로딩 스피너가 뜨는거라고 설명해주셨는데요. "explore에서 홈 페이지를 새로 로딩을 한다" 라는게 무슨 말인지 잘 모르겠습니다 ㅠ page.tsx가 CSR이 된다는 것인가요? 저는 어떤 페이지에 들어오면 그 페이지에 해당하는 page.tsx가 실행되는걸로 알고 있었는데 아닌가요? 홈의 page.tsx는 서버 컴포넌트인데 왜 홈에 처음 들어왔을 때만 page.tsx가 서버에서 실행되고 그 이후에는 마치 클라이언트에서 데이터 패칭하고 그에 따라 렌더링이 되는것처럼 "로딩"이라는 상태가 존재하는것인지가 궁금합니다.

  • next.js
  • react
jojeon4515 댓글 1 좋아요 0 조회수 103

Refresh Token 만료시 로그아웃 및 페이지 이동 처리

미해결

코드로 배우는 React 19 with 스프링부트 API서버

Refresh Token마저 만료되었을때 Todo 또는 Product 메뉴를 누르면 자동으로 로그아웃 및 메인페이지로 이동하려고 합니다. 강의 내용대로 쿠키 member를 삭제하여 로그아웃 처리는 하였으나 '/' Path로 이동은 안되어서 방법을 찾지 못하여 질문드립니다. 추가로 토큰만료시 jwtUtil의 beforeRes에서 쿠키를 삭제하였으나 todo 페이지가 호출 및 페이지 이동이 안되어서 todo 페이지 나오기전에 페이지 이동을 하고싶습니다. ListComponent의 useEffect에 hook을 사용했으나 실제로 이동안 되고 jwtUtil, todoAPI 는 모두 규칙 위반으로 hook이나 navigate를 사용할수 없더라구요. 어떻게 해야할까요..

  • react
  • spring-boot
  • jpa
  • jwt
  • redux-toolkit
ghoonpark 댓글 1 좋아요 0 조회수 449

2022 개정판

미해결

생활코딩 - React

유튜브에 2022버전 개정판이 나와있던데 이걸보는게 나을까요?

  • react
공부하자제발 댓글 1 좋아요 0 조회수 368

section04

해결됨

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

어제는 잘됬는데 오늘 다시 해보니까 계속 오류가 생겨서 무슨 문제일까요? 서버에서도 에러가 뜨고 어제는 잘됬는데요 어제는 오류 안떳는데 오늘은 뜨고요 이거 다운받아야 할까요? 네트워크는 잘 작동을 하는데요. 페이로드랑 응답에는 에러가 뜨네요. 어제는 분명이 됬는데 오늘 이러니까 이유를 모르겠어요 ㅠ 다른 섹션도요

  • react
  • node.js
  • seo
  • graphql
  • next.js
imhj11777 댓글 3 좋아요 0 조회수 228

useNavigate()을 검증할 때 이해가 안되는 부분이 있습니다.

미해결

실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트

const navigateFn = vi.fn(); vi.mock('react-router-dom', async () => { const original = await vi.importActual('react-router-dom'); return { ...original, useNavigate: () => navigateFn }; }); useNavigate 함수에 스파이 함수를 전달할때 위 코드를 사용하고 있는데요. 이부분에서 이해가 어려운게 있습니다. //ErrorPage.jsx const navigate = useNavigate(); const handleClickBackButton = () => { navigate(-1); }; 실제로 네비게이션에 활용하는 함수는 navigate() 잖아요. 그런데 왜 스파이 함수를 useNavigate()에 전달하는 건가요? 직관적으로 보자면, expect(navigate함수에 전달된 spyFn).toHaveBeenNthCalledWith(1, -1) 이여야 할 거 같다고 느껴져서 이해가 안갑니다.

  • javascript
  • react
  • 소프트웨어-테스트
  • vitest
박상원 댓글 2 좋아요 0 조회수 263

snackbar를 createportal를 썻을 때 갯수 조절이 가능한가요?

해결됨

[React / VanillaJS] UI 요소 직접 만들기 Part 2

context를 썻을때는 data length로 체크하면 최대 5개가 넘지 않게 더이상 오픈되지 않거나 가장 밑에 스낵바를 닫아 버린다던가 쉽게 구현을 가능할 것 같은데 portal를 쓰면 컨트롤이 가능한가? 궁금합니다

  • react
  • typescript
  • dom
  • ui
  • vanilla-js
징니 댓글 1 좋아요 0 조회수 207

toHaveStyle 메서드 사용이 조금 이상한 것 같습니다.

미해결

실무에 바로 적용하는 프런트엔드 테스트 - 1부. 테스트 기초: 단위・통합 테스트

it('focus가 활성화되면 border 스타일이 추가된다.', async () => { const { user } = await render(<TextField />); const textInput = screen.getByPlaceholderText('텍스트를 입력해 주세요.'); //await user.click(textInput); expect(textInput).toHaveStyle({ borderWidth: 'px', borderColor: 'rbg(25,a118,210)', }); }); (1) user.click (textInput)을 주석 처리 했습니다. 그리고 (2) toHaveStyle 부분에서, borderWidth, borderColor 두 값을 위와 같이 넣었는데도 테스트가 아래처럼 통과합니다. 수업 노트에 적혀진 이슈 ( 링크 )의 내용대로 "1px"이라고 작성하면 test가 fail이 됩니다. 혹시 제가 잘 못 이해한 부분이 있는걸까요?

  • javascript
  • react
  • 소프트웨어-테스트
  • vitest
박상원 댓글 2 좋아요 0 조회수 218

로그인 / 로그아웃 시 이전의 data가 남아있습니다.

해결됨

[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스

import React, { useState, MouseEvent } from "react"; import * as S from "./mypoint.index.styles"; import TapPointLoading from "./mypoint_loading"; import TapPointBuying from "./mypoint_buying"; import TapPointAll from "./mypoint_all"; import TapPointSelling from "./mypoint_selling"; export default function MyPoint(): JSX.Element { const [selectedValue, setSelectedValue] = useState<{ name: string; index: number; }>({ name: "전체내역", index: 0, }); const MyPageHeadInfoButton = [ { name: "전체내역", component: <TapPointAll /> }, { name: "충전내역", component: <TapPointLoading /> }, { name: "구매내역", component: <TapPointBuying /> }, { name: "판매내역", component: <TapPointSelling /> }, ]; const onClickTap = ( event: MouseEvent<HTMLDivElement>, index: number ): void => { const newValue = event.currentTarget.id; setSelectedValue({ name: newValue, index, }); }; // 버튼 클릭으로 해당 data 값을 보여주기 위함 const renderData = (): JSX.Element | undefined => { return ( <S.TableWrap> {/* 해당 탭의 배열의 객체 name통해 컴포넌트 가져옴 */} {MyPageHeadInfoButton.map((el) => { if (el.name === selectedValue.name && el.component) { return <div key={el.name}>{el.component}</div>; } return null; })} </S.TableWrap> ); }; return ( <S.Wrap> <S.MyPageHeadWrap> <S.MyPageHeadBtn> {/* 서브 탭 버튼 */} {MyPageHeadInfoButton.map((el, index) => ( <S.MyPageInfoBtn key={el.name} id={el.name} onClick={(event) => onClickTap(event, index)} selected={selectedValue.name === el.name} > {el.name} </S.MyPageInfoBtn> ))} </S.MyPageHeadBtn> </S.MyPageHeadWrap> <S.MyPageBodyWrap> {/* 해당 탭 data */} <div>{renderData()}</div> </S.MyPageBodyWrap> </S.Wrap> ); } 이렇게 탭을 클릭을 해서 해당 컴포넌트가 보이도록 했습니다. 그러면서 각각의 API data도 받아와 cache에 저장을 하도록 해 추가 API 요청이 일어나지 않도록 했는데 여기서 로그아웃을 하고 다른 아이디로 로그인을 하면 이전의 로그인 했던 data가 그대로 남아있어 최신 data를 가져오기 위해 여러가지 방법으로 시도했습니다. 로그아웃 시 useApolloClient를 활용해 cache를 삭제 했습니다. 이렇게 하면 다시 로그인 한 유저의 data를 잘 가져오는데 로그아웃을 하면서 cache data가 삭제되니 다른 API, Board, Markets 등 해당 page의 사용한 query문의 data를 다시 요청하는 문제가 있습니다. refetch()로 query문을 선언하면 해당 refetch()를 실행하지 않아도 API 요청이 일어나 refetchQueries를 사용해 data 최신화 하려는데 그렇게 되면 모든 탭을 refetch 해줘야 되는 문제가 있습니다. 각 탭 이동마다 API 요청 나가는게 싫어서 fetchporicy나 refetch()를 사용 하지 않았는데 보통 어떻게 사용을 하나요? 로그인에 의한 data는 탭 이동마다 refetch를 시켜주는게 좋을까요? 그리고 구매, 충전 등 하면 바로 MyPoint에 업데이트 되도록 client.writeQuery / readQeury 나 refetchQueries를 사용했는데 이런 결제 정보 같은거는 refetch로 실시간으로 data를 가져오는게 좋겠죠? 로그인, 로그아웃은 LayoutHeader에서 사용하고 있습니다.

  • react
  • node.js
  • seo
  • graphql
  • next.js
초무 댓글 2 좋아요 0 조회수 232

인기 태그

인프런 TOP Writers

주간 인기글