#function

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

5달 전 · CP 님의 답변 업데이트

RDBMS 실무 관계 연결 등 질문사항

혼자 프론트, 백엔드, DB 공부를 강의 보면서 독학하고 있는데 이번에 토이프로젝트로 쇼핑몰 웹을 하나 만들려고 합니다. 실무에서는 개발을 어떤식으로 하는지 궁금하여 질문 드립니다. 1. mysql 등 과 같은 RDBMS 테이블 관에 관계를 설정 안 하고 즉 외래키 연결 하나도 안 하고 사용할 때 장단점이 무엇인가요? 2. 지인 DBA분(오래 되심)께서 하시는 말씀은 관계 연결하면 DB 부하 심하다, 성능 저하된다 이런식으로 말씀하셨는데 맞나요? 2-1. 성능이 저항된다면 심하게 저하되나요? 3. 쿠팡, G마켓, 무신사, 유튜브 등과 같은 대형 플랫폼들은 RDBMS를 사용할 때 실제로 관계 연결을 안 하나요? 4. DB에서 값을 불러 올 때도 join 하나도 안 하고 소프트웨어적으로 수동으로 연결 한다. 제가 이해 하기로는 사진에 있는 예시 사진 참고 하면서 예를 들면 cart 불러오는데 user이름도 알아야 한다면 DB에 join을 해서 가져오는게 아니라 백엔드에 각 각 user, cart를 따로 호출하고 백엔드에서 if, for, array function 같은 메소드를 사용해 작업을 거쳐 가공 한다는 것 같은데 이러면 실무 적으로 봤을 때 장단점이 무엇인가요? 5. 대형 플랫폼 같은 실무에서는 4번 방식 처럼 하나요? 참고로 테이블이 20개 이상 정도 될 경우의 상황이 궁금합니다 실무에 관해서 민감한 질문 드려서 죄송합니다. 아는 것 없이 질문을 여러번 드려 번거롭게 만들어서 죄송합니다. 답변해 주신다면 열심히 공부하겠습니다.

개발자

#rdbms

답변 2

댓글 0

조회 69

6달 전 · 익명 님의 질문

ios18 popstate 적용

