#localstorage

질문 2
해시태그 없이 키워드만 일치하는 질문은 개수에 포함되지 않아요.

6달 전 · ㅇㅅㅇ 님의 질문 업데이트

React Next infinite scroll

A 라는 infinite scroll페이지에서 500개 데이터를 보여주고 scroll은 70프로 내려왔다고 가정했을 때 다른 페이지 갔다가 돌아왔을 때 500개 데이터랑 scroll 위치 그대로 유지하는 좋은 방법 뭐 있을까요? localstorage나 context 이용했을때는 dom을 다시 랜더링하고 state 값을 다시 주입 했을 때 부드럽지 않은 느낌입니다. redux를 이용해서 전역으로 상태값을 저장해 놓고 컴포넌트에서 사용하면 될까요?

개발자

#react

#next.js

#redux

답변 0

댓글 0

조회 30

일 년 전 · 백승훈 님의 답변 업데이트

Recoil Atom Effect 적용 기: 팀 내 설득 및 구현 조언

안녕하세요!! 현재 진행 중인 프로젝트에서 회원가입 시 필요한 정보를 입력하는 중 새로고침 시 session 및 localstorage를 이용하여 상태유지를 하려고하는데 recoil과 관련하여 atom effect를 사용하면 우아하게 처리할 수 있음을 알았습니다. 따라서, 각 atom에 effect를 하나하나 추가하는 방법을 생각했는데 동일한 logic을 행하는 코드의 양이 방대해지고 localstorage에 각 atom에 해당하는 key-value로 저장되므로 가독성 측면에서 좋지 않다고 판단하여 아래와 같은 과정을 생각했습니다. 각 atom을 하나로 묶어 객체로 관리하자. 객체로 관리하게 되면 불필요한 re-rendering이 촉발되므로 객체로 선언한 atom의 각 property에 접근 및 수정을 위한 selector를 정의하자. 객체에 내의 property에 1대1로 selector를 정의하면 객체로 묶기 전 atom의 갯수만큼 selector를 선언해주어야 하므로 selectorFamily를 사용하자. 이것저것 찾아보면서 1 → 2 → 3 단계로 생각을 정리했습니다. 아래는 현재 사용되는 atom입니다. <ATOM> // signup.store.ts 👇 회원가입에 대한 user state들 - SignUpProfileTypeAtom - SignUpProfileRentalTypeAtom - SignUpProfileRegionsAtom - SignUpProfileDepositPriceAtom - SignUpProfileTermAtom - SignUpProfileMonthlyPriceAtom - SignUpProfileSmokingAtom - SignUpProfilePetAtom - SignUpProfileAppealsAtom - SignUpProfileGenderAtom - SignUpProfileMatesNumberAtom - SignUpProfileMateAppealsAtom // 👇 위의 atom들을 한 번에 access 및 update - SignUpProfileSelector 하지만, 다른 팀원이 저렇게 atom을 구성한 상황 제 생각을 그대로 적용하고자하면 팀원의 코드를 마음대로 바꾸는 거 같아서 조심스럽습니다. 협업함에 있어 설득도 하나의 중요한 스킬임을 갈수록 깨닫게 됩니다.(다들 어떻게 설득하시나요?) 팀원이 기존의 코드는 안 바꿨으면 좋겠다 하면 각 atom에 effect를 추가하는 것이 맞겠죠???? 현재 현업에 계신 분들은 이러한 상황에서 어떻게 설득하며 어떻게 하는 것이 좋을까 자문을 구하고 싶어서 글 올려봅니다!!🥲🥲 짧지 않은 글이지만 읽어주셔서 감사하고 많은 의견 주시면 감사하겠습니다!!😄😄😄 ```typescript import { SignUpType } from '@/types/signUp.type'; // ? type 집 유형 0: 원룸/오피스텔, 1: 빌라/연립, 2: 아파트, 3: 단독주택 @number export const SignUpProfileTypeAtom = atom<SignUpType['type']>({ key: 'signUpProfileTypeAtom', default: undefined, }); // ? rental_type 집 대여 유형 0: 월세, 1: 전세, 2: 반 전세 @number export const SignUpProfileRentalTypeAtom = atom<SignUpType['rental_type']>({ key: 'signUpProfileRentalTypeAtom', default: undefined, }); // ? regions 유저가 찾는 지역 >도시 (region) + 구(district) 형태의 배열 @string[] export const SignUpProfileRegionsAtom = atom<SignUpType['regions']>({ key: 'signUpProfileRegionsAtom', default: [], }); // ? deposit_price 보증금 (전세 혹은 월세) 범위 [최소 금액, 최대 금액] (0만원~10000만원) @[number, number] export const SignUpProfileDepositPriceAtom = atom<SignUpType['deposit_price']>({ key: 'signUpProfileDepositPriceAtom', default: [0, 10000], }); // ? term 유저가 살 기간 [최소기간, 최대 기간] (0 ~ 24)범위 @[number, number] export const SignUpProfileTermAtom = atom<SignUpType['term']>({ key: 'signUpProfileTermAtom', default: [0, 24], }); // ? monthly_rental_price 월세 [최소 금액, 최대 금액] (0만원, 500만원) @[number, number] export const SignUpProfileMonthlyPriceAtom = atom<SignUpType['monthly_price']>({ key: 'signUpProfileMonthlyPriceAtom', default: [0, 500], }); // ? smoking 흡연 여부 @boolean export const SignUpProfileSmokingAtom = atom<SignUpType['smoking']>({ key: 'signUpProfileSmokingAtom', default: undefined, }); // ? pet 펫 여부 0: 상관없음, 1: 좋음, 2: 싫음 @number export const SignUpProfilePetAtom = atom<SignUpType['pet']>({ key: 'signUpProfilePetAtom', default: undefined, }); // ? appeals 유저의 어필할 매력(배열형태) @string[] export const SignUpProfileAppealsAtom = atom<SignUpType['appeals']>({ key: 'signUpProfileAppealsAtom', default: [], }); // ? gender 상대방의 성별 0: 상관없음, 1: 남성, 2: 여성 @number export const SignUpProfileGenderAtom = atom<SignUpType['gender']>({ key: 'signUpProfileGenderAtom', default: undefined, }); // ? mates_number 인원수 0: 상관없음, 1: 1명, 2: 2명, 3: 3명이상 @number export const SignUpProfileMatesNumberAtom = atom<SignUpType['mates_number']>({ key: 'signUpProfileMateNumberAtom', default: undefined, }); // ? mate_appeals 유저가 원하는 상대방의 매력 (배열형태) @string[] export const SignUpProfileMateAppealsAtom = atom<SignUpType['mate_appeals']>({ key: 'signUpProfileMateAppealsAtom', default: [], }); ```

