39,600원
다른 수강생들이 자주 물어보는 질문이 궁금하신가요?
- 미해결Slack 클론 코딩[실시간 채팅 with React]
front 폴더에서 yarn 설치 후 yarn dev 오류
맥북을 사용하기에 front 폴더에 yarn 설치 후, yarn dev를 하면 아래의 사진처럼 Type 'React.ReactNode' is not assignable to type {}. React.ReactNode오류가 뜹니다. setting 폴더에서 yarn 설치 후, yarn dev를 하면 정상적으로 작동합니다.(둘 다 똑같이 back 폴더에서 yarn run dev로 서버 가동은 해놓은 상태입니다)1번 에러2번 에러3번 에러총 이렇게 3개의 에러가 나오는 상황입니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
back 디렉토리에서 npm install시 node-gyp 에러가 발생합니다.
결론: 꼼꼼히 질문하려고 글을 작성하다가 문제를 해결했습니다. 하지만 질문이 있어서 마저 남깁니다 :)운영체제: macOS(Ventura 13.0.1)Node.js 버전(node -v): v16.16.0수강중인 강좌: '1강 sleact 강좌 소개 및 기본 세팅'진행상황: git clone이후, back 디렉토리로 이동했습니다.에러발생: npm install시 node-gyp 에러발생합니다.에러내용npm ERR! code 1 npm ERR! path /Users/jakinkim/Desktop/study/sleact/back/node_modules/bcrypt npm ERR! command failed npm ERR! command sh -c node-gyp rebuild npm ERR! gyp info it worked if it ends with ok npm ERR! gyp info using node-gyp@9.0.0 npm ERR! gyp info using node@16.16.0 | darwin | arm64 npm ERR! gyp info find Python using Python version 3.9.6 found at "/Library/Developer/CommandLineTools/usr/bin/python3" npm ERR! gyp info spawn /Library/Developer/CommandLineTools/usr/bin/python3 npm ERR! gyp info spawn args [ npm ERR! gyp info spawn args '/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/gyp/gyp_main.py', npm ERR! gyp info spawn args 'binding.gyp', npm ERR! gyp info spawn args '-f', npm ERR! gyp info spawn args 'make', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/Users/jakinkim/Desktop/study/sleact/back/node_modules/bcrypt/build/config.gypi', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/addon.gypi', npm ERR! gyp info spawn args '-I', npm ERR! gyp info spawn args '/Users/jakinkim/Library/Caches/node-gyp/16.16.0/include/node/common.gypi', npm ERR! gyp info spawn args '-Dlibrary=shared_library', npm ERR! gyp info spawn args '-Dvisibility=default', npm ERR! gyp info spawn args '-Dnode_root_dir=/Users/jakinkim/Library/Caches/node-gyp/16.16.0', npm ERR! gyp info spawn args '-Dnode_gyp_dir=/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp', npm ERR! gyp info spawn args '-Dnode_lib_file=/Users/jakinkim/Library/Caches/node-gyp/16.16.0/<(target_arch)/node.lib', npm ERR! gyp info spawn args '-Dmodule_root_dir=/Users/jakinkim/Desktop/study/sleact/back/node_modules/bcrypt', npm ERR! gyp info spawn args '-Dnode_engine=v8', npm ERR! gyp info spawn args '--depth=.', npm ERR! gyp info spawn args '--no-parallel', npm ERR! gyp info spawn args '--generator-output', npm ERR! gyp info spawn args 'build', npm ERR! gyp info spawn args '-Goutput_dir=.' npm ERR! gyp info spawn args ] npm ERR! gyp: Undefined variable module_name in binding.gyp while trying to load binding.gyp npm ERR! gyp ERR! configure error npm ERR! gyp ERR! stack Error: `gyp` failed with exit code: 1 npm ERR! gyp ERR! stack at ChildProcess.onCpExit (/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/lib/configure.js:261:16) npm ERR! gyp ERR! stack at ChildProcess.emit (node:events:527:28) npm ERR! gyp ERR! stack at Process.ChildProcess._handle.onexit (node:internal/child_process:291:12) npm ERR! gyp ERR! System Darwin 22.1.0 npm ERR! gyp ERR! command "/usr/local/bin/node" "/opt/homebrew/lib/node_modules/npm/node_modules/node-gyp/bin/node-gyp.js" "rebuild" npm ERR! gyp ERR! cwd /Users/jakinkim/Desktop/study/sleact/back/node_modules/bcrypt npm ERR! gyp ERR! node -v v16.16.0 npm ERR! gyp ERR! node-gyp -v v9.0.0 npm ERR! gyp ERR! not ok npm ERR! A complete log of this run can be found in: npm ERR! /Users/jakinkim/.npm/_logs/2022-12-12T13_05_39_462Z-debug-0.log시도해본 내용// node-gyp 설치 npm install -g node-gyp // 설치된 node-gyp 경로찾기 npm root -g node-gyp // 위에서 찾은 경로로 셋팅 npm config set node_gyp /opt/homebrew/lib/node_modules // python 의존성 구성 npm config set python /path/to/executable/python // 프로젝트 build 파일 생성 node-gyp configure // 기존에 설치된 node_modules 및 package-lock.json 삭제 rm -rf node_modules rm package-lock.json // npm update 및 npm install npm update npm install질문1) 여러 명령들을 실행해봤지만 정확하게 어떤 명령 덕분에 해결이 됐는지 이해가 안됩니다.2) npm configure을 해서 back 디렉토리에 build 파일이 생성된 것인지, npm install을 해서 build 파일이 생성된 것인지 애매합니다.(제가 생각하는)에러발생 원인: macOS에서 window등 다른 환경의 git파일을 clone할 때 문제가 발생하는 것 같습니다. 그리고 업데이트 문제인 것 같기도 합니다.찾아본 내용node-gyp - Node.js native addon build tool(https://www.npmjs.com/package/node-gyp)Installation notes for macOS Catalina (v10.15)(https://github.com/nodejs/node-gyp/blob/HEAD/macOS_Catalina.md)npm ERR! code 1 - when npm install #2682(https://github.com/nodejs/node-gyp/issues/2682)npm install with error: gyp failed with exit code: 1(https://velog.io/@minho100227/npm-install-with-error-gyp-failed-with-exit-code-1)Writing Native Node.js Modules(https://blog.risingstack.com/writing-native-node-js-modules/)C++ addons(https://nodejs.org/api/addons.html)
- 미해결Slack 클론 코딩[실시간 채팅 with React]
회원가입 페이지 모달관련 질문
회원가입 페이지를 구현하면서 실패시 SignupError를 모달에 props로 전달하려고합니다.근데 다음과 같이 모달에서 바인딩 요소 'string'은 암시적으로 'any' 유형을 가진다고 에러가 발생하는데해당 이유에 대해서 궁금해 질문드립니다.참고자료 함께 첨부하겠습니다. pages/signupconst [signupError, setSignupError] = useState(''); axios .post('/api/users', { email, nickname, password, }) .then(response => { console.log(response); setSignupSuccess(true); }) .catch(error => { console.log(error.response); setSignupError(error.response.data); }); console.log(email, nickname, password); } {signupError && <Error error={signupError} />} components/modalimport React from 'react'; const Modal = ({ error: string }) => { return ( <ModalWrapper> <header>Error!</header> <div>{error}</div> <ModalBtn>확인</ModalBtn> </ModalWrapper> ); }; export default Modal; 에러 로그
- 미해결Slack 클론 코딩[실시간 채팅 with React]
(참고) localhost:3090 접근 시 계속 오류가 나는 경우
강의 초반 강사님의 git(https://github.com/ZeroCho/sleact)을 다운받고 세팅 후 계속 오류가 나는 경우라면 참고하시면 좋을 것 같아 남깁니다.(코드가 아닌 세팅에서 오류가 날 때마다 힘이 빠지는 경우가 많아서.. 저도 참고하기 위해 남깁니다..) 결과npm i로 무언가 설치할 때-> 계속 오류가 뜬다면 뒤에 --force를 붙여보세요.ex) npm i fork-ts-checker-webpack-plugin -D --force 강의에서 올린 파일을 npm i로 설정하고 세팅도 동일하게 했는데 오류가 난다.->였습니다.-> 세팅단계에서는 쓰이지 않았으니 주석 return에서 설정한 항목들이 오류가 나는 경우처리 해주세요. 아래의 설정들을 주석처리해도 오류가 나면 return에 <div>아무말넣기</div>1. alecture/client.tsx<BrowserRouter></BrowserRouter> //주석처리alecture/components/ChatList/index.tsxreturn( 내부의 <ChatZone></ChatZone> //주석처리 )alecture/layouts/App/index.tsxreturn( 내부의 <Switch></Switch>//주석처리 )alecture/layouts/Workspace/index.tsxif (!userData) { //주석처리return <Redirect to="/login" />;}return (<div></div> //주석처리)alecture/pages/Login/index.tsxif (data) { //주석처리return <Redirect to="/workspace/sleact/channel/일반" />;}alecture/pages/SIgnUp/index.tsxif (data) { //주석처리return <Redirect to="/workspace/sleact/channel/일반" />;}
- 미해결Slack 클론 코딩[실시간 채팅 with React]
회원가입 요청이 가지않는 이슈
회원가입을 눌렀으나 회원가입이 안되고 요청이 가지 않는 것 같습니다. 에러메세지를 긁어서 확인 해보았으나 어디가 잘못된건지 모르겠고, 서버 부분의 콘솔을 확인해 보았으나 에러메세지가 나오지 않았습니다. 에러 메세지 이미지와 본문입니다.react_devtools_backend.js:4012 Error: Minified React error #31; visit https://reactjs.org/docs/error-decoder.html?invariant=31&args[]=object%20with%20keys%20%7Bsuccess%2C%20code%2C%20data%7D for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at ka (react-dom.production.min.js:140:47) at react-dom.production.min.js:150:265 at Ml (react-dom.production.min.js:176:171) at Bi (react-dom.production.min.js:271:134) at Eu (react-dom.production.min.js:250:347) at wu (react-dom.production.min.js:250:278) at bu (react-dom.production.min.js:250:138) at pu (react-dom.production.min.js:243:163) at react-dom.production.min.js:123:115 at t.unstable_runWithPriority (scheduler.production.min.js:18:34 혹시나 ENV를 까먹었을까봐 다시 확인했지만 있었고,아래는 서버쪽 터미널 이미지입니다.감사합니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
emotion global theme 설정관련 질문
emotion global theme을 설정하는 과정에서 오류가 발생해서 질문드립니다.자주 사용되는 css속성 단위를 전역에서 사용하고 싶어서 다음과 같이 설정을 진행했습니다.근데 알 수 없는 속성을 참조하고 있다고 반복해서 에러가 발생하고 있습니다.해당 문제에 관해서 피드백 부탁드리겠습니다.제가 설정한 코드는 다음과 같습니다. styles/theme.tsximport { Theme } from '@emotion/react'; const theme: Theme = { size: { tablet: '640px', laptop: '1200px', desktop: '1800px', }, colors: { red: '#f26462', primaryGray: '#3f4150', border: '#EFEFEF', selected: '#f2f2f2', }, calcRem: (pxSize: number) => { `${pxSize / 16}rem`; }, flexSet: (just = 'center', align = 'center') => { return `display: flex; justify-content: ${just}; align-items: ${align};`; }, flexColumnSet: (just = 'center', align = 'center') => { return `display: flex; flex-direction: column; justify-content: ${just}; align-items: ${align};`; }, }; export default theme; styles/emotion.d.tsximport '@emotion/react'; declare module '@emotion/react' { export interface DefaultTheme { size: { tablet: string; laptop: string; desktop: string; }; colors: { red: string; primaryGray: string; border: string; selected: string; }; calcRem: string; flexSet: string; flexColumnSet: string; } } client.tsximport 'core-js/stable'; import 'regenerator-runtime/runtime'; import React from 'react'; import { render } from 'react-dom'; import { BrowserRouter } from 'react-router-dom'; import { ThemeProvider } from '@emotion/react'; import axios from 'axios'; import App from './layouts/App'; import GlobalStyle from './styles/global'; import theme from './styles/theme'; axios.defaults.withCredentials = true; axios.defaults.baseURL = process.env.NODE_ENV === 'production' ? 'https://sleact.nodebird.com' : 'http://localhost:3090'; render( <BrowserRouter> <ThemeProvider theme={theme}> <GlobalStyle /> <App /> </ThemeProvider> </BrowserRouter>, document.querySelector('#app'), ); 발생 오류import React from 'react'; import styled from '@emotion/styled'; const ThemeTest1 = styled.div` // Property 'colors' does not exist on type 'Theme'. color: ${props => props.theme.colors.red}; `; const LogIn = () => { return ( <> <div>로그인</div> <ThemeTest1 >theme test1</div> </> ); }; export default LogIn;
- 미해결Slack 클론 코딩[실시간 채팅 with React]
npm i react react-dom 오류
db연결하고 npm init 잘설치후npm i react react-dom 해보았는데 오류 발생하였습니다. 구글검색해봐도 잘모르겠습니다.DELL@DESKTOP-CGJRPG6 MINGW64 ~/Desktop/sleact-master/alecture $ npm i react react-dom npm WARN ERESOLVE overriding peer dependency npm WARN While resolving: alecture@1.0.0 npm WARN Found: react@17.0.2 npm WARN node_modules/react npm WARN peer react@">=16.8.0" from @emotion/react@11.10.4 npm WARN node_modules/@emotion/react npm WARN peer @emotion/react@"^11.0.0-rc.0" from @emotion/styled@11.10.4 npm WARN node_modules/@emotion/styled npm WARN 1 more (the root project) npm WARN 12 more (@emotion/styled, ...) npm WARN npm WARN Could not resolve dependency: npm WARN peer react@"^0.14.0 || ^15.0.0 || ^16.0.0" from react-custom-scrollbars@4.2.1 npm WARN node_modules/react-custom-scrollbars npm WARN react-custom-scrollbars@"^4.2.1" from the root project npm WARN ERESOLVE overriding peer dependency npm WARN While resolving: alecture@1.0.0 npm WARN Found: react-dom@17.0.2 npm WARN node_modules/react-dom npm WARN peer react-dom@">=16.8.3" from react-mentions@4.4.7 npm WARN node_modules/react-mentions npm WARN react-mentions@"^4.1.1" from the root project npm WARN 2 more (react-toastify, the root project) npm WARN npm WARN Could not resolve dependency: npm WARN peer react-dom@"^0.14.0 || ^15.0.0 || ^16.0.0" from react-custom-scrollbars@4.2.1 npm WARN node_modules/react-custom-scrollbars npm WARN react-custom-scrollbars@"^4.2.1" from the root project npm ERR! code ERESOLVE npm ERR! ERESOLVE could not resolve npm ERR! npm ERR! While resolving: @pmmmwh/react-refresh-webpack-plugin@0.4.3 npm ERR! Found: webpack-dev-server@4.10.1 npm ERR! node_modules/webpack-dev-server npm ERR! dev webpack-dev-server@"^4.10.1" from the root project npm ERR! npm ERR! Could not resolve dependency: npm ERR! peerOptional webpack-dev-server@"3.x" from @pmmmwh/react-refresh-webpack-plugin@0.4.3 npm ERR! node_modules/@pmmmwh/react-refresh-webpack-plugin npm ERR! @pmmmwh/react-refresh-webpack-plugin@"^0.4.3" from the root project npm ERR! npm ERR! Conflicting peer dependency: webpack-dev-server@3.11.3 npm ERR! node_modules/webpack-dev-server npm ERR! peerOptional webpack-dev-server@"3.x" from @pmmmwh/react-refresh-webpack-plugin@0.4.3 npm ERR! node_modules/@pmmmwh/react-refresh-webpack-plugin npm ERR! @pmmmwh/react-refresh-webpack-plugin@"^0.4.3" from the root project npm ERR! npm ERR! Fix the upstream dependency conflict, or retry npm ERR! this command with --force, or --legacy-peer-deps npm ERR! to accept an incorrect (and potentially broken) dependency resolution. npm ERR! npm ERR! See C:\Users\DELL\AppData\Local\npm-cache\eresolve-report.txt for a full report. npm ERR! A complete log of this run can be found in: npm ERR! C:\Users\DELL\AppData\Local\npm-cache\_logs\2022-12-07T07_52_49_907Z-debug-0.log DELL@DESKTOP-CGJRPG6 MINGW64 ~/Desktop/sleact-master/alecture
- 미해결Slack 클론 코딩[실시간 채팅 with React]
.env파일 COOKIE_SECRET 설정관련 질문드립니다.
강좌에서는 .env파일의 COOKIE_SECRET이 sleactcookie로 설정되어 있는데, github 참고자료에서는 cookienyamnyam으로 적혀있더라고요 강좌 내용은 무시하고 github에 적혀있는 COOKIE_SECRET을 설정하면 될까요? 서버 세팅은 정상적으로 완료했는데 혹시나, 이후에 실습을 진행하면서 문제가 되는 부분이 있을까해서 질문드립니다. # 강좌 COOKIE_SECRET=sleactcookie # github COOKIE_SECRET=cookienyamnyam
- 미해결Slack 클론 코딩[실시간 채팅 with React]
스크롤탑 동기처리 이슈.
안녕하세요 제로초님.인피니티 스크롤 로딩 후 추가 데이터를 로딩하고 스크롤 위치를 유지하는 로직에 문제가 있어서 문의드립니다.아래 코드에서는 setSize의 then문 안에 setTimeout으로 한 번 더 감싸주었는데setTimeout이 없는경우 데이터가 불러와지기전에(스크롤의 높이가 늘어나지 않은 상태에서) setTimeout내부의 로직이 실행됩니다.그로인해 스크롤의 높이는 기존높이 - 기존높이 로 scrollTop(0) 과 같은 상태가 되어버리는데요.setTimeout으로 0초의 딜레이를 주면 또 순서대로 동작을 합니다...이런경우에 좋은 해결책이 있을까요? const onScroll = useCallback((values: positionValues) => { if (values.scrollTop === 0 && !isReachingEnd) { setSize((prevSize) => prevSize + 1).then(() => { setTimeout(() => { if (typeof scrollbarRef !== "function" && scrollbarRef?.current) { scrollbarRef.current.scrollTop(scrollbarRef.current.getScrollHeight() - values.scrollHeight); } }, 0); }); } }, []);
- 미해결Slack 클론 코딩[실시간 채팅 with React]
CollapseButton이 토글할때마다 어떻게 화살표(?)모양이 css에서 바뀌는지 못찾겟습니다
Direct Message 저 왼쪽의 아이콘(=CollapseButton)이 토글할때마다 바뀌는걸 css코드에서 찾고싶은데 제가 지식이 부족한건지 못찾겠습니다위의 사진을 보면 collapse: boolean으로 가져온거로 collapse일때& i { transform: none; };이게 실행되는건 알겠는데, 이게 실행되면<i className="c-icon ..." (다른 attrs) /> 이 태그가<i className="c-icon ..." (다른 attrs) transform=none; /> 이렇게 변하는데 (이거 맞나요?)transform=none;이면 슬랙쪽에서 만든 p-channel_sidebar__section_heading_expand같은 p-가 달린 속성이 토글되는거 같습니다만,,어떻게 다음의 속성이& i { transform: none; };부모태그인 button의 클래스를 바꾸게 하는건가요??-->css에서 부모태그의 클래스를 바꾸는건 들어본적이 생소해서요 (슬랙에서 제공하는 스타일시트url) 슬랙에서 내부적으로 p-channel_sidebar__section_heading_expand 속성이 있으면 자식i태그에 transform: none이 있으면 부모 클래스속성을 토글하는거 같긴한뎀,,
- 미해결Slack 클론 코딩[실시간 채팅 with React]
useParams channel 값 undefined
안녕하세요 제로초님.useParams로 channel 값을 불러오면 undefined가 나와 문의드립니다.아래 첨부한 소스코드와 같이 route를 구성해두었는데. 강의에 있는 InviteChannelModal 컴포넌트에서 channel을 불러오면 undefined가 뜹니다.혹시몰라 workspace.tsx에 정의해둔 route대로 Channel 컴포넌트에 들어가서 호출해보니 Channel 컴포넌트에서는 workspace와 channel 두가지 값 모두 정상적으로 불러올 수 있습니다.route를 타고 들어가지 않은 다른 요소에서 channel이라는 파라미터값을 사용하려면 어떻게 해야 할까요?app.tsx <Routes> <Route path="/" element={<Navigate replace to="/login" />} /> <Route path={"/login"} element={<SignIn />} /> <Route path={"/signup"} element={<SignUp />} /> <Route path={"/workspace/:workspace/*"} element={<Workspace />} /> </Routes> workspace.tsx <Routes> <Route path={"channel/:channel"} element={<Channel />} /> <Route path={"dm/:id"} element={<DirectMessage />} /> </Routes>
- 미해결Slack 클론 코딩[실시간 채팅 with React]
npx sequelize db:create 오류에 대한 질문입니다.
PS C:\Projects\sleact\back> npx sequelize db:createSequelize CLI [Node: 18.12.1, CLI: 6.2.0, ORM: 6.26.0]Loaded configuration file "config\config.js".Using environment "development".ERROR: Access denied for user 'root'@'localhost' (using password: YES)현재 node version은 18.12.1npm version은 8.19.2 입니다.squelize 는 npm 을 통해서 설치하였고 cli도 설치하였습니다.config/config.js 에 string으로도 넣어보았고.env 에도 넣어보았습니다. .env에 값이 나오는 것은 console.log로 확인하였습니다.MySQL commend clinent 에 들어가 password가 맞는지도 확인했는데 맞는 password 였습니다....!그럼에도 불구하고실행이 안됐습니다.. ㅠ 도움 주시면 감사하겠습니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
swr 현 버전에서의 revalidation 질문
안녕하세요 제로초님.swr 현 버전 기준으로는 revalition이 사라져서 고민하다가 useSWR에서 제공하는 mutate를 활용하는 방법을 생각해봤는데 사용해도 괜찮은건지 확신이 안서서 문의드립니다.axios({ method: "post", url: "http://localhost:3095/api/workspaces", data: { workspace: newWorkspace, url: newUrl, }, withCredentials: true, }) .then(async () => { await mutate(); onCloseModal(); }) .catch((err) => { console.dir(err); toast.error(err.response?.data, { position: "bottom-center" }); });위 코드처럼 mutate에 data를 넣어주지 않고 사용하면 useSWR에 선언되어있는 키와 페처를 기준으로 다시 호출해주던데.. revalidation을 이러한 방식으로 대체해도 괜찮을까요?
- 미해결Slack 클론 코딩[실시간 채팅 with React]
useSWR data undefined 이슈.
안녕하세요 제로초님.useSWR을 통해 서버에 user 정보를 요청하면 서버에서 넘어오는 response는 정상적으로 넘어오는데 화면에서 사용하는 data가 undefined로만 찍히는 원일을 모르겠어 문의드립니다.(추가로 로그아웃을 한것처럼 쿠키를 삭제하고 data를 찍어보아도 undefined가 찍힙니다. / response는 false로 오구요.) fetcher.ts 는 {}를 생략해서 return 되게끔 해두었습니다.import axios from "axios"; const fetcher = (url: string) => axios({ url, withCredentials: true }).then((res) => res.data); export default fetcher; Login.tsx 에서는 컴포넌트 최상단에 uswSWR을 사용해주었습니다.const { data, error, revalidate } = useSWR("http://localhost:3095/api/users", fetcher); 호출되는 users api의 response를 console.log에 찍어도 그렇고 네트워크 탭에서 response를 열어봐도 정상적으로 데이터는 받아집니다.제가 뭘 놓치고 있는지 시간되실 때 한 번 확인 부탁드리겠습니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
문득 든 궁금증입니다.
안녕하세요 제로초님,좋은 강좌 감사합니다.강좌 거의 막바지 쯤 든 생각인데, 프론트 개발자 중에신입이나 1,2년차 개발자들이 이런 서비스를 수월하게 구현할 수 있을까요? 보통 어느정도 실력이고 느낌인지 궁금합니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
소켓 이벤트 연결하기를 시청하다가 504 (Gateway Timeout) 오류가 떴습니다.
안녕하세요 제로초님,useEffect(() => { console.log('DMList: workspace 바꼈다', workspace); setOnlineList([]); }, [workspace]); useEffect(() => { socket?.on('onlineList', (data: number[]) => { console.log("data", data) setOnlineList(data); }); // socket?.on('dm', onMessage); // console.log('socket on dm', socket?.hasListeners('dm'), socket); return () => { // socket?.off('dm', onMessage); // console.log('socket off dm', socket?.hasListeners('dm')); // socket?.off('onlineList'); }; }, [socket]);여기까지 진행하고 슬랙앱을 봤을 때, (나) 여기에만 초록불이 잘 들어오는걸 확인했는데, 여기서 다른 탭을 갔다오거나 새로고침을 하면 제 생각엔 swr이 작동을 안하는 것 같습니다. userdata를 못받아와서 갑자기 loginpage로 튕겨져 나가는데, 쿠키는 남아있는데 계속 로딩중이라고 뜹니다. 백이랑 프론트 서버를 재시작하면 다시 되긴하는데, 채널을 옮기거나 하면 다시 오류가 시작되는데 이유를 못찾겠습니다. 프론트 쪽백쪽어디서 꼬인건지 잘 모르겠습니다. mutate쪽이 문제인가 싶어서 지워봤는데 똑같습니다..
- 미해결Slack 클론 코딩[실시간 채팅 with React]
optimistic UI 중 mutateChat 에서 Objects are not valid as a React child (found: Tue Nov 08 2022 17:24:47 GMT+0900 (한국 표준시)). If you meant to render a collection of children, use an array instead.
const onSubmitForm = useCallback( // optimistic UI (e: any) => { e.preventDefault(); console.log(chat); 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; // 먼저 추가해서 보여주고 post요청. }, false).then(() => { setChat(''); scrollbarRef.current?.scrollToBottom(); }); axios .post(`/api/workspaces/${workspace}/dms/${id}/chats`, { content: chat, }) .then(() => { mutateChat(); }) .catch(console.error); } }, [chat, chatData, myData, userData, workspace, id], ); date쓰는곳이 onSubmit함수 안인데..왜이럴까요...ㅜ
- 미해결Slack 클론 코딩[실시간 채팅 with React]
3095포트로 요청이 가지 않습니다.
devServer: { historyApiFallback: true, // react router port: 3090, devMiddleware: { publicPath: '/dist/' }, static: { directory: path.resolve(__dirname) }, proxy: { '/api/': { target: 'http://localhost:3095', changeOrigin: true, }, }, },-> webpack.config.ts if (prod) { app.enable("trust proxy"); app.use(morgan("combined")); app.use(helmet({ contentSecurityPolicy: false })); app.use(hpp()); } else { app.use(morgan("dev")); // app.use( // cors({ // origin: true, // credentials: true, // }) // ); }-> back > app.js 에서 주석한 부분 const onSubmit = useCallback((e: React.FormEvent<HTMLFormElement>): void => { e.preventDefault(); console.log(email, nickname, password, passwordCheck); if (!mismatchError && nickname) { console.log("회원가입 하러가기!"); setSignUpError('') // 비동기 요청전에 초기화 한번 해주기 setSignUpSuccess(false); axios.post('/api/users', { email, nickname, password, }) .then((response) => { console.log(response); setSignUpSuccess(true); }) .catch((err) => { console.log(err.response); setSignUpError(err.response.data); }); } }, [email, nickname, password, passwordCheck]);-> SignUp axios 부분 const onSubmit = useCallback((e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); setLogInError(false); axios.post( 'api/users/login', { email, password }, { withCredentials: true } ) .then(() => { }) .catch((error) => { }) }, []);-> LogIn axios 부분 -> 회원가입 시 3090 포트로 요청이 갑니다.-> 로그인 시도 마찬가지로 3090 포트로 요청이 갑니다. 검색도 해보고 /api/를 /api로도 바꿔봤는데, 마땅한 해결책을 찾을수가 없어서 질문드립니다.
- 미해결Slack 클론 코딩[실시간 채팅 with React]
Chats안에 Route된 페이지가 화면에 출력 되지 않는 현상
import { AddButton, Channels, Chats, Header, LogOutButton, MenuScroll, ProfileImg, ProfileModal, RightMenu, WorkspaceButton, WorkspaceModal, WorkspaceName, Workspaces, WorkspaceWrapper } from '@layouts/Workspace/styles' import fetcher from '@utils/fetcher'; import React, { useCallback, useState } from 'react'; import useSWR from 'swr'; import axios from 'axios' import gravatar from 'gravatar' import loadable from '@loadable/component'; import { Navigate, Route, Routes } from 'react-router'; import { useParams } from 'react-router'; import { toast } from 'react-toastify'; import Menu from '@components/Menu'; import useInput from '@hooks/useInput'; import Modal from '@components/Modal'; import CreateChannelModal from '@components/CreateChannelModal'; import { IChannel, IUser } from '@typings/db'; import { Link } from 'react-router-dom'; import { Button, Input, Label } from '@pages/SignUp/styles'; import InviteWorkspaceModal from '@components/InviteWorkspaceModal'; import InviteChannelModal from '@components/InviteChannelModal'; import ChannelList from '@components/ChannelList'; import DMList from '@components/DMList'; const Channel = loadable(() => import('@pages/Ch')); const DirectMessage = loadable(() => import('@pages/DirectMessage')); const Workspace = () => { // const Workspace: React.FC<Props> = ({ children }) => { // const { data: userData, mutate: revalidateUser } = useSWR<IUser | false>('http://localhost:3095/api/users', fetcher); const [showUserMenu, setShowUserMenu] = useState(false); const [showCreateWorkspaceModal, setShowCreateWorkspaceModal] = useState(false); const [showInviteWorkspaceModal, setShowInviteWorkspaceModal] = useState(false); const [showInviteChannelModal, setShowInviteChannelModal] = useState(false); const [showWorkspaceModal, setShowWorkspaceModal] = useState(false); const [showCreateChannelModal, setShowCreateChannelModal] = useState(false); const [newWorkspace, onChangeNewWorkspace, setNewWorkpsace] = useInput(''); const [newUrl, onChangeNewUrl, setNewUrl] = useInput(''); const { workspace } = useParams<{ workspace: string }>(); const { data: userData, error, mutate: revalidateUser } = useSWR<IUser | false>('/api/users', fetcher, { dedupingInterval: 2000, }); const { data: channelData } = useSWR<IChannel[]>( userData ? `/api/workspaces/${workspace}/channels` : null, fetcher); const onLogout = useCallback(() => { console.log(userData) axios.post( '/api/users/logout', null, { withCredentials: true, }) .then(() => { revalidateUser(false, false); }) .catch((err) => { console.log(err) }) }, []) const onClickUserProfile = useCallback(() => { setShowUserMenu((prev) => !prev); }, []) const onCloseUserProfile = useCallback((e: React.MouseEvent<HTMLInputElement>) => { // console.trace('click') e.stopPropagation(); setShowUserMenu((prev) => !prev); }, []) const onClickCreateWorkspace = useCallback(() => { setShowCreateWorkspaceModal(true); }, []) // 메뉴창에 채널생성 const onCreateWorkspace = useCallback((e: React.FormEvent<HTMLFormElement>) => { e.preventDefault(); if (!newWorkspace || !newWorkspace.trim()) return; if (!newUrl || !newUrl.trim()) return; axios.post('/api/workspaces', { workspace: newWorkspace, url: newUrl, }, { // 내가 로그인 된 상태라는걸 쿠키를 전달해서 안다 withCredentials: true, }).then(() => { revalidateUser(); // 초기화 setShowCreateWorkspaceModal(false); setNewWorkpsace(''); setNewUrl(''); }).catch((error) => { console.dir(error); // toastify npm으로 에러 메세지 toast.error(error.response?.data, { position: 'bottom-center' }) }) }, [newWorkspace, newUrl]) // 모달닫기 const onCloseModal = useCallback(() => { setShowCreateWorkspaceModal(false); setShowCreateChannelModal(false); setShowInviteWorkspaceModal(false); setShowInviteChannelModal(false); }, []) const toggleWorkspaceModal = useCallback(() => { setShowWorkspaceModal((prev) => !prev); }, []) const onClickAddChannel = useCallback(() => { setShowCreateChannelModal(true); }, []) const onClickInviteWorkspace = useCallback(() => { setShowInviteWorkspaceModal(true); }, []); // return 아래에 hooks가 있으면 Invalid hook call 에러가 뜬다 if (userData === undefined) return null; if (userData === false) { return <Routes><Route path="/*" element={<Navigate replace to="/login" />} /></Routes> } return ( <div> <Header> <RightMenu> <span onClick={onClickUserProfile}> <ProfileImg src={gravatar.url(userData.email, { s: '28px', d: 'retro' })} alt={userData.nickname} /> {showUserMenu && (<Menu style={{ right: 0, top: 38 }} show={showUserMenu} onCloseModal={onCloseUserProfile}> <ProfileModal> <img src={gravatar.url(userData.email, { s: '28px', d: 'retro' })} alt={userData.nickname} /> <div> <span id="profile-name">{userData.nickname}</span> <span id="profile-active">Active</span> </div> </ProfileModal> <LogOutButton onClick={onLogout}>로그아웃</LogOutButton> </Menu> )} </span> </RightMenu> </Header> <WorkspaceWrapper> <Workspaces> {userData?.Workspaces && userData?.Workspaces.map((ws: any) => { return ( <Link key={ws.id} to={`/workspace/${ws.url}/channel/일반`}> <WorkspaceButton>{ws.name.slice(0, 1).toUpperCase()}</WorkspaceButton> </Link> ); })} <AddButton onClick={onClickCreateWorkspace}>+</AddButton> </Workspaces> <Channels> <WorkspaceName onClick={toggleWorkspaceModal}>Sleact</WorkspaceName> <MenuScroll> {/* Menu에서 div옆에 style을 받았기 때문에 style사용가능 */} <Menu show={showWorkspaceModal} onCloseModal={toggleWorkspaceModal} style={{ top: 95, left: 80 }}> <WorkspaceModal> <h2>Sleact</h2> <button onClick={onClickInviteWorkspace}>워크스페이스에 사용자 초대</button> <button onClick={onClickAddChannel}>채널 만들기</button> <button onClick={onLogout}>로그아웃</button> </WorkspaceModal> </Menu> <ChannelList /> <DMList /> </MenuScroll> </Channels> <Chats> <Routes> <Route path='/workspace/:workspace/channel/:channel/*' element={<><Channel /></>} /> <Route path='/workspace/:workspace/dm/:id/*' element={<><DirectMessage /></>} /> </Routes> </Chats> </WorkspaceWrapper> <Modal show={showCreateWorkspaceModal} onCloseModal={onCloseModal}> <form onSubmit={onCreateWorkspace}> <Label id="workspace-label"> <span>워크스페이스 이름</span> <Input id="workspace" value={newWorkspace} onChange={onChangeNewWorkspace} /> </Label> <Label id="workspace-url-label"> <span>워크스페이스 url</span> <Input id="workspace" value={newUrl} onChange={onChangeNewUrl} /> </Label> <Button type="submit">생성하기</Button> </form> </Modal> <CreateChannelModal show={showCreateChannelModal} onCloseModal={onCloseModal} setShowCreateChannelModal={setShowCreateChannelModal} /> <InviteWorkspaceModal show={showInviteWorkspaceModal} onCloseModal={onCloseModal} setShowInviteWorkspaceModal={setShowInviteWorkspaceModal} /> <InviteChannelModal show={showInviteChannelModal} onCloseModal={onCloseModal} setShowInviteChannelModal={setShowInviteChannelModal} /> </div> ) } export default Workspace;Workspace import React from 'react'; import gravatar from 'gravatar'; import { Container, Header } from './styles'; import { useParams } from 'react-router'; import useSWR from 'swr'; import fetcher from '@utils/fetcher'; import ChatBox from '@components/ChatBox'; 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); if (!userData || !myData) { return null } return ( <Container> <Header> <img src={gravatar.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nickname} /> <span>{userData.nickname}</span> </Header> <ChatList /> <ChatBox chat="" /> </Container> ) } export default DirectMessage;DirectionMessage import React, { useCallback } from 'react' import { Form } from 'react-router-dom'; import { ChatArea, MentionsTextarea, SendButton, Toolbox } from './styles'; interface Props { chat: string; } const ChatBox: React.FC<Props> = ({ chat }) => { const onSubmitForm = useCallback(() => { }, []); return ( <ChatArea> <Form onSubmit={onSubmitForm}> <MentionsTextarea> <textarea /> </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;ChatBoximport styled from '@emotion/styled'; export const Container = styled.div` display: flex; flex-wrap: wrap; height: calc(100vh - 38px); flex-flow: column; position: relative; `; export const Header = styled.header` height: 64px; display: flex; width: 100%; --saf-0: rgba(var(--sk_foreground_low, 29, 28, 29), 0.13); box-shadow: 0 1px 0 var(--saf-0); padding: 20px 16px 20px 20px; font-weight: bold; align-items: center; & img { margin-right: 5px; } `; export const DragOver = styled.div` position: absolute; top: 64px; left: 0; width: 100%; height: calc(100% - 64px); background: white; opacity: 0.7; display: flex; align-items: center; justify-content: center; font-size: 40px; `;DirectMessage stylesimport styled from '@emotion/styled'; import { MentionsInput } from 'react-mentions'; export const ChatArea = styled.div` display: flex; width: 100%; padding: 20px; padding-top: 0; `; export const Form = styled.form` color: rgb(29, 28, 29); font-size: 15px; width: 100%; border-radius: 4px; border: 1px solid rgb(29, 28, 29); `; export const MentionsTextarea = styled(MentionsInput)` font-family: Slack-Lato, appleLogo, sans-serif; font-size: 15px; padding: 8px 9px; width: 100%; & strong { background: skyblue; } & textarea { height: 44px; padding: 9px 10px !important; outline: none !important; border-radius: 4px !important; resize: none !important; line-height: 22px; border: none; } & ul { border: 1px solid lightgray; max-height: 200px; overflow-y: auto; padding: 9px 10px; background: white; border-radius: 4px; width: 150px; } `; export const Toolbox = styled.div` position: relative; background: rgb(248, 248, 248); height: 41px; display: flex; border-top: 1px solid rgb(221, 221, 221); align-items: center; border-bottom-left-radius: 4px; border-bottom-right-radius: 4px; `; export const SendButton = styled.button` position: absolute; right: 5px; top: 5px; `; export const EachMention = styled.button<{ focus: boolean }>` padding: 4px 20px; background: transparent; border: none; display: flex; align-items: center; color: rgb(28, 29, 28); width: 100%; & img { margin-right: 5px; } ${({ focus }) => focus && ` background: #1264a3; color: white; `}; `;ChatBox stylesimport styled from '@emotion/styled'; export const RightMenu = styled.div` float: right; `; export const Header = styled.header` height: 38px; background: #350d36; color: #ffffff; box-shadow: 0 1px 0 0 rgba(255, 255, 255, 0.1); padding: 5px; text-align: center; `; export const ProfileImg = styled.img` width: 28px; height: 28px; position: absolute; top: 5px; right: 16px; `; export const ProfileModal = styled.div` display: flex; padding: 20px; & img { display: flex; } & > div { display: flex; flex-direction: column; margin-left: 10px; } & #profile-name { font-weight: bold; display: inline-flex; } & #profile-active { font-size: 13px; display: inline-flex; } `; export const LogOutButton = styled.button` border: none; width: 100%; border-top: 1px solid rgb(29, 28, 29); background: transparent; display: block; height: 33px; padding: 5px 20px 5px; outline: none; cursor: pointer; `; export const WorkspaceWrapper = styled.div` display: flex; flex: 1; `; export const Workspaces = styled.div` width: 65px; display: inline-flex; flex-direction: column; align-items: center; background: #3f0e40; border-top: 1px solid rgb(82, 38, 83); border-right: 1px solid rgb(82, 38, 83); vertical-align: top; text-align: center; padding: 15px 0 0; `; export const Channels = styled.nav` width: 260px; display: inline-flex; flex-direction: column; background: #3f0e40; color: rgb(188, 171, 188); vertical-align: top; & a { padding-left: 36px; color: inherit; text-decoration: none; height: 28px; line-height: 28px; display: flex; align-items: center; &.selected { color: white; } } & .bold { color: white; font-weight: bold; } & .count { margin-left: auto; background: #cd2553; border-radius: 16px; display: inline-block; font-size: 12px; font-weight: 700; height: 18px; line-height: 18px; padding: 0 9px; color: white; margin-right: 16px; } & h2 { height: 36px; line-height: 36px; margin: 0; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; font-size: 15px; } `; export const WorkspaceName = styled.button` height: 64px; line-height: 64px; border: none; width: 100%; text-align: left; border-top: 1px solid rgb(82, 38, 83); border-bottom: 1px solid rgb(82, 38, 83); font-weight: 900; font-size: 24px; background: transparent; text-overflow: ellipsis; overflow: hidden; white-space: nowrap; padding: 0; padding-left: 16px; margin: 0; color: white; cursor: pointer; `; export const MenuScroll = styled.div` height: calc(100vh - 102px); overflow-y: auto; `; export const WorkspaceModal = styled.div` padding: 10px 0 0; & h2 { padding-left: 20px; } & > button { width: 100%; height: 28px; padding: 4px; border: none; background: transparent; border-top: 1px solid rgb(28, 29, 28); cursor: pointer; &:last-of-type { border-bottom: 1px solid rgb(28, 29, 28); } } `; export const Chats = styled.div` flex: 1; `; export const AddButton = styled.button` color: white; font-size: 24px; display: inline-block; width: 40px; height: 40px; background: transparent; border: none; cursor: pointer; `; export const WorkspaceButton = styled.button` display: inline-block; width: 40px; height: 40px; border-radius: 10px; background: white; border: 3px solid #3f0e40; margin-bottom: 15px; font-size: 18px; font-weight: 700; color: black; cursor: pointer; `;Workspace Styles (혹시나 해서 스타일까지 올렸습니다)저기 흰색 부분 (Chats) 부분에 아무것도 출력이 되지 않습니다. 아예 DirectMessage 페이지 자체를 못 받아오는 것 같은데 route를 App으로 옮겨서 <div>TEST</div>만 출력 시킬 땐 작동이 됩니다..그래서 <Channel />이랑 <DirectMessage />이렇게 Route바깥으로 빼서 출력해보면const { data: userData } = useSWR(`/api/workspaces/${workspace}/users/${id}`, fetcher);저 ${id} 부분이 undefined가 나옵니다.. 메세지 클릭시 url 주소는 제대로 다 바뀌고 있습니다
- 미해결Slack 클론 코딩[실시간 채팅 with React]
db 생성과 seed data 에러 없이 넣었습니다.
그런데 sleact 데이터 베이스와 seed Data가 제 mysql localhost에는 만들어진게 없는데, npx sequelize db:create 이 명령어와 npx sequelize db:seed:all 이 명령어를 입력했을 때, 제 mysql 상에 데이터가 들어와야 맞는거 아닌가 해서 질문 드립니다. 물론 localhost:3095는 잘 나옵니다.감사합니다.