Ios18 업데이트 이후 popstate 적용 안되는 분 계신가요???... window.addEventListener('popstate', function (event){}

개발자

#프론트엔드

#javascript

답변 0

댓글 0

조회 27

6달 전 · 문종호 님의 새로운 답변

RAG 를 짜는 중에 도무지 어떤 부분이 문제인지 모르겠습니다.

# JSON 파일에서 FAQ 데이터를 로드하는 함수 def load_faq_data_from_json(file_path): with open(file_path, 'r', encoding='utf-8') as f: faq_data = json.load(f) return faq_data # FAQ 데이터 로드 json_file_path = '' faq_data = load_faq_data_from_json(json_file_path) # ChromaDB 클라이언트 및 Embedding 설정 chroma_client = chromadb.Client() # ChromaDB 클라이언트 생성 # 고유한 컬렉션 이름 생성 collection_name = "faq_data_" + datetime.datetime.now().strftime("%Y%m%d_%H%M%S") collection = chroma_client.create_collection(collection_name) # LangChain의 Text Splitter 설정 text_splitter = RecursiveCharacterTextSplitter( chunk_size=512, chunk_overlap=50 ) # OpenAI 임베딩 설정 openai_api_key = '' embedding_function = OpenAIEmbeddings( model="text-embedding-ada-002", openai_api_key=openai_api_key ) # 텍스트 스플리팅 및 임베딩 생성 함수 def split_and_embed_text(text): splitted_texts = text_splitter.split_text(text) print(f"Splitted texts: {splitted_texts}") try: # OpenAIEmbeddings는 embed_documents를 사용합니다. embeddings = embedding_function.embed_documents(splitted_texts) except Exception as e: print(f"임베딩 생성 중 오류 발생: {e}") return None # 임베딩이 제대로 생성되었는지 확인합니다. if embeddings is None or len(embeddings) == 0: print("임베딩 생성 실패") return None # 임베딩을 numpy 배열로 변환 embeddings = np.array(embeddings) print(f"Embeddings shape: {embeddings.shape}") # 임베딩 벡터의 차원을 확인하고 처리합니다. if embeddings.ndim == 1 and embeddings.shape[0] == 1536: # 임베딩이 1차원 배열이고 길이가 1536인 경우 final_embedding = embeddings elif embeddings.ndim == 2 and embeddings.shape[1] == 1536: # 임베딩이 2차원 배열이고 두 번째 차원이 1536인 경우 final_embedding = np.mean(embeddings, axis=0) else: print("임베딩 벡터의 차원이 예상과 다릅니다.") return None print(f"Final embedding shape: {final_embedding.shape}") return final_embedding # FAQ 데이터를 Vector DB에 저장 def store_faq_data_in_vector_db(faq_data, collection): for faq in faq_data: # 'question'과 'answer'가 있는지 확인하고, 'answer'가 None이 아닌지 확인 if 'question' not in faq or 'answer' not in faq or faq['answer'] is None: print(f"누락된 'question' 또는 'answer'로 인해 항목을 건너뜁니다: {faq}") continue # 다음 항목으로 넘어감 # 텍스트 스플리팅 및 임베딩 생성 question_embedding = split_and_embed_text(faq['question']) if question_embedding is None: print(f"Embedding generation failed for question: {faq['question']}") continue # 임베딩이 없으면 다음 질문으로 넘어감 print(f"Generated embedding for question '{faq['question']}': {question_embedding}") # 각 질문에 고유한 ID 생성 faq_id = str(uuid.uuid4()) # 메타데이터에서 None 값을 제거 metadata = {k: v for k, v in {"answer": faq['answer']}.items() if v is not None} # Vector DB에 저장 collection.add( documents=[faq['question']], metadatas=[metadata], ids=[faq_id], embeddings=[question_embedding] ) # 추가 후 임베딩 확인 (저장된 후 곧바로 확인) stored_results = collection.get(ids=[faq_id], include=["embeddings"]) if stored_results['embeddings'] is not None and len(stored_results['embeddings']) > 0: print(f"Embedding for question '{faq['question']}' successfully stored.") else: print(f"Failed to store embedding for question '{faq['question']}'") # FAQ 데이터를 JSON에서 로드하고 저장 store_faq_data_in_vector_db(faq_data, collection) 이렇게 데이터를 저장하고 # 환경 변수에서 API 키 로드 openai_api_key = os.getenv("OPENAI_API_KEY") if not openai_api_key: raise ValueError("OpenAI API 키가 설정되지 않았습니다. 환경 변수 OPENAI_API_KEY를 설정하세요.") # OpenAI 임베딩 설정 embedding_function = OpenAIEmbeddings( model="text-embedding-ada-002", openai_api_key=openai_api_key ) # LangChain의 Text Splitter 설정 (일관성 유지) text_splitter = RecursiveCharacterTextSplitter( chunk_size=512, chunk_overlap=50 ) # ChromaDB 클라이언트 및 컬렉션 설정 chroma_client = chromadb.Client() collection_name = "faq_data_collection" try: # 이미 존재하는 컬렉션인지 확인하고, 있으면 가져옴 collection = chroma_client.get_collection(name=collection_name) except chromadb.errors.CollectionNotFoundError: # 컬렉션이 존재하지 않을 경우에만 생성 collection = chroma_client.create_collection(name=collection_name) # Vector DB에서 유사 질문 검색 (ChromaDB) def find_similar_question_in_vector_db(new_question_embedding, collection, k=5): results = collection.query(query_embeddings=[new_question_embedding], n_results=k, include=['documents', 'metadatas', 'embeddings']) best_similarity = 0 best_question = None best_answer = None # 검색 결과에서 각 질문의 유사도와 답변을 처리합니다. if 'documents' in results and 'metadatas' in results: documents = results['documents'][0] metadatas = results['metadatas'][0] embeddings = results['embeddings'][0] for i in range(len(documents)): stored_embedding = embeddings[i] metadata = metadatas[i] if stored_embedding is not None: # 코사인 유사도를 통해 유사도를 계산합니다. similarity = cosine_similarity([new_question_embedding], [stored_embedding])[0][0] print(f"유사도: {similarity} for {documents[i]}") # 유사도가 가장 높은 결과를 선택하며, 임계값 이상일 경우에만 선택 if similarity > best_similarity and similarity >= SIMILARITY_THRESHOLD: best_similarity = similarity best_question = documents[i] if isinstance(metadata, list): metadata = metadata[0] best_answer = metadata.get('answer') if isinstance(metadata, dict) else None return best_question, best_answer # Fine-tuned GPT를 사용해 새로운 답변 생성 def gpt_generate_response_from_finetuned_gpt(question, style="의사 A 말투"): prompt = f"다음은 환자의 질문입니다: \"{question}\". 아래 말투를 사용하여 질문에 대해 성실하고 정확한 답변을 작성해주세요.\n\ 말투: {style}" response = client.chat.completions.create( model="", # Fine-tuned된 GPT 모델 ID messages=[ {"role": "system", "content": "You are a helpful medical assistant."}, {"role": "user", "content": prompt}, ], max_tokens=300, temperature=0.7, # 답변의 다양성을 조절합니다. ) return response.choices[0].message.content.strip() # 새로운 질문 처리 및 최종 응답 생성 def generate_final_response(new_question, collection): # 텍스트 스플리팅 및 임베딩 생성 splitted_texts = text_splitter.split_text(new_question) new_question_embedding = np.mean(embedding_function.embed_documents(splitted_texts), axis=0) # ChromaDB에서 유사 질문 검색 similar_question, answer = find_similar_question_in_vector_db(new_question_embedding, collection) if similar_question and answer: final_response = f"질문: {new_question}\n유사 질문: {similar_question}\n기본 답변: {answer}" else: generated_answer = gpt_generate_response_from_finetuned_gpt(new_question) final_response = f"질문: {new_question}\nGPT로 생성된 답변: {generated_answer}\n(이 답변은 벡터데이터에서 유사한 답변을 찾을 수 없어 GPT에 의해 생성되었습니다.)" return final_response # 사용자로부터 새로운 질문 입력 받기 new_question = input("새로운 질문을 입력하세요: ") # 최종 응답 생성 response = generate_final_response(new_question, collection) print(response) 로 데이터베이스에서 유사한 질문-답변 쌍을 끌어오려는데 정확히 같은 질문을 넣어도 (이러면 유사도가 1인데) 저장되어있는 답변이 끌어와지질 않네요...

개발자

#llm#rag

답변 1

댓글 0

조회 95

8달 전 · 유호준 님의 질문

NavigationContainer 중첩 오류

안녕하세요, RN(Expo)로 React Navigation을 적용하다 오류가 해결되지 않아서 질문드립니다. expo를 통해 다음과 같이 index.js에 React Navigation을 적용했습니다. import { store } from "@/redux/store"; import MainScreen from "./screens/MainScreen"; import { Provider } from "react-redux"; import { NavigationContainer } from "@react-navigation/native"; import { createNativeStackNavigator } from "@react-navigation/native-stack"; import LoginScreen from "./screens/LoginScreen"; export default function HomeScreen() { const Stack = createNativeStackNavigator(); return ( <Provider store={store}> <NavigationContainer> <Stack.Navigator> <Stack.Screen name="Main" component={MainScreen} /> <Stack.Screen name="Login" component={LoginScreen} />{" "} </Stack.Navigator> </NavigationContainer> </Provider> ); } 그러나 다음과 같은 오류가 뜨며 빈화면만 보이더라구요ㅠ Error: Looks like you have nested a 'NavigationContainer' inside another. Normally you need only one container at the root of the app, so this was probably an error. If this was intentional, pass 'independent={true}' explicitly. Note that this will make the child navigators disconnected from the parent and you won't be able to navigate between them. 찾아보니 NavigationContainer가 중첩되었다는 것 같은데, 저는 계속해서 그대로 강의를 따라가고 있었고, 따로 NavigationContainer를 적용한 파일이 존재하지 않습니다 ㅠ 다음 속성을 추가해도 오류가 해결되지 않습니다 ㅠ 아마 어디선가 부모에서 NavigationContainer가 적용된 것 같은데 찾을 수가 없네요 ㅠㅠ independent={true} 조금 더 찾아보니 expo-router랑 충돌이 난 거일 수도 있다는데 정확하게 모르겠네요 ㅠ

개발자

#react-native

#react-navigation

#expo

#navigationcontainer

답변 0

댓글 0

조회 103

9달 전 · 익명 님의 질문

Expo SQLite WHERE 조건 한글 안됨

React Native Expo에서 앱을 개발중에 sql문이 오류가 뜹니다. 코드는 아래와 같습니다. async function SearchName() { console.log("load data"); try { const db = await SQLite.openDatabaseAsync("MountBedge.db"); const data = await db.getAllAsync(`SELECT * FROM HikingData WHERE Name = '가';`); setLoadedData(data); } catch (error) { console.error("Error testing database connection:", error); } } 문제가 되는 부분은 getAllAsync의 WHERE부분입니다. 한글로 검색한 부분을 영어로 변경하면 오류도 뜨지 않고 검색도 잘 됩니다. 한글로 검색 시 뜨는 오류는 아래와 같습니다. Error testing database connection: [Error: Calling the 'prepareAsync' function has failed → Caused by: Error code 1: near "'ㄱ'": syntax error] 혹시 해결할 방법을 아시는 분이 계시나요? 이게 expo에서는 해결이 가능한건지, 아니면 react native cli로 넘어가야 하는건지 모르겠습니다. 추가로 expo에서 sql문으로 데이터를 저장 시 db가 어디에 있는지 알 수 있는 방법이 있다면 알고싶습니다. 영어를 못해 영어로는 검색을 거의 안해봤지만 자료가 너무 없네요...

개발자

#react-navite-expo

#react-native

#expo

#sql

답변 0

댓글 0

조회 49

일 년 전 · 짹 님의 새로운 답변

콜백함수부분에 대해 질문있습니다.

안녕하세요 현재 자바스크립트를 공부하고 있는 초보자입니다. 현재 위치를 보여주는 코드를 작성하면서 궁금한 점이 생겼습니다. const askForLocation = function () { navigator.geolocation.getCurrentPosition((position) => { console.log(position); }); }; askForLocation(); 이러한 코드가 있는데 제가 알기론 ()=>{} 콜백함수에 매개변수로 position이 있고 제일 마지막에 askForLocation() 함수 호출하는게 있는데 이 함수 호출부분에서 인자로 아무것도 전달되는것이 없어서 console.log(position)를 했을 때 undefined가 나올 것을 예상했는데 geolocation의 객체정보가 콘솔창에 나오더라구요. 그래서 매개변수로 전달 될 만한것이 없는데 어떻게 콘솔창에 객체정보가 나오는지 궁금합니다. 초보자 입장에서 정말 쉽게 설명해주시면 너무 감사드리겠습니다.

개발자

#함수

#콜백함수

#프론트엔드

#자바스크립트

답변 1

댓글 0

보충이 필요해요 1

조회 45

일 년 전 · 프레드윰 님의 새로운 답변

안녕하세요 html,css질문입니다 제발 도와주세요

<!doctype html> <html lang="en"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>중경삼림</title> <script src="//code.jquery.com/jquery-3.3.1.min.js"></script> <script src="https://cdnjs.cloudflare.com/ajax/libs/jquery.mb.YTPlayer/3.3.1/jquery.mb.YTPlayer.min.js"></script> <script> jQuery( function() { jQuery( '#background' ).YTPlayer(); } ); </script> <link rel="stylesheet" href="style.css"> </head> <body> <div class="jb-box"> <div id="background" class="player" data-property="{ videoURL:'https://www.youtube.com/watch?v=ncT1R2hMpaQ', mute: true, showControls: false, useOnMobile: true, quality: 'highres', containment: 'self', loop: true, autoPlay: true, stopMovieOnBlur: false, startAt: 9.5, opacity: 1 }"></div> </div> <br><br><br> <div id="director"> <br><br><br><br> <h1>왕가위</h1> </div> </body> </html> 이건 html이고, body{ margin: 0; } .jb-box { position: relative; } #background { z-index: -1; } 이건 외부 css파일입니다. 문제는 저 스크립트가 다른 컴퓨터에서 실행했을 때 영상이 재생되지 않는다는 것입니다. '이 동영상은 볼 수 없습니다'로 뜹니다...혹시 저 스크립트에 문제가 있는 것 일까요..?? 도와주시면 정말 감사하겠습니다...

개발자

#html-css-js

#웹디자인

#css

#html

#script

답변 2

댓글 0

조회 88

일 년 전 · 방재호 님의 답변 업데이트

[Js] 함수 매개변수 전달에 대하여...

안녕하세요! 이제 막 1년 좀 넘은 주니어 개발자 입니다. 공부 중에 한 가지 궁금한 점이 생겨서 선생님들께 여쭤보려합니다. js 함수를 작성하는 중에 매개변수로 event를 전달하려 했더니 event에 취소선이 생성됩니다... 예시) - html - <div class='.card'> ... <button id="deleteCard" onclick="deleteCard(event)">삭제</button> </div> - js - function deleteCard(event){ let card = $(event.target).closest('.card').remove(); }; 위와 같이 작성했는데 함수 실행은 되긴 하는데 매개변수 event에 취소선이 생기니 잘못된 것 같아서 여쭤봅니다... 취소선이 생기는 이유와 문제가 된다면 어떤 점에서 문제가 생기는지 개선점은 뭐가 있는지 궁금해서 문의 남깁니다.