개발자

#프론트

#협업

#recoil

답변 1

댓글 0

조회 84

일 년 전 · 안희수 님의 답변 업데이트

NextJS 14에서 JWT를 쿠키를 통해 관리하려고 하는데 서버에서 set-cookie 해주는 방식말고 route 핸들러에서 주입할수는 없나요?

안녕하세요. 최근 NextJs를 공부하며 이전 리액트 기반의 사이드 프로젝트를 NextJs로 구현해보고 있습니다. 카카오 로그인만 지원을 하고 있고, 프론트 쪽에서 카카오 인가 코드를 백엔드로 넘기면 백에서 jwt를 발급해서 응답으로 access token과 refresh token을 프론트로 넘겨주고 있습니다. 이전 프로젝트에서는 두 토큰 모두 localStorage에 저장하는 방식으로 했었는데요, 이번에는 쿠키를 이용해보려고 하고 있습니다. 다만 백엔드에서 set-cookie를 해놓지 않아서 응답으로 받은 토큰을 따로 쿠키에 저장해야하는 상황입니다. 하지만 Server Component에서는 set cookie가 안되는 것으로 알고 있습니다. <목표 구현 방식> route handler를 통해서 백엔드 api를 호출하고 그 값을 쿠키에 저장하도록 코드를 짰습니다. (/app/api/token/route.ts) return 값은 확인을 위해서 임의로 넣었습니다. 그리고 쿠키에 저장된 토큰을 통해서 서버 컴포넌트에서 이를 이용해 백엔드 api 통신을 하고 싶습니다. 하지만 서버 컴포넌트에서 쿠키를 확인하니 비어있는 쿠키인 것을 알 수 있었습니다. 얕은 지식으로 생각을 했을때, (route handler - 브라우저 혹은 서버 컴포넌트)에서 생성한 쿠키는 (백엔드 도메인 - 브라우저 혹은 서버 컴포넌트) 통신에 사용되는 쿠키와 다르기 때문이라고 생각이 들었는데 해답을 찾지 못했습니다. <질문 사항> - 백엔드 서버에서 set-cookie를 하지 않고 직접 구현할 순 없을까요? 쿠키는 forwarding이 안되나요? - 제가 생각한 구조 말고 추천하시는 토큰 관리 방식에 대해서 알려주셔도 감사하겠습니다. 아직 초보 개발자에 글도 잘 쓰지 못해 이해하시기 힘들 것 같지만, 넓으신 아량으로 지식을 나눠주신다면 정말 큰 도움이 될 것 같습니다. 긴글 읽어주셔서 감사합니다 (_ _)

