묻고 답해요
148만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Slack 클론 코딩[실시간 채팅 with React]
setSignUpError(error.response.data);에 data 가 TypeError: Cannot read properties of undefined (reading 'data')라고 뜹니다.
setSignUpError(error.response.data);이 부분의 data에 typeerror가 뜹니다.왜 뜨는지 검색을 해봐도 모르겠어서 질문 남깁니다.
-
미해결Slack 클론 코딩[실시간 채팅 with React]
안읽은메세지 표시
안녕하세요 제로초님mutate(0)으로 했는데도 콘솔찍어보니까 다시 1로 변합니다channel부분만 이러네요
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
npm i typescript 충돌 오류
npm i typescript 작성 시 아래와 같은 오류가 뜹니다. 종속성 해결 과정에서 충돌이 발생한 것으로 보이는데, 여기서 --force를 해서 설치를 하면 실행 될 것 같긴한데 그렇게 했을때는 결국 문제가 터졌던 경험들이 있어서 어떻게 하면 되는지 잘 모르겠습니다./c/02WorkSpace/sleact/alecture (master)$ npm i typescriptnpm ERR! code ERESOLVEnpm ERR! ERESOLVE could not resolvenpm ERR!npm ERR! While resolving: react-custom-scrollbars@4.2.1npm ERR! Found: react@17.0.2npm ERR! node_modules/reactnpm ERR! peer react@">=16.8.0" from @emotion/react@11.10.6npm ERR! node_modules/@emotion/reactnpm ERR! peer @emotion/react@"^11.0.0-rc.0" from @emotion/styled@11.10.6npm ERR! node_modules/@emotion/stylednpm ERR! @emotion/styled@"^11.1.5" from the root projectnpm ERR! @emotion/react@"^11.1.5" from the root projectnpm ERR! peer react@">=16.8.0" from @emotion/styled@11.10.6npm ERR! node_modules/@emotion/stylednpm ERR! @emotion/styled@"^11.1.5" from the root projectnpm ERR! 10 more (@emotion/use-insertion-effect-with-fallbacks, ...)npm ERR!npm ERR! Could not resolve dependency:npm ERR! peer react@"^0.14.0 || ^15.0.0 || ^16.0.0" from react-custom-scrollbars@4.2.1npm ERR! node_modules/react-custom-scrollbarsnpm ERR! react-custom-scrollbars@"^4.2.1" from the root projectnpm ERR!npm ERR! Conflicting peer dependency: react@16.14.0 npm ERR! node_modules/reactnpm ERR! peer react@"^0.14.0 || ^15.0.0 || ^16.0.0" from react-custom-scrollbars@4.2.1npm ERR! node_modules/react-custom-scrollbars npm ERR! react-custom-scrollbars@"^4.2.1" from the root projectnpm ERR!npm ERR! Fix the upstream dependency conflict, or retrynpm ERR! this command with --force or --legacy-peer-depsnpm ERR! to accept an incorrect (and potentially broken) dependency resolution.npm ERR!npm ERR!npm ERR! For a full report see:npm ERR! C:\Users\KG.Park\AppData\Local\npm-cache\_logs\2023-05-16T00_56_02_463Z-eresolve-report.txtnpm ERR! A complete log of this run can be found in:
-
미해결Slack 클론 코딩[실시간 채팅 with React]
데이터 초기화 후
안녕하세요 제로초님 이미지가 안들어가져서 데이터를 삭제하고 다시 만들었는데 갑자기 잘되던것들이 이렇게 오류가 계속뜨네요. 아래는 현재 데이터 테이블들입니다
-
미해결Slack 클론 코딩[실시간 채팅 with React]
SWR Devtools 강의중
안녕하세요 제로초님 npm 사이트에서 devtools 보니까cache하고 mutate가 사라져있는데 swr하고 swr-devtools 버전을 강의하고 일치시키면 mutate 만되고 cache가 안됩니다!
-
미해결Slack 클론 코딩[실시간 채팅 with React]
안읽은메세지 개수 표시하기
안녕하세요 제로초님 디엠부분에서는 안읽은 메시지 표시가 떠서 읽으면 없어지는데채널부분에서는 없어지지않고 남아있습니다!
-
미해결Slack 클론 코딩[실시간 채팅 with React]
이미지 드래그 업로드하기 강의중
안녕하세요 제로초님Dm에서는 이미지가 드래그업로드가 되는데채널에서는 500에러가 뜹니다!백엔드코드 최신버전인데 바꿔야할것이 있나요?POST http://localhost:3095/api/workspaces/sleact/dms/%EC%9D%BC%EB%B0%98/images 500 (Internal Server Error)Error at Query.run (/Users/js/Desktop/sleact/back/node_modules/sequelize/lib/dialects/mysql/query.js:52:25) at /Users/js/Desktop/sleact/back/node_modules/sequelize/lib/sequelize.js:314:28 at process.processTicksAndRejections (node:internal/process/task_queues:95:5) at async MySQLQueryInterface.insert (/Users/js/Desktop/sleact/back/node_modules/sequelize/lib/dialects/abstract/query-interface.js:308:21) at async DM.save (/Users/js/Desktop/sleact/back/node_modules/sequelize/lib/model.js:2432:35) at async DM.create (/Users/js/Desktop/sleact/back/node_modules/sequelize/lib/model.js:1344:12) at async /Users/js/Desktop/sleact/back/routes/api.js:522:20 POST /api/workspaces/sleact/dms/%EC%9D%BC%EB%B0%98/images 500 7.558 ms - 898
-
미해결Slack 클론 코딩[실시간 채팅 with React]
로그인 회원가입 둘다 cors 오류가 뜹니다 ㅠㅠ 도대체 뭐가 문제일까요..
안녕하세요~ 그전까지 잘되다가 오랜만에 다시 강의를 이어가려고하는데 갑자기 안됩니다 ㅠㅠ 뭐가 문제일까요..회원가입시에도 페이지가 넘어가지않고 계속 CORS 오류가 생기네요.. https://github.com/nuring9/react-SWR-SlackClone_front제가 따라한 코드 깃허브 주소올립니다 ㅠㅠ
-
미해결Slack 클론 코딩[실시간 채팅 with React]
SWR DevTools 관련
안녕하세요 SWR관련 질문이 있습니다.혹시 React 18버전에서는 SWR DevTools를 어떻게 사용할 수 있는지 부탁 드립니다.감사합니다.
-
미해결Slack 클론 코딩[실시간 채팅 with React]
채팅보내기 강의중
안녕하세요 제로초님!채팅보내기 강의를 보고있는데 workspace/index.tsx에서갑자기 socket 코드 가생겼는데 강의에는 설명이 없는거 같아서 문의 남깁니다!
-
미해결Slack 클론 코딩[실시간 채팅 with React]
str.toLowerCase is not a function
예상하지 못한 부분에서 에러가 나와서 질문 남겨드립니다 !ChatBox.tsximport React, { useCallback, useEffect, useRef, VFC } from 'react'; import { ChatArea, EachMention, Form, MentionsTextarea, SendButton, Toolbox } from './styles'; import autosize from 'autosize'; import { Mention, SuggestionDataItem } from 'react-mentions'; import { useParams } from 'react-router'; import useSWR from 'swr'; import { IUser } from '@typings/db'; import fetcher from '@utils/fetcher'; import gravatar from 'gravatar'; interface Props { chat: string; onSubmitForm: (e: any) => void; onChangeChat: (e: any) => void; placeholder?: string; } const ChatBox: VFC<Props> = ({ chat, onSubmitForm, onChangeChat, placeholder }) => { const { workspace } = useParams<{ workspace: string }>(); const { data: userData, error, revalidate, mutate, } = useSWR<IUser | false>('/api/users', fetcher, { dedupingInterval: 2000, // 2초 }); const { data: memberData } = useSWR<IUser[]>(userData ? `/api/workspaces/${workspace}/members` : null, fetcher); const textareaRef = useRef<HTMLTextAreaElement>(null); useEffect(() => { if (textareaRef.current) { autosize(textareaRef.current); } }, []); const onKeydownChat = useCallback( (e) => { if (e.key === 'Enter') { if (!e.shiftKey) { e.preventDefault(); onSubmitForm(e); } } }, [onSubmitForm], ); const renderSuggestion = useCallback( ( suggestion: SuggestionDataItem, search: string, highlightedDisplay: React.ReactNode, index: number, focus: boolean, ): React.ReactNode => { if (!memberData) return; return ( <EachMention focus={focus}> <img src={gravatar.url(memberData[index].email, { s: '20px', d: 'retro' })} alt={memberData[index].nickname} /> <span>{highlightedDisplay}</span> </EachMention> ); }, [memberData], ); return ( <ChatArea> <Form onSubmit={onSubmitForm}> <MentionsTextarea id="editor-chat" value={chat} onChange={onChangeChat} onKeyPress={onKeydownChat} placeholder={placeholder} inputRef={textareaRef} allowSuggestionsAboveCursor > <Mention appendSpaceOnAdd trigger="@" data={memberData?.map((v) => ({ id: v.id, display: v.nickname })) || []} renderSuggestion={renderSuggestion} /> </MentionsTextarea> <Toolbox> <SendButton className={ 'c-button-unstyled c-icon_button c-icon_button--light c-icon_button--size_medium c-texty_input__button c-texty_input__button--send' + (chat?.trim() ? '' : ' c-texty_input__button--disabled') } data-qa="texty_send_button" aria-label="Send message" data-sk="tooltip_parent" type="submit" disabled={!chat?.trim()} > <i className="c-icon c-icon--paperplane-filled" aria-hidden="true" /> </SendButton> </Toolbox> </Form> </ChatArea> ); }; export default ChatBox;혼자서 해결해보려다가 못찾고 있어서 질문 남겨드려요 ㅠㅠ
-
미해결Slack 클론 코딩[실시간 채팅 with React]
데이터 질문이요
const onSubmitForm = useCallback( (e) => { e.preventDefault(); if (chat?.trim() && chatData) { const savedChat = chat; mutateChat((prevChatData) => { prevChatData?.[0].unshift({ id: (chatData[0][0]?.id || 0) + 1, content: savedChat, SenderId: myData.id, Sender: myData, ReceiverId: userData.id, Receiver: userData, createdAt: new Date(), }); return prevChatData; }, false).then(() => { localStorage.setItem(`${workspace}-${id}`, new Date().getTime().toString()); setChat(''); if (scrollbarRef.current) { console.log('scrollToBottom!', scrollbarRef.current?.getValues()); scrollbarRef.current.scrollToBottom(); } }); axios .post(`/api/workspaces/${workspace}/dms/${id}/chats`, { content: chat, }) .then(() => console.log('first')) .catch(console.error); } }, [chat, workspace, id, myData, userData, chatData, mutateChat, setChat], ); const onMessage = useCallback( (data: IDM) => { if (data.SenderId === Number(id) && myData.id !== Number(id)) { mutateChat((chatData) => { chatData?.[0].unshift(data); return chatData; }, false) 이부분은 socket?.on('dm', onMessage) dm보내는 페이지에서 디엠을 보낼 때 onSubmitForm에서 mutate가 먼저 실행돼서 화면 데이터를 먼저 바꿔주고 그 다음 서버로 데이터를 보낸 뒤 처리하는 과정에서 socket.emit()이 실행되고 onMessage가 실행되는 걸로 이해했는데요. onMessage가 받는 데이터가 onSumbitForm의 mutate가 인자로 받는 함수랑 똑같아서 중복작업이 아닌가 싶어서 onMessage mutate 안의 chat.Data?.[0].unshift(data)를 지우고 실행해봐도 똑같은 결과가 나오는데 이 코드는 왜 있는 건가요?
-
미해결Slack 클론 코딩[실시간 채팅 with React]
DM 내용 표시하기
안녕하세요 강의중에 DM 내용 표시 하기 강의에서 map을 활용해 DM내용을 표시하는 부분인데 DM을 클릭하고 내용을 확인할 때 TypeError에러가 뜨면서 chatData.map is not a function 이라는 오류가 나오고 있습니다.. 혼자 해결하다 막혀서 질문 남겨 드립니다! DirectMessage.tsx (return 부분)return ( <Container> <Header> <img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nicknam} /> <span>{userData.nickname}</span> </Header> <ChatList chatData={chatData} /> <ChatBox chat={chat} onChangeChat={onChangeChat} onSubmitForm={onSubmitForm} /> </Container> );chatList.tsximport React, { VFC, useCallback, useRef } from 'react'; import { ChatZone } from './styles'; import { IDM } from '@typings/db'; import Chat from '@components/Chat'; import { Scrollbars } from 'react-custom-scrollbars'; interface Props { chatData?: IDM[]; } const ChatList: VFC<Props> = ({ chatData }) => { const scrollbarRef = useRef(null); const onScroll = useCallback(() => {}, []); return ( <ChatZone> <Scrollbars autoHide ref={scrollbarRef} onScrollFrame={onScroll}> {chatData?.map((chat) => ( <Chat key={chat.id} data={chat} /> ))} </Scrollbars> </ChatZone> ); }; export default ChatList; chat.tsximport { IDM, IChat } from '@typings/db'; import React, { VFC, memo, useMemo } from 'react'; import gravatar from 'gravatar'; import { ChatWrapper } from './styles'; interface Props { data: IDM; } const Chat: VFC<Props> = ({ data }) => { const user = data.Sender; return ( <ChatWrapper> <div className="chat-img"> <img src={gravatar.url(user.email, { s: '36px', d: 'retro' })} alt={user.nickname} /> </div> <div className="chat-text"> <div className="chat-user"> <b>{user.nickname}</b> <span>{data.createdAt}</span> </div> <p>{data.content}</p> </div> </ChatWrapper> ); }; export default Chat;오류내용
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
웹소켓은 프록시 사용 할 수 없나요?
`http://localhost:3095/ws-${workspace}`위 주소로는 잘 되는데 `/api/ws-${workspace}`로는 연결이 안됩니다. 웹소켓은 프록시 못쓰는건지,못쓴다면 혹시 왜 안되는건지 이유를 여쭈워도 괜찮을까요?
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
Scss문법
styles.tsx파일을 보면& img {...}& > div {...}이렇게 있던데 '>' 기호가 있고 없고의 차이점은 뭔가요?
-
미해결Slack 클론 코딩[실시간 채팅 with React]
chat box가 위에 고정되어 있습니다.
DirectMessageimport React, { useCallback, useState } from 'react'; import gravatar from 'gravatar'; import { Container } from 'semantic-ui-react'; import { Header } from './styles'; import useSWR from 'swr'; import { useParams } from 'react-router'; import fetcher from '@utils/fetcher'; import ChatBox from '@components/ChatBox'; import useInput from '@hooks/useinput'; import axios from 'axios'; import { IDM } from '@typings/db'; import ChatList from '@components/ChatList'; const DirectMessage = () => { const { workspace, id } = useParams<{ workspace: string; id: string }>(); const { data: userData } = useSWR(`/api/workspaces/${workspace}/users/${id}`, fetcher); const { data: myData } = useSWR('/api/users', fetcher); const { data: chatData, mutate: mutateChat, revalidate, } = useSWR<IDM[]>(`/api/workspace/${workspace}/dms/${id}/chats?perPage=20&page=1`, fetcher); const [chat, onChangeChat, setChat] = useInput(''); const onSubmitForm = useCallback( (e) => { e.preventDefault(); console.log('chat'); if (chat?.trim()) { axios .post(`/api/workspaces/${workspace}/dms/${id}/chats`, { content: chat, }) .then(() => { revalidate(); setChat(''); }) .catch(console.error); } }, [chat], ); if (!userData || !myData) { return null; } return ( <Container> <Header> <img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nicknam} /> <span>{userData.nickname}</span> </Header> <ChatList chatData={chatData} /> <ChatBox chat={chat} onChangeChat={onChangeChat} onSubmitForm={onSubmitForm} /> </Container> ); }; export default DirectMessage;ChatListimport React, { VFC } from 'react'; import { ChatZone, Section } from './styles'; import { IDM } from '@typings/db'; import Chat from '@components/Chat'; interface Props { chatData?: IDM[]; } const ChatList: VFC<Props> = ({ chatData }) => { return ( <ChatZone> {chatData?.map((chat) => { <Chat key={chat.id} data={chat} />; })} </ChatZone> ); }; export default ChatList; 보여드린 코드처럼 chatbox 중간에 chatlist를 넣게 되면 자동으로 아래로 내려갈 수 있게 했습니다.말씀대로 chatlist를 만들고 directmessage사이에 chatlist를 import 했습니다. 그런데 아래로 내려오지 않고 상단으로 그대로 고정되어 있어서 아무리 찾아보려고 해도 답이 안나오는거 같아 질문 남겨드립니다 ㅠ
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
영상 5:20 설명 질문
실패하면 then의 revalidate때문에 원래 있던 데이터가 사라진다고 하셨는데 따로 catch부분에서 처리해줘야 이전에 넣어뒀던 가짜 데이터를 삭제하는 등 처리되는 거 아닌가요?
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
useSWRInfinite에서 index질문
const { data: chatData, mutate, setSize, } = useSWRInfinite<IDM[]>( (index) => `/api/workspaces/${workspace}/dms/${id}/chats?perPage=20&page=${index + 1}`, fetcher, );setSize에서 prevSize +1이 1페이지 더 불러오는 거면 useSWRInfinite에서 index +1은 뭔 역할이죠? 둘 다 페이지 관련된거라 헷갈립니다.
-
해결됨Slack 클론 코딩[실시간 채팅 with React]
[Tip] NAS와 같이 외부의 DB에 연결하는 경우
Environment- Synology NAS - code-server - MySQL(mariaDB) - Node.js@latest | v18.16.0 - npm@latest | v9.5.1 - nvm@latest | v0.39.3sequelize 사용 시, 로컬이 아닌 외부 DB에 연결하는 경우저 같은 경우, Synology NAS로 code-server를 사용하고 있습니다. 저와 비슷한 환경에서 개발하시는 경우, 포트 설정에 애먹으시는 분 있을까봐 메모 납깁니다.db의 port를 방화벽에서 해제하기해당 포트 포트포워딩(공유기)참고로, phpMyAdmin이나 WorkBench에서 외부 DB에 접근이 가능한데, squelize로 접근하면 ERROR: connect ETIMEDOUT과 같은 메시지가 출력되는 경우가 있는데, 저는 아래 방법으로 해결할 수 있었습니다.(위 에러메시지는 host는 찾았지만 DB를 찾지 못했거나, DB가 있어도 접근할 수 없을 때 출력된다고 합니다.){ "development": { "username": "slackk", "password": process.env.DB_PASSWORD, "database": "slack-db", "host": "***.***.***.***", //IP "port": 3307, //source|target 다를 경우 별도로 지정 "dialect": "mysql" } }port를 별도로 지정해주어야 합니다. ERROR: getaddrinfo ENOTFOUND {IP address} 메시지가 출력되는 경우host에 입력한 주소 문제입니다.
-
미해결Slack 클론 코딩[실시간 채팅 with React]
로그인 성공시 /workspace/channel 로 이동이 안되고 있습니다.
App.tsximport React, { FC } from 'react'; import loadable from '@loadable/component'; import { Switch, Route, Redirect } from 'react-router'; const Login = loadable(() => import('@pages/Login')); const SignUp = loadable(() => import('@pages/SignUp')); const Channel = loadable(() => import('@pages/Channel')); const App: FC = () => { return ( <Switch> <Redirect exact path="/" to="/login" /> <Route path="/login" component={Login} /> <Route path="/signUp" component={SignUp} /> <Route path="/workspace/channel" component={Channel} /> </Switch> ); }; export default App; Login/ index.tsximport React, { useState, useCallback } from 'react'; import useInput from '@pages/hooks/useinput'; import axios from 'axios'; import { Error, Form, Label, Input, LinkContainer, Button, Header } from '@pages/SignUp/styles'; import { Link, Redirect } from 'react-router-dom'; import useSWR from 'swr'; import fetcher from '@utils/fetcher'; const Login = () => { const { data, error, revalidate } = useSWR('http://localhost:3095/api/users', fetcher); //주소를 fetcher로 옮겨주고 실제로 주소를 어떻게 처리할지 정해줌 const [logInError, setLogInError] = useState(false); const [email, onChangeEmail] = useInput(''); const [password, onChangePassword] = useInput(''); const onSubmit = useCallback( (e) => { e.preventDefault(); setLogInError(false); axios .post( 'http://localhost:3095/api/users/login', { email, password }, { withCredentials: true, }, ) .then(() => { revalidate(); }) .catch((error) => { setLogInError(error.response?.data?.statusCode === 401); }); }, [email, password], ); if (data) { return <Redirect to="/workspace/channel" />; }Channel / index.tsximport Workspace from '@layouts/Workspace'; import React from 'react'; const Channel = () => { return ( <Workspace> <div>로그인을 축하합니다.</div> </Workspace> ); }; export default Channel; Workspace.tsximport React, { FC, useCallback } from 'react'; import useSWR from 'swr'; import fetcher from '@utils/fetcher'; import axios from 'axios'; import { Redirect } from 'react-router'; const Workspace: FC = ({ children }) => { const { data, error, revalidate } = useSWR('http://localhost:3095/api/users', fetcher); const onLogout = useCallback(() => { axios .post('http://localhost:3095/api/users/logout', null, { withCredentials: true, }) .then(() => { revalidate(); }); }, []); if (!data) { return <Redirect to="/login" />; } return ( <div> <button onClick={onLogout}>로그아웃</button> {children} </div> ); }; export default Workspace; 현재 코드에서 로그인 성공까지 되는데 페이지 이동이 없습니다... 하나하나 빠짐없이 확인 해봤는데 제가 찾지 못하는거 같습니다 ㅠㅠ더군다나 URl 주소를 다이렉트로 localhost:3090/workspace/channel 입력해도 아무런 창이 뜨지 않고 있어서 어떤 문제가 있는지 확인이 어렵습니다.. 도움을 부탁드려요