개발자

#javascript

#매개변수

답변 1

댓글 0

조회 80

일 년 전 · 한민석 님의 새로운 댓글

NextJS 14 project 시작 단계에서 에러가 발생했어요... 최대한 빠른 답변 부탁드립니다.

npx create-next-app 라는 명령어로 프로젝트를 시작했는데요. 아무것도 건들이지 않은 상태에서 app/layout.tsx 파일을 클릭했는데 맨 위에 에러가 발생해져 있더라구요.. 내용을 보니깐 Parsing error: __classPrivateFieldGet(...).at is not a function eslint 이런 에러가 있고 해당 에러가 tailwindcss.config.ts 파일 맨 윗줄에도 발생해져 있습니다. 어떻게 해야하는 건가요..?

개발자

#nextjs

#react

#nextjs14

#nextjs13

#next.js

답변 1

댓글 1

보충이 필요해요 2

조회 152

일 년 전 · 털먹는토끼 님의 새로운 댓글

타입스크립트 'value' is possibly 'null' 에러 옵셔널체이닝으로 해결안되는 이슈

import DateRangePicker from "@wojtekmaj/react-daterange-picker"; import { useDispatch } from "react-redux"; import { dateFetch } from "components/feature/FetchSlice"; import styled from "styled-components"; type ValuePiece = Date | null; type Value = ValuePiece | [ValuePiece, ValuePiece]; export default function CustomCalendar() { const dispatch = useDispatch(); const [value, onChange] = useState<Value>([new Date(), new Date()]); return ( <CalendarBox> <Calendar>조회 기간</Calendar> <StlyedDateRangePicker onChange={onChange} value={value} onCalendarClose={() => { dispatch( dateFetch({ startDate: value[0]?.toISOString(), endDate: value[1]?.toISOString(), }) ); console.log(value); }} /> </CalendarBox> ); } <StlyedDateRangePicker>는 styled component로 만든 DateRangePicker 라이브러리 컴포넌트입니다. DateRangePicker 에서 날짜 2개를 선택하면 value라는 배열에 Date 객체 2개가 들어갑니다. 그리고 onCalendarClose 함수가 동작하면서 redux로 만들어놓은 startDate, endDate 객체에 각각 date를 toISOString() 처리한 값이 할당되는 로직입니다. 날짜를 선택하기 전에는 value={value}의 value 배열요소인 Date객체 값이 null 값이니까 type ValuePiece = Date | null; 타입지정을 해줬습니다. startDate: value[0]?.toISOString(), endDate: value[1]?.toISOString(), 근데 위 코드의 value[0], value[1] 에러가 나더라구요. 'value' is possibly 'null'.ts(18047) Element implicitly has an 'any' type because expression of type '0' can't be used to index type 'Date | [ValuePiece, ValuePiece]'. Property '0' does not exist on type 'Date | [ValuePiece, ValuePiece]'. null 값일 수도 있다길래 옵셔널체이닝을 줬는데 여전히 에러가 발생합니다.. 해결방법을 도무지 모르겠네요.. 도와주시면 진심으로 감사하겠습니다ㅠㅠㅠ