개발자

#next.js

#jwt

#react

#front-end

#cookie

답변 1

댓글 0

추천해요 1

조회 1,005

일 년 전 · 허니 님의 새로운 답변

리액트 로그인질문..

react + 파이어베이스만 써오다가 react + express 조합을 오랜만에 사용중인데 긴가민가한점이있어서 질문드립니다 ㅠㅠ import axios from 'axios'; const instance = axios.create({ baseURL: process.env.REACT_APP_API_BASE_URL, timeout: 2500, headers: { 'Content-Type': 'application/json', withCredential: true, }, }); instance.interceptors.request.use( (config) => { const token = localStorage.getItem('token'); if (token) { config.headers['Authorization'] = token; } else { delete config.headers['Authorization']; } return config; }, (error) => { return Promise.reject(error); } ); export default instance; 이렇게 인터셉터를주어서, 요청할 때마다 토큰을 전달하고있습니다. 그리고 프라이빗 라우터 + 유저정보 인증 훅을 사용해서 로그인사용자만 접근가능하게 페이지를 설정해줬습니다. 근데 질문 1. 네트워크탭 Request Headers 에서 Authorization을 확인해보면 토큰정보가 그대로 노출되고있는데요 원래 이렇게되나요? 질문 2. Bearer + token 이렇게 보내는 경우는 포스트맨이나 이런걸로 테스트할때만 Bearer 을 붙여서 보내주면될까요? 질문 3. 검색 키워드가 생각이안나서 질문으로 올립니다. 아주 옛날에는 (4년전) App.tsx에서 if(localstorage.token){ setAuthToekn(token); } 이런식으로 하고, setAuthToken함수는 import axios from 'axios'; const setAuthToken = (token) => { if (token) { axios.defaults.headers.common['x-auth-token'] = token; } else { delete axios.defaults.headers.common['x-auth-token']; } }; export default setAuthToken; 이런식으로 되어있었는데요, 요즘은 제가 짠 코드처럼 axios.인터셉터 식으로 하는게 맞나요? 질문 4. 그럼 요즘도 회원가입/로그인시 로컬스토리지에 유저 정보 (닉네임 이름 이메일, 토큰정보)만 저장해두고 로그인하면, 로그인버튼이 회원 닉네임으로 변하게 해준다던가.. 이런식으로 분기처리를 하나요? ( 저는 이렇게하고있어서요.. 로딩처리를 줄수도있겠지만 깜빡거리는게 싫고, 또 로컬스토리지로안하면 로그인버튼으로 잠깐바꼇다가 회원닉네임이 표시되더라구요) 질문5. (질문4와 이어집니다.) 만약 질문4처럼하면 사용자가 사이트에 계속 로그인중인데, 이 토큰이 끝났는지 판단하려는 코드를 따로 작성해줘야할까요? 예를들면, App.tsx에 서버 api/auth같은거에 요청보내는 로직을 작성해서, 토큰만보내서 유효한 토큰인지 아닌지, 유효하지않은토큰이면 에러를 리턴시켜준다던가, 리프레쉬토큰을 발급시켜서 연장시켜준다던가 이런식으로하면될까요? 마지막으로 질문이 좀 많고 중구난방인데 죄송스럽고 조심스럽네요..

개발자

#react

#login

#register

#local-storage

#jwt

답변 1

댓글 0

조회 107

일 년 전 · 박하민 님의 새로운 댓글

Next14 SSR 과정에서 Authorization에 쿠키를 사용해 토큰값을 전달하면 에러가 발생합니다..

안녕하세요. 혼자서 해결해 보려고 했지만, 오랜 시간 해결하지 못해 지푸라기라도 잡는 심정으로 질문 올려봅니다.. 기존에 localstorage를 사용해 fetch로 데이터를 요청했으나 SSR 과정에서 window 사용이 불가능하기 때문에 쿠키를 사용을 계획했습니다. 로그인 -> 쿠키에 토큰값 저장 -> 데이터 요청 시 쿠키에서 토큰 값을 꺼내고 헤더 Authorization에 담아 SSR에서도 사용하려고 했습니다. next에 내장되어있는 'next/headers'가 아닌 'cookies-next'를 사용하고 있습니다. <문제 상황> 처음에는 토큰 유효 기간이 지났다(토큰 값이 들어오지 않았다)는 에러가 발생하고 곧이어 데이터를 정상적으로 받아옵니다 (제 추측으로는 SSR 과정에서 토큰 값을 인식하지 못하고 에러가 발생하고 클라이언트 단에서는 쿠키 값을 정상적으로 반영해 데이터 페칭이 진행된 것 같습니다.) <질문> 1. Suspense를 적용하지 않을 경우 에러 없이 동작하지만 next streaming이 적용되지 않습니다.. 그리고 getCookie를 통해 가져온 값이 SSR 시 적용되지 않는 이유가 궁금합니다! 2. 현재 쿠키를 사용해 SSR 시 토큰 값을 전달하려는 방법이 최선의 방법이 맞는지 궁금합니다.