개발자

#react

#typescript

#optional-chaining

답변 3

댓글 3

조회 270

일 년 전 · olcloolzj 님의 새로운 댓글

Next.js에서 page.js

안녕하세요. Next.js를 공부하던 중 궁금한점이 생겨 질문드립니다 ! 제가 app/page.js 파일에 사용자가 로그인했다면 메인화면 컴포넌트를 보여주고, 로그인하지 않았다면 로그인 컴포넌트를 보여주도록 작성해두었습니다. 그런데 궁금한 점이 로그인을 했는지 유무를 getserversession을 통해 세션을 확인해서 판단합니다. 그런데 이때 비동기처리를 위해 await를 붙여줘야하는데, 그렇다면 page.js의 Home() 자체에 async를 붙여주어야합니다. 그래서 해당 방법을 사용해 제가 생각한 로직은 구현했습니다. 그런데 궁금한 점이 page.js에서 export default async function Home() 이런식으로 작성해도 되나요? 제가 page.js의 역할을 정확히 이해하지 못한 느낌이 들어 질문드립니다. (챗 지피티에게 물어보니 13버전 이전의 내용만 알고 있는 듯합니다. 또한 컴포넌트 자체에 async를 붙이면 안된다고 답변이 옵니다 !)

개발자

#next.js

답변 1

댓글 1

추천해요 1

조회 492

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

react에서 에러 status에 따라 에러 모달을 가져오는 법

안녕하세요. 지금 api를 호출 후에 api에서 에러가 났을 때, 해당 에러의 status를 저장하여 해당 status에 맞는 에러 모달을 띄워주려고 하고 있습니다. ``` catch (error: unknown) { if (error instanceof AxiosError) { handleErrorModal(error.response?.status); } return null; } ``` 이렇게 fetchData에서 에러가 발생했을 때, handleErrorModal로 에러 status를 전달하고 있습니다. ``` const [errorType, setErrorType] = useRecoilState(errorDataState); const handleErrorModal = (errorStatus: string | number | null) => { setErrorType(errorStatus); }; ``` 그리고 handleErrorModal 함수는 이와 같이 작성을 해놓은 상태이고요. 근데, setState가 비동기로 작동해서인지 errorStatus가 저장이 되지 않아서 계속 초기값인 null을 띄워줍니다. 그리고, 계속 ``` Warning: Can't perform a React state update on a component that hasn't mounted yet. This indicates that you have a side-effect in your render function that asynchronously later calls tries to update the component. Move this work to useEffect instead. ``` 이 오류를 띄우네요. 이 문제를 해결하기 위해서는 useEffect를 쓰는 방법외에는 다른 방법이 없는걸까요?

개발자

#react

#react-query

답변 1

댓글 1

조회 112

일 년 전 · 이동희동이 님의 질문

Next.js 14 서버액션을 사용한 폼 데이터 처리 중 질문입니다.

next.js 14의 서버액션을 사용해서 사용자로부터 form으로 데이터를 입력받아 DB에 저장하고 첨부파일을 서버에 업로드하는 모듈을 개발중입니다. 문제점은, 첨부파일을 input으로 입력받아 서버액션 함수로 formData로 넘겨주는데, 서버액션 함수에서 첨부파일의 파일명에 한글이 포함됐을 경우 파일명의 한글이 유니코드로 보이는 문자열로 찍히고 있습니다. // Form.jsx "use client"; // [other code] export default function Form() { const [formState, formAction] = useFormState(inquiryAction, { success: undefined, message: "", }); const { register, handleSubmit, reset, formState: { errors }, } = useForm(); const onSubmit = (data) => { const formData = new FormData(); const jsonData = JSON.stringify(data); formData.append("jsonData", jsonData); data.attachment[0] && formData.append("attachment", data.attachment[0]); formAction(formData); }; return ( <form action={handleSubmit(onSubmit)}> // [other code] <FileInput label="첨부파일" {...register("attachment")} error={errors} resetTrigger={resetTrigger} /> // [other code] </form> ); } // inquiryAction.js "use server"; import { connectDB } from "./connectDB"; export async function inquiryAction(prevState, formData) { const fields = JSON.parse(formData.get("jsonData")); const attachment = formData.get("attachment"); console.log(attachment); } Form 컴포넌트는 클라이언트 컴포넌트이고, react-hook-form과 next14의 서버액션을 사용하기 위해, form의 action에는 react-hook-form의 handleSubmit함수에 onSubmit 함수를 인자로 전달합니다. onSumbit 함수에서 서버액션 함수를 가져와 처리를 하고 있습니다. 그런데 여기서 서버함수쪽에서 첨부파일을 받을 때 한글 파일명이 다 깨지고 있네요... 기존에 api route와 fetch api를 사용했을 땐 문제가 없었는데.. 제가 놓치고 있는 부분이 있을까요?

개발자

#next.js

#server-action

답변 0

댓글 0

조회 529

일 년 전 · 우엉김밥 님의 질문

nextjs에서 랜더링 시점 바꾸기

안녕하세요! nextjs 프로젝트 진행중에 궁금증이 생겼습니다. 현재 Sidebar 컴포넌트에서 카카오맵이 불러와져야 작업을 할 수 있는 상태입니다. 카카오 맵은 children 에서 랜더링되기 때문에 아래와 같이 코드작성시, Sidebar 랜더링 시점에 kakao is not defined 라는 오류가 뜹니다. 혹시 Sidebar를 좀 늦게 랜더링 할 수 있을까요? export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body className={inter.className}> <div id="login-modal" /> <section className="flex h-screen"> <nav className=" h-full bg-slate-100"> <Sidebar /> </nav> {children} </section> </body> <Script src={`//dapi.kakao.com/v2/maps/sdk.js?appkey=${APIKEY}&libraries=services,clusterer`} strategy="beforeInteractive" /> </html> ); }

개발자

#nextjs

#reactjs

답변 0

댓글 0

조회 59

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

리액트 쿼리 useQuery에서 데이터가 잘못 나오는 부분

하나의 컴포넌트에서 두개의 useQuery를 사용중입니다. 각각의 useQuery는 다른 쿼리키를 갖고 있으며 하나는 상품정보, 하나는 카테고리 정보를 불러옵니다. 그런데 '간혹' 상품정보 쿼리에서 카테고리 정보를 불러올때가 있습니다. 코드를 일부 보여드리겠습니다. // 상품정보 불러오는 코드(커스텀 훅) export default function useGetProduct(productId: number) { return useQuery(["getProduct", productId], () => getProduct(productId), { onError: (err) => alert(err), }); } // 카테고리 정보 불러오는 코드(커스텀 훅) export default function useGetCountByCategory() { return useQuery(["getCountByCategory"], getCountByCategory, { select: (res) => res.result.productCountsByCategory, }); } 두 코드에서 쿼리키가 완전 다르다고 생각합니다. 그런데 에러가 나서 네트워크 탭을 보면 상품정보 request의 response에 카테고리 정보 response가 담겨옵니다(백엔드 쪽은 스웨거를 통해 여러번 시도했는데 동일하게 데이터가 오고 있구요). 어떤 부분이 문제일까요!? 리액트 쿼리가 아주 애를 먹이네요..! 지식을 나눠주신다면 감사하겠습니다.

개발자

#react

#react-query

#frontend

답변 1

댓글 1

조회 105

일 년 전 · 이수빈 님의 질문 업데이트

zustand의 equality function의 파라미터가 같은 값을 반환합니다

안녕하세오 zustand 사용 중 궁금한게 있어 글 쓰게 되었습니다 zustand는 이전 값과 변경된 값을 비교해서 true가 리턴되면 리렌더링이 일어나는 것으로 알고 있는데 값이 객체일때 acion으로 객체를 수정하게 되면 이전 값도 바뀐 값으로 콘솔에 찍힙니다. 원시값일땐 이전값과 변경한값이 잘 찍히는데 객체만 이러는 이유가 있을까요? 뭔가 놓치고 있다면 답변 주시면 감사하겠습니다.

개발자

#react

#zustand

답변 0

댓글 0

조회 34

일 년 전 · LHS 님의 질문

Next.js의 dynamic import를 이용한 Ref 전달

현재 next.js 13버전과 toast ui calendar를 사용해서 프로젝트를 진행하고있습니다. toast ui calendar는 서버사이드에서는 렌더링이 되지 않기 때문에 dynamic 함수를 사용해서 import를 했습니다. dynamic 함수를 사용해서 import한 component에 ref를 넘기는 방법이 궁금합니다! https://careerly.co.kr/qnas/2078 위의 질문글을 보고 현재 아래 코드와 같이 작성을했는데 이렇게 작성을 하게된다면 결국 TuiCalendar라는 컴포넌트에는 ref={ref}, forwardRef를 사용해서 넘기는것이 아닌 forwardedRef라는 props로 ref를 넘기는형태가 되는건데 dynamic 함수를 사용해서 받아온 컴포넌트에 ref를 넘기는것은 이방법밖에 없을까요? 또한 "use client" import { useRef } from "react"; import Child from "./child"; export default function Parent (props : any) { const testRef = useRef(3) return ( <> <button onClick={() => console.log(testRef.current)}>버튼</button> <Child testRef={testRef} /> </> ) } 이것과 같이 ref를 그냥 props로 넘기는것과 ref + forwardRef 로넘기는 것의 차이점을 알고싶습니다!

개발자

#next.js

#react

답변 0

댓글 0

추천해요 2

조회 508

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

테일윈드 + react 사용 중인데 반응형을 어떻게 구현하면 좋을까요?