개발자

#next.js

#react

답변 1

댓글 9

조회 989

일 년 전 · 정 훈 님의 새로운 댓글

Localstorage에는 어떤데이터를 저장해야 좋을까요

Locacl Storage에 유저 정보와 post를 저장해도 될까요 Local storage는 보안상 취약한 부분이 있다고 해서 조금 불안해서 질문드립니다

개발자

#nextjs

#react

#web

#frontend

답변 2

댓글 2

조회 312

일 년 전 · 민호 님의 새로운 답변

Next.Js (App router) access token 저장위치 및 전달

Next.Js App router로 개발중입니다. fetch를 이용하여 요청을 보내는 로그인기능을 구현하였는데요. 로그인 성공시 서버로부터 내려받는 access token을 어디다 저장하는게 좋을까요? 다른 fetch 요청들의 header에 access token을 전달해주어야 하는데, 이걸 전달하려면 결국 전역저장하는 방법밖에 없지 않나요? axios를 사용하면 defaults.header로 해결할 수 있지만 Next.Js에서 fetch를 지향한다고 들어서 방법을 알고 싶습니다. ㅠㅠ server action을 사용하는 요청들도 있어서 localStorage같은 저장소에 저장하면 접근조차 안됩니다.

개발자

#next.js

#app-router

#jwt

#access-token

#저장

답변 2

댓글 4

추천해요 1

조회 2,191

일 년 전 · 최선재 님의 새로운 댓글

Next.js(13.4.0) 모든 페이지에서 토큰 유/무 판단하기

현재 signup, signin, home, save, mypage 총 5개의 페이지가 있습니다. home, save, mypage에서 refresh-token의 존재 유/무에 따라서 signin 경로로 redirect 시키려고 합니다. 로그인을 하면 localStorage에 access-token 저장, browser cookie에 refresh-token이 저장됩니다. 로그인 후에 임의로 refresh-token 값을 지웠을 때, signin 경로로 redirect 시켜주기 위해 각 페이지에서 getServerSideProps를 사용하여 refresh-token의 존재 유/무를 판단하여 redirect를 시켜주고 있습니다. 현 상황처럼 각 페이지에서 인증을 처리하는 것이 아닌 모든 페이지에서 공통으로 인증을 처리하는 방법이 있는지 궁금하여 질문드립니다.

개발자

#next.js

#typescript

#인증

답변 1

댓글 1

조회 505

2년 전 · 박예진 님의 질문 업데이트

채팅 새로고침시 연결 끊기는 문제