안녕하세요 ! 테일윈드 + react로 간단한 투두프로젝트 진행 중인데 반응형을 구현하던 도중 궁금한 점이 생겨서 질문드립니다. 최대 뷰포트 480 이하부터만 특정 컴포넌트(시계, 제목)는 안보이게 하고 기존의 투두리스트 입력할 input, 투두리스트 ul 목록들, 날짜만 보이도록 구현하고 싶은 상황입니다. 480 이상일 때는 위의 말한 컴포넌트들이 모두 보이는 상황입니다! 테일윈드 반응형을 하게 되면 특정 뷰포트일 때만 아예 안보이도록도 구현할 수 있나요? 가능하다면 특정 컴포넌트는 안보여야 하다보니 기존에 구현에 놓은 ui가 안깨지고도 가능한건지, 아니면 직접 재설정 해줘야하는건지도 궁금합니다! 테일윈드 반응형에 익숙치 않아서 어렵네요 ㅠㅠ 위와 같은 고민으로 다른 방법을 찾다보니 useMediaQuery 가 있어서 설치해보고 사용중인데 테일윈드의 단점인 클래스명 길어지는 것, 일일히 태그마다 지정해서 사용해줘야한다는 것을 해결해 줄 수 있을 것 같았는데 특정 컴포넌트가 아예 안보이게 하다보니 조건부렌더링으로 해서 코드가 길어지고, 480 이하 일때 안보이기는 하나 ui가 모두 다 깨져서 결국엔 다시 테일윈드로 레이아웃을 맞춰주게 되더라구요.. 코드로 예를 들자면 import { useMediaQuery } from 'react-responsive'; function TodoHead() { const isSmallScreen = useMediaQuery({ query: '(max-width: 480px)', }); return ( !isSmallScreen && ( <div> <h1 className="mt-[100px] text-center text-6xl font-bold text-white"> Todo List </h1> </div> ) ); } export default TodoHead; 이와 같이 짜둔 상황인데 480 이하일 때는 의도대로 제목이 안보이기는 하나, 해당 컴포넌트가 사라지면서 모든 ui가 깨지니까 결국엔 다시 레이아웃을 조정해야하는 상황인거죠 ㅠㅠ 테일윈드 단점을 해결하고자 쓴건데 좋은 방법이 아닌 것 같기도하고.. 사실 초보라서 사용하던 테일윈드를 활용해서 해결 가능한건지, useMediaQuery 이게 좋은 방법인지도 아닌지도, 아님 굳이 사용할 필요가 없는건지.. 잘 판단이 안서는 상황이네요..ㅎㅎ 도와주세요 선배님들의 조언이 필요합니다 !!

개발자

#tailwind

#반응형웹

#react

#프로젝트

답변 1

댓글 2

조회 2,172

2년 전 · 권민수 님의 답변 업데이트

자바스크립트 코드작성에 대해 질문있습니다.

안녕하세요 현재 프론트엔드의 자바스크립트 인강을 들으면서 기초를 공부중인데 변수~함수등 기본적인 문법을 배우고 어떤 실습을 하는데 여기서 궁금한점이 있습니다. // 랜덤번호 지정 (컴퓨터쪽) // 유저가 번호를 입력한다. 그리고 go라는 버튼 클릭 // 만약에 유저가 랜덤번호를 맞추면 맞췄습니다. // 만약에 유저가 랜덤번호를 틀리면 틀렸습니다. // 랜덤번호 < 유저 down // 랜덤번호 > 유저 up // Reset을 누르면 게임이 리셋된다. // 5번의 기회를 다 사용하면 게임이 끝난다. (더 이상 추측불가, 버튼이 disable(클릭안됨)) // 유저가 1~100 범위 밖에 숫자를 입력하면 알려준다. 기회를 깍지 않는다. // 유저가 입력한 숫자를 또 입력하면 알려준다. 기회를 깍지 않는다. let compuerNum = 0; // 랜덤번호 저장할 변수 작성 function pickRandomNum() { compuerNum = Math.random(); console.log(compuerNum); } pickRandomNum() 이런 코드가 있는데 궁금한점이, 1. 위 코드에서 랜덤번호를 저정할 변수를 만들었는데 저 코드를 혼자 작성해본다고 했을때 저걸 변수에 우선 담아야 겠다. 뭐 이런 생각조차 나지 않더라구요. 어떻게 하면 쉽게 할수 있을지 궁금하고, 2. 두번째로 밑에 함수를 사용했는데 함수는 재사용, 관련된것끼리 묶어놓는다 이정도로 알고있습니다. 1번 질문과 마찬가지로 이부분은 함수를 사용하면 되겠다 이런 생각도 나지 않는데 혼자서도 코드를 잘 짜는 방법이 있다면 알려주시면 너무 감사드리겠습니다. 문법은 어느정도 이해는 하는데 혼자 코드를 작성을 할려고 하니 너무 막막하더라구요. 초보자가 그래도 조금이라도 코드를 혼자 작성할 정도로 공부를 한다면 어떤식으로 공부를 하면 되는지 선배님들의 조언부탁드리겠습니다.

개발자

#javascript

#프론트앤드

답변 2

댓글 2

조회 233

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

(SSR 새로고침 문제)NextJS page에서 redux persist gate 설정하면 Client컴포넌트로 인식되는 문제

NextJS Pages Router에서 유저 데이터를 상태관리하기위해 redux를 사용했으나, 새로고침 시 데이터가 날라가는 문제를 해결하기 위해 persist gate를 사용했습니다. 하지만 redux persist gate를 사용하면 클라이언트 컴포넌트로 인지되는 문제가 있습니다. 궁금한 것 1) persist gate를 잘못써서 생긴 문제일까요? 아님 persist gate를 쓰면 안될까요? 2) 해결 방법으로 생각 해본 것은, "persist gate를 사용하지 않고 매 새로고침 시 저장되어있는 local storage에서 데이터를 새로 가져온다." 입니다. 3) ssr시 상태관리 새로고침 다른 방법으로 해결해본 경험 있으시면 아무렇게나 대답해주시면 감사하겠습니다!!! ----------------------------------------------- 문제의 코드 위치: https://github.com/bbookng/zippyziggy-v2/blob/main/frontend/zippy-ziggy/src/pages/_app.tsx 문제의 코드: import GlobalStyle from '@/styles/Global.style'; import useDarkMode from '@/hooks/useDarkMode'; import { media } from '@/styles/media'; import { darkTheme, lightTheme } from '@/styles/theme'; import type { AppProps } from 'next/app'; import { ThemeProvider, createGlobalStyle } from 'styled-components'; import normalize from 'styled-normalize'; import '@/styles/index.css'; import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; import AppLayout from '@/layout/AppLayout'; import store, { persistor } from '@/core/store'; import { PersistGate } from 'redux-persist/integration/react'; import { Provider } from 'react-redux'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; import 'toastify-js/src/toastify.css'; import { ToastContainer } from 'react-toastify'; import 'react-toastify/dist/ReactToastify.css'; import DefaultHead from '@/components/Head/DefaultHead'; import Construction from './construction'; const queryClient = new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, // default: true }, }, }); function App({ Component, pageProps }: AppProps) { const { colorTheme, toggleTheme } = useDarkMode(); return ( <Provider store={store}> <PersistGate persistor={persistor}> <QueryClientProvider client={queryClient}> <ThemeProvider theme={colorTheme === 'dark' ? darkTheme : lightTheme}> <AppLayout toggleTheme={toggleTheme}> <Component {...pageProps} /> ... </AppLayout> </ThemeProvider> <ReactQueryDevtools initialIsOpen={false} /> </QueryClientProvider> </PersistGate> </Provider> ); } export default App;

개발자

#next.js

#persis

#redux

답변 1

댓글 0

조회 570

2년 전 · 익명 님의 질문

애저 함수 앱 배포시 에러

Deployment Log file does not exist in /tmp/oryx-build.log 에러가 뜨고 배포에 실패합니다 로컬 테스트시 결과값잘나오는데 배포만 수행하면 에러가납니다 <requirements.txt> azure-functions openai Pillow regex transformers==4.33.0 nltk==3.8.1 torch==2.0.0

개발자

#azure

#pytorch

#openai

#배포

#클라우드

답변 0

댓글 0

조회 28

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

자바스크립트 객체 생성 방식 질문 드립니다.

안녕하세요, 저는 현재 자바스크립트 Deep Dive라는 책을 독학하고 있습니다. 클로저 예제(24-13)와 관련해 이해가 다소 어려운 부분이 있어 질문글을 작성하게 되었습니다. const Counter = (function() { let num = 0; function Counter() { } Counter.prototype.increase = function () { return ++num; } Counter.prototype.decrease = function () { return num > 0 ? --num : 0; } return Counter; })(); 여기서 객체의 생성 방식에 따른 동작 방식에 대한 의문이 있습니다. 1. 생성자 호출 const counter = new Counter(); // Counter {} new 연산자와 함께 호출하면 return 문의 유무와 관계 없이 Counter 객체가 생성되는 점은 이해했습니다. 2. 일반 호출 const counter =Counter(); // undefined 위 경우 명시적으로 return Counter를 반환하고 있음에도, undefined가 콘솔에 출력되는 이유가 궁금합니다. chatGPT에 문의했더니 답변이 오락가락해 혼란이 가중되네요.. 지식 나눔에 미리 감사드립니다.

개발자

#javascript

#클로저

#즉시실행함수

답변 2

댓글 1

조회 94

2년 전 · 김인후 님의 새로운 답변

js callback함수란?

fs.readFile(파일명,'utf8', function(err, data){}) 이런식의 비동기함수를 처리하는 callback함수가 있다고 할때 질문이 두가지가 있습니다. 1. 첫번째는 error고 두번째는 무조건 data가 오도록 한건 fs.readFile을 만든 개발자 마음인거죠? 이건 제가 변경할 수 없죠? 2. 위의 함수는 파일이 제대로 읽어질때까지(파일이 없다면 안읽어질때까지) 기다렸다가 callback 함수가 실행될텐데요. 대체 내부적으로 어떻게 구현이 되어있길래. 기다려주는건가요? 당연히 setTimeout을 쓰진 않겠지만, 내부적으로 setTimeout처럼 뭔가를 기다려주게 코드를 짜놓은건가요?

개발자

#javascript

답변 1

댓글 0

조회 56

2년 전 · 방재호 님의 새로운 답변

안녕하세요 Emotion 컴포넌트 관련해서 질문있습니다 ! (어느방식이 괜찮은 방식일까요?)

안녕하세요 ! 팀원과 Emotion으로 컴포넌트 작업을 하는데 스타일이 서로 달라서 갑자기 궁금해졌는데.... 아래의 두가지 방식중 어느 방식이 더 괜찮은 방식인지 궁금해서 질문 남깁니다 ! 1. @emotion/styled 활용 const Component = styled.div` background-color: blue; color: white; ` export default function Badge({ text }: any) { return <Badge>{text}</Badge> } 2. @emotion/react 활용 const badgeStyles = css` background-color: blue; color: white; ` export default function Badge({ text }:any) { return <div css={css([badgeStyles])} >{text}</div> } 이렇게 간단하게 두가지 예시를 적어봤습니다 ! 읽어주셔서 감사합니다 :)

개발자

#react

#emotion

#css

답변 1

댓글 0

조회 73

2년 전 · 익명 님의 질문

documentFragment를 활용하여 리팩토링 하였지만 오히려 속도가 더 느려졌네요. 원인이 궁금합니다.

<select></select> <select></select> <select></select> ... var targetArr = document.querySelectorAll("select"); var optionArr = [ {CODE_NAME: "one", CODE_ID: 1}, {CODE_NAME: "two", CODE_ID: 2}, ... ]; 이런 환경에서 optionArr을 가지고 모든 select에 option을 넣어주려고 합니다. 기존 소스 : targetArr.forEach(function(target) { optionArr.forEach(function(item) { var option = document.createElement("option") option.setAttribute("value", item.CODE_ID); option.innerText = item.CODE_NAME; target.append(option); }); }); 변경 소스 : var fragment = document.createDocumentFragment(); var option = document.createElement("option"); optionArr.forEach(function(item) { var cloneOption = option.cloneNode(); cloneOption.setAttribute("value", item.CODE_ID); cloneOption.innerText = item.CODE_NAME; fragment.append(cloneOption); }); targetArr.forEach(function(target) { target.append(fragment.cloneNode(true)); }); 이렇게 O(nm)으로 동작하던 기존 소스를 O(n)으로 변경하였고 더하여 직접 DOM을 조작하기 보다 documentFragment를 활용하였으니 더 빨라질 것으로 예상하였으나 더욱 느리게 나오더라구요. cloneNode가 문제인 건지... 이유를 모르겠습니다. 알려주시면 감사하겠습니다.