안녕하세요. 현재 Websocket과 stompjs v6.0.0을 활용해 채팅을 구현했습니다. roomId로 여러 채팅방을 만들 수 있게 구현했고, 현재 새로고침을 하지 않는 이상 잘 돌아갑니다. 그러나, 새로고침 할 시에는 바로 연결이 끊겨 이전의 채팅 내역도 보이지 않고, 연결, 구독 내역이 사라집니다 ... 어떻게 reconnect 해야할까요? 단순히 채팅 페이지에서 useEffect로 connect를 다시 하니 이미 연결 구독이 된 상태라고 뜨더라구요 .... ㅠㅠ (고민글을 올렸을 때 채팅방이 생성되고, 연결 구독이 됩니다. 채팅 시작 버튼을 눌렀을 경우에는 본인이 연결 구독이 되어 1대 1로 상대방과 채팅이 시작되는 구조입니다. ) import { CompatClient, Stomp } from "@stomp/stompjs"; import { createContext, useContext, useMemo, useRef } from "react"; import { useSetRecoilState } from "recoil"; import { messageState } from "../../states/chatting"; import audio from "../../assets/audios/chatting.mp3"; const ChatContext = createContext( {} as { connect: (roomId: number) => void; disconnect: () => void; send: (roomId: number, message: string) => void; }, ); export const useChatContext = () => useContext(ChatContext); export function ChatProvider({ children }: any) { const setMessages = useSetRecoilState(messageState); const token = localStorage.getItem("accessToken"); // 채팅 연결 구독 const client = useRef<CompatClient>(); const connect = (roomId: number) => { client.current = Stomp.over(() => { const sock = new WebSocket("wss://m-ssaem.com:8080/stomp/chat"); return sock; }); client.current.connect( { token: token, }, () => { client.current && client.current.subscribe( `/sub/chat/room/${roomId}`, (message) => onMessageReceived(message, roomId), { token: token!, }, ); }, ); return client; }; const onMessageReceived = (message: any, roomId: number) => { const audioElement = new Audio(audio); audioElement.play(); setMessages((prevMessages) => { const updatedMessages = { ...prevMessages, [roomId]: [...(prevMessages[roomId] || []), JSON.parse(message.body)], }; return updatedMessages; }); }; // 채팅 나가기 const disconnect = () => { if (client.current) { client.current.disconnect(() => { window.location.reload(); }); } }; // 채팅 보내기 const send = (roomId: number, message: string) => { if (client.current) { client.current.send( `/pub/chat/message`, { token: token, }, JSON.stringify({ roomId: roomId, message: message, type: "TALK", }), ); } }; const handlers = useMemo(() => ({ connect, disconnect, send }), []); return ( <ChatContext.Provider value={handlers}>{children}</ChatContext.Provider> ); } ----------이 부분은 connect 하는 부분입니다 --------- const { connect } = useChatContext(); const chatRoomId = worryBoard && worryBoard.chatRoomId; const handleStartChatting = () => { navigate(`/chatting`); connect(chatRoomId!!); }; ------------ 채팅 페이지는 따로 있습니다 --------------

개발자

#websocket

#stompjs

#채팅

#chatting

#react

답변 0

댓글 0

조회 327

2년 전 · Ed 님의 답변 업데이트

nextjs 전역 상태관리 질문

안녕하세요 nextjs(App router 사용)로 프로젝트를 진행하고 있는데, 전역상태를 정의하기 위해서 zustand를 사용하려고 하고 생각중입니다. 전역 상태를 정의하기 위해서는 1. 가장 root가 되는 layout.tsx에 provider를 불러와 감싸주어, 전역적으로 참조할 수 있도록 하는 것 2. persist middleware을 사용해서 LocalStorage에 저장하는 방식으로 상태를 관리하는 것 이 정도 두 가지가 있는 것 같은데, 질문은 1. 만약 1번 방법을 사용한다면 client component로 선언한 custom provider로 자식 컴포넌트를 감싸게 될텐데, 그러면 상태가 변경됨에 따라 하위 컴포넌트들(server, client 상관없이)이 모두 리렌더링 되는 것인가요? 만약 그렇게 된다면 SSR의 의미가 사라지는 것 아닌가요? 2. 일반적으로 nextjs에서는 전역 상태를 어떤 식으로 관리하나요? 입니다. 감사합니다!

개발자

#next.js

#zustand

#상태관리

답변 1

댓글 0

조회 1,356

2년 전 · 박예진 님의 새로운 댓글

채팅 기능 client 가 null 값이 돼요

하나의 페이지에서 connectHandler를 작동하고 또다른 페이지에서 sendHandler를 작동하려고 하는데 이렇게 해서는 useChat()이 리렌더링 되면서 client 값이 초기화가 되더라구요 값을 유지하고 싶고 recoil에 client를 담는 건 불가능이라고 떠서... connectHandler와 sendHandler를 다른 hooks로 분리하는 방법도 생각해봤는데 그러면 또 client값이 connect한 값이 아니더라구요 무슨 방법이 있을까요? 제발 도와주세요 ㅠㅠ (한 페이지에서 connectHandler, sendHandler, disconnectHandler 실행하면 잘 작동합니다!) import { CompatClient, Stomp } from "@stomp/stompjs"; import { useRef } from "react"; import { useRecoilState } from "recoil"; import { inputMessageState, messageState } from "../../states/chatting"; export function useChat() { const [messages, setMessages] = useRecoilState(messageState); const [inputMessage, setInputMessage] = useRecoilState(inputMessageState); const token = localStorage.getItem("accessToken"); // 채팅 연결 구독 const client = useRef<CompatClient>(); const connectHandler = () => { client.current = Stomp.over(() => { const sock = new WebSocket("wss://m-ssaem.com:8080/stomp/chat"); return sock; }); client.current.connect( { token: token, }, () => { client.current && client.current.subscribe(`/sub/chat/room/1`, onMessageReceived, { token: token!, }); }, ); }; const onMessageReceived = (message: any) => { setMessages((prevMessage) => [...prevMessage, JSON.parse(message.body)]); }; // 채팅 나가기 const disconnectHandler = () => { if (client.current) { client.current.disconnect(() => { window.location.reload(); }); } }; // 채팅 보내기 const sendHandler = () => { if (client.current && inputMessage.trim() !== "") { client.current.send( `/pub/chat/message`, { token: token, }, JSON.stringify({ roomId: 1, message: inputMessage, type: "TALK", }), ); setInputMessage(""); } }; return { connectHandler, disconnectHandler, sendHandler, }; }

개발자

#react

#chatting

#stompjs

답변 1

댓글 8

조회 231

2년 전 · 쇠오리 님의 댓글 업데이트

카카오 로그인 accessToken 어디에 저장해야 할까요??

[상황] 현재 하고 있는 동아리 프로젝트에서 카카오 로그인을 구현하기로 했습니다. 저는 프론트엔드 파트이고, 프로젝트는 react, recoil 쓰고 있습니다. +) 팀원이 react-query 써서 백엔드와 통신을 하자고 합니다. [질문] 카카오 로그인에서 인가코드를 백엔드에 보내면, 백엔드에서 accessToken과 refreshToken을 넘겨주는데 이걸 어디에 저장해야 할까요?? 둘다 http response로 헤더에 실어서 보내준다고 합니다! 백엔드에서 쿠키에 넣어주지는 않고 토큰을 보내준다는데, 이걸 어떻게 관리해야 할까요?? localStorage에 저장하는건 매우 위험하다는 글을 봐서, 어떤식으로 관리해야 할지 모르겠습니다. 스토리지에 저장 안 하면, 보통 recoil로 atom에 저장해두고 쓰나요..? 로그인 구현이 처음이라 막막한데 도와주세요ㅠㅠ

개발자

#react

#oauth

#카카오-로그인

#accesstoken

#refreshtoken

답변 1

댓글 2

추천해요 2

조회 699

2년 전 · kevin 님의 새로운 답변

react에서 state를 잘 관리하는 방법 질문 드립니다

안녕하세요 왕킹왕짱짱초보 프론트 개발자입니다 현재 react와 recoil을 사용하여 프로젝트를 개발중입니다 구조는 간단하게 도메인별로 (ex pages 디렉토리 하위 login 디렉토리 하위 action, model, component 이런식으로 구조를 잡아뒀습니다 다른 도메인들도 똑같이 잡아서 사용하고있습니다 서론은 저는 recoil을 그저 로그인 데이터나 다국어 정보등 localstorage와 연관된 정보나 말 그대로 프로젝트 전체 범위에 영향을 끼치는 상태들만 관리하는 용도로 사용하고있습니다 그런데 프로젝트를 진행하다보니 각 도메인별로 컴포넌트 개수가 많아지고 특히 Modal을 사용하거나 api호출 시 isLoading과 같은 상탯값을 다룰때 이게 상태가 많아지고 넘기는 값이 많아지니까 제가 만든 코드를 제가 구분하기 힘든 지경에 이르러버렸습니다... 본론은 도메인별로 api, model, compnent를 관리할때 recoil이나 redux같은 전역 상태도 각 domain별로 atoms 디렉토리나 store 디렉토리로 관리해도 괜찮을까요?? 전역 상태 관리 남용이나 오용은 아닌지 걱정도 되고.. 잘 몰라서 해도 되는지 확신이 안 서네요.. 🙇

개발자

#react

#recoil

#redux

#frontend

#state

답변 2

댓글 0

추천해요 2

보충이 필요해요 1

조회 1,030

2년 전 · 커리어리 AI 봇 님의 새로운 답변

리액트로 스프링과 웹소켓 채팅방을 구현했는데 자동 랜더링이 안됩니다..

안녕하세요! 현재 웹소켓으로 스프링과 채팅기능을 구현중에 있습니다 채팅방에서 채팅을 보내고 받는 건 가능한 상태인데 같이 채팅방에 입장해서 A가 B한테 보냈을 때 B가 페이지를 새로고침 하지 않으면 채팅이 자동 랜더링이 되지 않는 상황인데 여러 방법을 참고하고 해봤지만.. 성공하지 않았습니다 어떻게 풀어나가야 할지 잘 모르겠습니다 ㅠㅠ 코드가 길지만 ... 혹시 답변이 가능할까해서 참고해봅니다 좋은 키워드도 추천해주시면 감사하겠습니다!!... export const ChatRoomPage = () => { //메뉴 모달 const [isModalOpen, setIsModalOpen] = useState(false); const [isExitModalOpen, setIsExitModalOpen] = useState(false); const [backgroundPosition, setBackgroundPosition] = useState('static'); const location = useLocation(); const params = location.pathname; const segments = params.split('/'); const RoomUniqueId = segments[4]; const RoomId = segments[5]; const [messageData, setMessageData] = useState([]); const [messageList, setMessageList] = useState([]); const [message, setMessage] = useState(''); const accesskey = Cookies.get('Access_key'); // 채팅방 입장시 안내 문구 기능 const [showModal, setShowModal] = useState(false); const client = useRef({}); useEffect(() => { console.log('유즈이펙트 쉴행'); setShowModal(true); connect('L'); return () => disconnect(); }, []); const connect = type => { client.current = new StompJs.Client({ brokerURL: 'ws://222.102.175.141:8081/ws-stomp', connectHeaders: { Access_key: `Bearer ${accesskey}`, }, debug: function (str) { console.log('str ::', str); }, onConnect: () => { if (type === 'L') { subscribe(); publish(); } else { subscribe1(); publish1(); } }, }); client.current.webSocketFactory = function () { return new SockJS('http://222.102.175.141:8081/ws-stomp'); }; client.current.activate(); return () => disconnect(); }; const subscribe = () => { client.current.subscribe(`/sub/chat/messageList/${localStorage.memberUniqueId}`, message => { // console.log('messageData11 : ', JSON.parse(`${message.body}`)); setMessageData(JSON.parse(`${message.body}`)); const data = JSON.parse(`${message.body}`); setMessageList(data.data.chatMessageList); }); }; const publish = () => { client.current.publish({ destination: `/pub/chat/messageList/${localStorage.memberUniqueId}`, body: JSON.stringify({ chatRoomId: RoomId, chatRoomUniqueId: RoomUniqueId, page: 0, }), }); }; const closeModal = () => { setIsModalOpen(false); setBackgroundPosition('static'); }; const openModal = () => { setIsModalOpen(true); setBackgroundPosition('fixed'); }; const handleBackdropClick = e => { console.log('e ::', e); if (e.target === e.currentTarget) { closeModal(); } }; const ExitopenModal = () => { setIsExitModalOpen(true); }; const ExitcloseModal = () => { setIsExitModalOpen(false); }; const ReportButtonHandler = () => { alert('곧 업데이트 예정입니다!'); }; // 채팅 보내기 const sendMessage = message => { console.log('message :: ', message); connect(); setMessage(''); return () => disconnect(); }; const subscribe1 = () => { client.current.subscribe(`/sub/chat/message/${RoomUniqueId}`, message => { setMessageData({ ...messageList, message }); }); }; const publish1 = () => { client.current.publish({ destination: `/pub/chat/message/${RoomUniqueId}`, body: JSON.stringify({ memberId: `${localStorage.memberId}`, memberName: `${localStorage.memberName}`, memberUniqueId: `${localStorage.memberUniqueId}`, memberProfileImage: `${localStorage.profileImage}`, chatRoomId: RoomId, chatRoomUniqueId: RoomUniqueId, message: message, }), }); }; const disconnect = () => { client.current.deactivate(); }; console.log('messageList :: ', messageList); return ( <> <div style={{ width: '100%', height: '100%', position: backgroundPosition, }} > <Background> <Topbar> <Link to={`${PATH_URL.PARTY_CHAT}/${localStorage.memberUniqueId}`}> <TopBackDiv> <LeftBack /> </TopBackDiv> </Link> <TopbarName>모임이름</TopbarName> <ModalBtn onClick={() => { openModal(); }} > <RoomMenuIcon /> </ModalBtn> </Topbar> <Container> <Contents> <ParticipantDiv>ㅇㅇㅇ님이 참여했습니다.</ParticipantDiv> {messageList?.map((data, index) => { return ( <OtherDiv key={index}> <div style={{ position: 'relative', }} > <OtherImg> <OtherProfile> <img src={data.memberProfileImage} alt="profile" style={{ width: '100%', height: '100%', borderRadius: '8px', }} /> </OtherProfile> <OtherHostIcon> <PartHostIcon /> </OtherHostIcon> </OtherImg> <OthertInfo> <OtherName>{data.sender}</OtherName> <OtherContents> <OtherChatText>{data.message}</OtherChatText> <OtherChatTime>12:19 pm</OtherChatTime> </OtherContents> </OthertInfo> </div> </OtherDiv> ); })}

개발자

#채팅

#웹소켓

#채팅기능

답변 2

댓글 0

조회 595

2년 전 · 커리어리 AI 봇 님의 새로운 답변

react에서 google oauth redirect 관련해서 좋은 방법이 있을까 해서 질문 드려요~

/pathname-a >> google oauth 로그인 >> redirect to /oauth 위 단계에서 route /oauth에서 다시 route /pathname-a 로 redirect하는 좋은 방법이 있을까요 ? /pathname-a는 언제든 바뀔 수 있는 값이고.. localStorage로 rediret 경로를 저장을 하면 react state가 저장이 되지 않아서 고민이 많네요 ㅠ

개발자

#react

#google-oauth

#redirect

답변 1

댓글 0

조회 166

2년 전 · 프레드윰 님의 답변 업데이트

웹에서 새로고침했을 때 스크롤 유지시켜주는 기능을 개선하려고 합니다.

localstorage에 클릭 요소를 저장해두고 새로고침했을 때 그 값으로( = 유저가 보던 위치로) 스크롤을 내려주는 앵커기능을 만들었는데요, 문제는 더보기를 눌러서 데이터를 더 받아온 상태로 클릭한 요소를 저장하면 더보기를 누르지 않았을 경우엔 그 위치로 갈 수가 없네요.. 이 경우엔 어떻게 해야 할까요?

개발자

#scroll-restoration

답변 1

댓글 0

조회 472

2년 전 · kevin 님의 답변 업데이트

react Custom Hook을 만들려고 하는데 도움이 필요합니다ㅠㅠ

안녕하세요, react, typescript로 개발중인 주니어 취준생입니다 커스텀 훅을 처음으로 작성해보려고하는데... 제가 커스텀 훅에 대한 이해가 부족한 건지 이런 저런 방법을 사용해봐도 같은 에러가 계속 나네요ㅠㅠ vscode상에서 나타나는 에러는 없는데 로그아웃 버튼을 누르면 콘솔에 계속 같은 에러가 생깁니다...! 상황) 로그아웃 로직을 재사용할 수 있게 커스텀 훅으로 관리하려고 함 [로그아웃 로직] - 로그아웃 하면 localStorage의 access_token과 refresh_token을 삭제하고, - alert창을 띄우고, 메인화면으로 이동하게 함. 에러메세지에 있는 링크 https://reactjs.org/warnings/invalid-hook-call-warning.html 에 있는 세가지 일반적인 이유는 아래와 같습니다. 1. React와 React DOM의 버전이 일치하지 않을 수 있습니다 . -> 확인해보니 Hooks를 지원하는 버전 맞습니다. 2. Hooks 규칙을 위반하고 있을 수 있습니다 . -> Hooks규칙을 맞춰서 작성했다고 생각했는데 이부분은 정확하게 모르겠습니다. 3. 동일한 앱에 둘 이상의 React 사본이 있을 수 있습니다 . -> 링크에 나온대로 'npm ls react'를 해보면 사진과 같은 결과가 나옵니다. 혹시 3번이 문제가 있는건가요? 봐도 잘 모르겠습니다...흐ㅠㅠ 커스텀 훅이 아니라 그냥 함수로 만든 후에 재사용해야하나? 싶은데 그 함수는 컴포넌트도 아니고 커스텀훅도 아니라서 useNavigate를 사용할 수 없다는 에러가 떠서 그럼 로그아웃 로직을 사용할 때마다 컴포넌트에서 별도로 navigate처리를 해줘야 할 것 같아서 로그아웃 로직 안에서 useNavigate를 사용해서 커스텀훅으로 만들고 싶습니다...! 이런 형태의 로직은 커스텀훅으로 만들 수 없는건가요? 아니면 제가 뭔가 잘못하고있는게 있을까요ㅜㅠㅠ

개발자

#react

#react-hooks

답변 2

댓글 2

조회 928

2년 전 · 커리어리 AI 봇 님의 새로운 답변

react-persist, localStorage를 사용하지 않고 새로고침시 데이터가 유지되는 방법이 있을까요??

간단한 과제겸 프로젝트(게시판)중인데 요구사항중 게시판 검색조건 상태 및 결과를 새로고침해도 유지된 상태가 되어야 하고 상태관리 라이브러리 (redux-toolkit)을 사용할 수는 있지만, react-persist, localStroage는 사용하지 말라고 되어있어서 구글링해도 잘 나오지 않아 질문 올려봅니다..! 다른 방법이 있을까요??

개발자

#react

#react-toolkit

답변 3

댓글 2

추천해요 1

조회 2,248