개발자

#javascript

답변 0

댓글 0

조회 48

2년 전 · 털먹는토끼 님의 새로운 댓글

next.js 특정 페이지에 컴포넌트 미출력 기능 구현 이슈(use client 사용)

로그인페이지(/user-page)에서 footer컴포넌트를 안띄우는 기능을 구현하고 싶어 footer 컴포넌트를 csr 방식으로 사용하도록 'use client' 줬습니다. 근데 error ReferenceError: window is not defined 라는 에러가 뜨면서 적용이 안되네요ㅠㅠ nextjs는 ssr이니까 window에 접근하기 위해선 'use client'를 주면 된다고 들었는데 왜 안되는걸까요?? 찾아보니까 useEffect 쓰라해서 useEffect도 써봤는데 에러가 뜨진않지만 여전히 적용안되더라구요. 문제점 알려주시면 감사하겠습니다ㅠㅠㅠ <footer.tsx 파일> 'use client' import React, { useEffect } from 'react' import style from '../styles/footer.module.scss' const Footer = () => {     if (window.location.pathname === '/user-page') return null return ( -생략- ) } <루트 layout.tsx 파일> 'use client' export default function RootLayout({     children, }: {     children: React.ReactNode }) {   return (         <html lang="ko">             <body className={inter.className}>                 <div className="wrap bg-white">                     <Header />                     {children}                     <Footer />               </div>             </body>         </html>     ) }

개발자

#next.js

답변 3

댓글 3

조회 372

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

조회 338

2년 전 · 이영준 님의 새로운 답변

리액트 컴포넌트 설계에 대해 질문이 있습니다.

현재 Dropdown 컴포넌트를 compound pattern을 접목하여 구현을 해보고있습니다. ChatRoomHeader 라는곳에있는 DotsIcon을 클릭하면 Dropdown이 랜더링되게끔 구현을 하였는데요. 각 메뉴 리스트들을 배열로 해서 map을 사용하여 렌더링해주고있습니다. 제가 생각하는 문제점은 Dropdown안에 있는 로직들이 뭔가 전혀 상관없는곳에서 정의하고 props로 내려주는것에대해서 약간 문제점이 있어보이는것같습니다.. 혹시 다른방법이 있을까요? 아니면 참고할만한 블로그 알려주시면 감사하겠습니다 (__) 'use client'; import Link from 'next/link'; import ArrowLeftIcon from '@/public/arrow-left.svg'; import FlexBox from '@/components/ui/FlexBox'; import DotsIcon from '@/public/tabler_dots.svg'; import Dropdown from '@/components/ui/Dropdown/Dropdown'; import Divider from '@/components/ui/Divider'; export default function ChatRoomHeader({ title }: { title: string }) { const copyToClipboard = async () => { try { await navigator.clipboard.writeText(window.location.href); alert('복사 성공'); } catch { alert('복사 실패'); } }; const CHAT_ROOM_OPTIONS = [ { name: '공지', }, { name: '사진', }, { name: '링크' }, { name: '공유하기', event: copyToClipboard }, { name: '채팅방 나가기' }, ]; return ( <FlexBox as="header" justify="between" align="center" className=" p-8 h-14 tablet:h-24 w-full gap-4 bg-white border-b-[1px]" > <FlexBox className="gap-1"> <Link href="/community"> <ArrowLeftIcon className="w-7 h-7" /> </Link> <p className="text-xl font-bold">{title}</p> </FlexBox> <Dropdown> <Dropdown.Trigger> <DotsIcon className="w-6 h-6 tablet:w-7 tablet:h-7" /> </Dropdown.Trigger> <Dropdown.Menu> <li className="block tablet:hidden"> <Dropdown.Item>인원</Dropdown.Item> <Dropdown.Item>스케줄</Dropdown.Item> <Divider type="horizontal" /> </li> {CHAT_ROOM_OPTIONS.map((option) => ( <Dropdown.Item key={option.name} event={option.event}> {option.name} </Dropdown.Item> ))} </Dropdown.Menu> </Dropdown> </FlexBox> ); }

개발자

#react

답변 3

댓글 1

추천해요 2

조회 1,078

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

JavaScript 질문-for 루프와 전역 변수 관련

``` var func = []; // 함수의 배열을 생성하는 for 루프의 i는 전역 변수다. for (var i = 0; i < 3; i++) { func.push(function () { console.log(i); }); } console.log(func); // 배열에서 함수를 꺼내어 호출한다. for (var j = 0; j < 3; j++) { func[j](); } /* 실행결과: [Log] Array (3) => "console.log(func);" 0 function () { console.log(i); } 1 function () { console.log(i); } 2 function () { console.log(i); } [Log] 3(3)=> "for (var j = 0; j < 3; j++) { func[j](); }" 3 3 3 */ ``` 자바스크립트 클로저를 공부하다가 이해가 되지 않는 부분이 있어서 질문을 남깁니다. 첫 번째 for 루프에서 func 배열에 인덱스 숫자를 콘솔에 출력하는 함수를 순차적으로 집어넣는 로직을 작성해서 두 번째 for 루프에서 그것을 호출시키는 로직을 작성했는데 '0, 1, 2'가 아니라 보기와 같이 '3, 3, 3' 이렇게 출력되었습니다. 이렇게 출력되는 원인을 찾아봤더니 첫 번째 for 루프에 선언된 초기식 변수 var i가 전역 변수이기 때문이라는 설명이 있었습니다. 그러면 'var i'의 변수값이 두 번째 for 루프의 초기식인 var j에 영향을 미쳤다는 얘기로 보면 되는건가요?

개발자

#javascript

답변 1

댓글 0

조회 151

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

조회 238