inflearn logo
강의

강의

N
챌린지

챌린지

멘토링

멘토링

N
클립

클립

로드맵

로드맵

지식공유

묻고 답해요

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

Cannot read properties of undefined (reading 'data')

미해결

Slack 클론 코딩[실시간 채팅 with React]

제로초님, 전 강의 듣고 할 때만 해도 잘 됐는데 오늘 쉬고 다시 해보니까 이런 오류 메세지가 뜹니다. 해결해보려고 해도 잘 안되네요.. Cannot read properties of undefined (reading 'data') SignUp 폴더에서 index.tsx에 문제가 있다고 떠서 코드 올립니다 import useInput from "@hooks/useInput"; import React, { useCallback, useState } from "react"; import { Form, Label, Input, LinkContainer, Button, Header, Error, Success} from './styles' import axios from "axios"; import {Link} from 'react-router-dom'; // 타입스크립트는 간단하게 말하면 변수, 매개변수, 리턴 값에 타입을 붙여줌 // 변수에는 딱히 타입을 붙여주지 않아도 된다 타입스크립트가 알아서 추론하기 때문에(리턴값도 마찬가지) 그러나 매개변수에는 붙여주어야됨 const SignUp = () => { const [email, onChangeEmail] = useInput('');//useInput은 커스텀 훅 const [nickname, onChangeNickName] = useInput(''); const [password, setPassword] = useState(''); const [passwordCheck, setPasswordCheck] = useState(''); const [mismatchError, setMismathError] = useState(false); const [signUpError, setSignUpError] = useState(''); const [signUpSuccess, setSignUpSuccess] = useState(false); const onChangePassword = useCallback((e: any) => { setPassword(e.target.value); setMismathError(e.target.value !== passwordCheck); // 함수 기준으로 외부 변수만 deps에 적어줌 내부 변수는 x }, [passwordCheck]); const onChangePasswordCheck = useCallback((e: any) => { setPasswordCheck(e.target.value); setMismathError(e.target.value !== password) }, [password]); const onSubmit = useCallback( (e: any) => { e.preventDefault(); if (!mismatchError && nickname) { console.log('서버로 회원가입하기'); setSignUpError(''); setSignUpSuccess(false); axios .post('/api/users', { email, nickname, password, }) .then((response) => { console.log(response); setSignUpSuccess(true); }) .catch((error) => { console.log(error.response); //여기가 문제가 있다고 뜹니다. setSignUpError(error.response.data); }) .finally(() => {}); } }, [email, nickname, password, passwordCheck, mismatchError], ); return ( <div id="container"> <Header>Sleact</Header> <Form onSubmit={onSubmit}> <Label id="email-label"> <span>이메일 주소</span> <div> <Input type="email" id="email" name="email" value={email} onChange={onChangeEmail} /> </div> </Label> <Label id="nickname-label"> <span>닉네임</span> <div> <Input type="text" id="nickname" name="nickname" value={nickname} onChange={onChangeNickName} /> </div> </Label> <Label id="password-label"> <span>비밀번호</span> <div> <Input type="password" id="password" name="password" value={password} onChange={onChangePassword} /> </div> </Label> <Label id="password-check-label"> <span>비밀번호 확인</span> <div> <Input type="password" id="password-check" name="password-check" value={passwordCheck} onChange={onChangePasswordCheck} /> </div> {mismatchError && <Error>비밀번호가 일치하지 않습니다.</Error>} {!nickname && <Error>닉네임을 입력해주세요.</Error>} {signUpError && <Error>{signUpError}</Error>} {signUpSuccess && <Success>회원가입되었습니다! 로그인해주세요.</Success>} </Label> <Button type="submit">회원가입</Button> </Form> <LinkContainer> 이미 회원이신가요?&nbsp; <Link to="/login">로그인 하러가기</Link> </LinkContainer> </div> ); }; export default SignUp;

  • 웹팩
  • react
  • socket.io
  • babel
  • typescript
  • 클론코딩
  • Socket.io
  • 클론코딩
성창수 댓글 1 좋아요 0 조회수 2391

node_modules/.bin/webpack 오류가 납니다

미해결

프론트엔드 개발환경의 이해와 실습 (webpack, babel, eslint..)

node_modules/.bin/webpack --help 하면 이러한 오류가 나는데 이건 왜그런걸까요?

  • node.js
  • 웹팩
  • eslint
  • nodejs
  • babel
두부 댓글 1 좋아요 0 조회수 1108

초기 새팅에 어려움을 가져서 질문드립니다. config.js 파일이 없습니다

미해결

Slack 클론 코딩[실시간 채팅 with React]

https://github.com/ZeroCho/sleact에서 code로 가서 zip파일을 다운 받았습니다. 이후 git clone https://github.com/zerocho/sleact 명령어를 입력한 후, back 폴더에서 npm i까지 마쳤는데, 저는 강의 내용과 다르게 config 폴더가 비어 있습니다. 어떤 부분에서 잘못 따라 하였는이해를 못해서 깃 관련 구글링을 해보다가 결국 질문 드립니다.

  • react
  • typescript
  • 웹팩
  • socket.io
  • Socket.io
  • 클론코딩
  • babel
  • 클론코딩
댓글 1 좋아요 0 조회수 595

tsconfig.json과 webpack.config.ts의 연동구간?

미해결

Slack 클론 코딩[실시간 채팅 with React]

tsconfig.json(ts -> js)로 바꿔주고, 그 후에 webpack.config.ts가 js,css,html들을 하나로 번들링해주는 순서가 맞나요?? $webpack 실행하면 웹팩 프로그램이 그냥 알아서 tsconfig.json이 있으면 먼저 적용한후 webpack.config.ts를 적용하는건가요?

  • 클론코딩
  • Socket.io
  • react
  • socket.io
  • babel
  • 클론코딩
  • 웹팩
  • typescript
초간단 댓글 1 좋아요 0 조회수 499

npx sequelize db:seed:all 시, ERROR: Validation error 이슈

미해결

Slack 클론 코딩[실시간 채팅 with React]

안녕하세요 강사님, 강의 중 채널 생성과정에서 오류가 있어 문의를 남깁니다. 먼저, 채널 데이터를 가져오지 못해 다른 문의를 찾아보니 seed 설정을 해주지 않은거 같아 npx sequelize db:create 진행하였고, 이어서 npx sequelize db:seed:all 과정을 진행했습니다 npx sequelize db:seed:all 을 진행하니 Validation error가 발생했습니다. 다른 문의를 보니 db에 sleact table이 생성되지 않아 발생하는 문의글이 많아서 db 사진 올려드릴게요 추가적으로, back 파일에서 npm run dev를 실행하면 db 연결까지 잘 됩니다. 도대체 어디가 잘 못 된 건지 감이 오지 않습니다.. 감사합니다.

  • react
  • babel
  • socket.io
  • typescript
  • 웹팩
  • 클론코딩
  • Socket.io
  • 클론코딩
안찬익 댓글 1 좋아요 0 조회수 1121

POST http://localhost:3090/api/users net::ERR_INTERNET_DISCONNECTED

미해결

Slack 클론 코딩[실시간 채팅 with React]

제로초님, 코드는 정확히 따라 한 거 같은데, 무엇이 문제인지 판단이 안되네요... 리액트 v18, 타입스크립트 v18, axios는 1.2.3 입니다. webpack import path from 'path'; import ReactRefreshWebpackPlugin from '@pmmmwh/react-refresh-webpack-plugin'; import webpack, { Configuration as WebpackConfiguration } from "webpack"; import { Configuration as WebpackDevServerConfiguration } from "webpack-dev-server"; interface Configuration extends WebpackConfiguration { devServer?: WebpackDevServerConfiguration; } import ForkTsCheckerWebpackPlugin from 'fork-ts-checker-webpack-plugin'; const isDevelopment = process.env.NODE_ENV !== 'production'; const config: Configuration = { name: 'sleact', mode: isDevelopment ? 'development' : 'production', devtool: !isDevelopment ? 'hidden-source-map' : 'eval', resolve: { extensions: ['.js', '.jsx', '.ts', '.tsx', '.json'], alias: { '@hooks': path.resolve(__dirname, 'hooks'), '@components': path.resolve(__dirname, 'components'), '@layouts': path.resolve(__dirname, 'layouts'), '@pages': path.resolve(__dirname, 'pages'), '@utils': path.resolve(__dirname, 'utils'), '@typings': path.resolve(__dirname, 'typings'), }, }, entry: { app: './client', }, module: { rules: [ { test: /\.tsx?$/, loader: 'babel-loader', options: { presets: [ [ '@babel/preset-env', { targets: { browsers: ['IE 10'] }, debug: isDevelopment, }, ], '@babel/preset-react', '@babel/preset-typescript', ], env: { development: { plugins: [['@emotion', { sourceMap: true }], require.resolve('react-refresh/babel')], }, production: { plugins: ['@emotion'] } }, }, exclude: path.join(__dirname, 'node_modules'), }, { test: /\.css?$/, use: ['style-loader', 'css-loader'], }, ], }, plugins: [ new ForkTsCheckerWebpackPlugin({ async: false, // eslint: { // files: "./src/**/*", // }, }), new webpack.EnvironmentPlugin({ NODE_ENV: isDevelopment ? 'development' : 'production' }), ], output: { path: path.join(__dirname, 'dist'), filename: '[name].js', publicPath: '/dist/', }, devServer: { historyApiFallback: true, // react router port: 3090, devMiddleware: { publicPath: '/dist/' }, static: { directory: path.resolve(__dirname) }, proxy: { '/api/': { target: 'http://localhost:3095', changeOrigin: true, }, }, }, }; if (isDevelopment && config.plugins) { config.plugins.push(new webpack.HotModuleReplacementPlugin()); config.plugins.push(new ReactRefreshWebpackPlugin()); } if (!isDevelopment && config.plugins) { } export default config; index.tsx import useInput from "@hooks/useInput"; import React, { useCallback, useState } from "react"; import { Form, Label, Input, LinkContainer, Button, Header, Error} from './styles' import axios from "axios"; const SignUp = () => { const [email, onChangeEmail] = useInput('');//useInput은 커스텀 훅 const [nickname, onChangeNickName] = useInput(''); const [password, setPassword] = useState(''); const [passwordCheck, setPasswordCheck] = useState(''); const [mismatchError, setMismathError] = useState(false); const onChangePassword = useCallback((e: any) => { setPassword(e.target.value); setMismathError(e.target.value !== passwordCheck); // 함수 기준으로 외부 변수만 deps에 적어줌 내부 변수는 x }, [passwordCheck]); const onChangePasswordCheck = useCallback((e: any) => { setPasswordCheck(e.target.value); setMismathError(e.target.value !== password) }, [password]); const onSubmit = useCallback((e: React.FormEvent) => { e.preventDefault(); if(!mismatchError && nickname){ console.log('서버로 회원가입하기'); axios.post('/api/users', { email, nickname, password, }) .then((response) => { console.log(response); })//요청이 성공하면 실행 .catch((error) => { console.log(error.response); })//요청이 실패하면 실행 .finally(() => {});//성공하든 실패하든 실행시키고 싶은 것 } console.log(email, nickname, password, passwordCheck) }, [email, nickname, password, passwordCheck, mismatchError]); return ( <div id="container"> <Header>Sleact</Header> <Form onSubmit={onSubmit}> <Label id="email-label"> <span>이메일 주소</span> <div> <Input type="email" id="email" name="email" value={email} onChange={onChangeEmail} /> </div> </Label> <Label id="nickname-label"> <span>닉네임</span> <div> <Input type="text" id="nickname" name="nickname" value={nickname} onChange={onChangeNickName} /> </div> </Label> <Label id="password-label"> <span>비밀번호</span> <div> <Input type="password" id="password" name="password" value={password} onChange={onChangePassword} /> </div> </Label> <Label id="password-check-label"> <span>비밀번호 확인</span> <div> <Input type="password" id="password-check" name="password-check" value={passwordCheck} onChange={onChangePasswordCheck} /> </div> {mismatchError && <Error>비밀번호가 일치하지 않습니다.</Error>} {!nickname && <Error>닉네임을 입력해주세요.</Error>} {/* {signUpError && <Error>{signUpError}</Error>} */} {/* {signUpSuccess && <Success>회원가입되었습니다! 로그인해주세요.</Success>} */} </Label> <Button type="submit">회원가입</Button> </Form> <LinkContainer> 이미 회원이신가요?&nbsp; <a href="/login">로그인 하러가기</a> </LinkContainer> </div> ); }; export default SignUp; 이렇게 따라 한 후에 회원 가입 누르면 아래 같은 화면이 뜹니다.

  • 웹팩
  • react
  • socket.io
  • Socket.io
  • typescript
  • 클론코딩
  • babel
  • 클론코딩
성창수 댓글 2 좋아요 0 조회수 1128

개발환경에서 assets 파일 참조관련 질문

해결됨

프론트엔드 개발환경의 이해와 실습 (webpack, babel, eslint..)

요약 개발환경에서 src/assets/.... 에 있는 이미지 파일을 제대로 참조하는 방법이 궁금합니다. 구성요소 프로젝트의 구성요소는 아래와 같습니다. public[index.html, favicon.ico] src[assets[image0, image1...], index.js 등] 설치된 패키지는 아래와 같습니다. "webpack": "^5.75.0", "webpack-cli": "^5.0.1", "webpack-dev-server": "^4.11.1" // 본 강의에선 4.x.x 버전을 사용하지만... // 5 version을 공부해야해서... 죄송합니다 😥 설명 dev server를 실행시켜 개발할 때, js 파일을 수정하면 바로 반영이 되는 걸 확인했습니다. 그런데 이미지 파일의 경우 다른 파일을 참조하도록 하면 해당 파일을 불러오지 못합니다. 그리고 build된 파일을 참조합니다. 예로들어 정적 이미지 파일이 ./src/assets/image_0.jpg 라면, dev server로 실행시켜 확인하면 HOST/dist/assets/images/[hash][ext][query].jpg 이렇게 되어있습니다. (경로가 다름) 그리고 build를 하면 분명 assets 디렉토리엔 다수의 이미지 파일이 존재함에도 불구하고 코드에서 사용된 이미지 파일만 build됩니다. 그러면 만약 코드내부에서 동적으로 다른 static image 파일을 참조하게 된다면 해당 이미지가 없기 때문에 오류가 날텐데 이런건 어떻게 처리해야하나요? 코드 const path = require('path'); const { BannerPlugin, DefinePlugin } = require('webpack'); const childProcess = require('child_process'); const HtmlWebpackPlugin = require('html-webpack-plugin'); const MiniCssExtractPlugin = require('mini-css-extract-plugin'); const isDevMode = (process.env.NODE_ENV || 'development').trim() === 'development'; console.log('is DEV mode?', isDevMode); console.log('__dirname: ', __dirname); module.exports = { mode: isDevMode ? 'development' : 'production', // entry: webpack 시작되는 부분이라고 생각하면 된다. entry: { main: './src/index.js', }, /** * output * entry point를 기준으로 * 모든 .js 파일을 합쳐서 하나의 bundle 파일로 만드는데, * 이걸 어디에 저장할 것인지 지정하는 option */ output: { path: path.resolve(__dirname, 'dist'), filename: isDevMode ? '[name].js' : 'main.[contenthash].js', chunkFilename: '[id].chunk.js', assetModuleFilename: 'images/[hash][ext][query]', clean: true, }, devServer: { port: 3000, hot: true, client: { overlay: { errors: true, warnings: false, }, }, // static: { // directory: path.resolve(__dirname, './src/assets/'), // }, }, /** * module * test에 설정한 파일들을 inspect 하여, * 조건에 맞는 파일들에 대해 loader 들을 실행하여 해석함 */ module: { rules: [ { test: /\.(sa|sc|c)ss$/i, exclude: [/node_modules/], use: [ // creates 'style' nodes from JS strings isDevMode ? 'style-loader' : { loader: MiniCssExtractPlugin.loader, options: { publicPath: '', }, }, // translates css into common JS 'css-loader', 'postcss-loader', // complies sass to css 'sass-loader', ], }, { test: /\.(png|svg|jpg|jpeg|gif)$/i, exclude: [/node_modules/], type: 'asset/resource', parser: { dataUrlCondition: { // 크기가 8kb 미만인 파일은 inline 모듈로 처리되고 그렇지 않으면 resource 모듈로 처리됩니다. maxSize: 4 * 1042, }, }, // generator: { // publicPath: './assets/', // outputPath: './assets/', // }, }, { test: /\.js$/, exclude: [/node_modules/], loader: 'babel-loader', }, { test: /\.(woff|woff2|eot|ttf|otf)$/i, exclude: [/node_modules/], type: 'asset/resource', }, ], }, plugins: [ /** * 개발할 때 API 서버주소, * 배포했을 때 API 서버주소를 설정하는 Plugin */ // new DefinePlugin({ // NODE_ENV: 'development', // }), new BannerPlugin({ banner: `Build Date: ${new Date().toLocaleString()} Commit Version: ${childProcess.execSync('git rev-parse --short HEAD')} Author: ${childProcess.execSync('git config user.name')}`, }), new HtmlWebpackPlugin({ template: './public/index.html', templateParameters: { env: isDevMode ? '개발용' : '배포용', }, minify: !isDevMode ? { collapseWhitespace: true, removeComments: true, } : false, }), ...(!isDevMode ? [ new MiniCssExtractPlugin({ filename: isDevMode ? '[name].css' : '[name].[contenthash].css', chunkFilename: isDevMode ? '[id].css' : '[id].[contenthash].css', }), ] : []), ], }; 결론 즉 정리하자면, 개발모드일 때 정적 이미지 파일을 참조하도록 설정을 어떻게 해야하나요? 왜 build할 땐 이미지 파일이 코드에서 사용중인 것만 빌드 되나요? 답변 주시면 감사하겠습니다.

  • 웹팩
  • webpack5
  • 웹팩
  • nodejs
  • eslint
  • babel
taylous 댓글 1 좋아요 0 조회수 1190

swr revalidate에 대해 질문드립니다.

미해결

Slack 클론 코딩[실시간 채팅 with React]

안녕하세요 swr revalidate 가 deprecated 되어 mutate를 사용하면 된다는 답변을 확인하고 mutate를 썼는데 궁금한 점이 있습니다. mutate()를 하는 이유는 로그인 성공했을때 그 시점에 users api를 호출하기 위해서 인가요? 그리고 mutate 와 무관하게 디폴트 설정에따라(화면전환등) SWR에서 userapi를 호출하고 있는것도 맞나요? 1: 화면 첫 렌더링때 user api 콜 로그인 mutate실행으로 user api 콜 화면전환했을때 다시 콜 제가 이해한게 맞는지 답변 부탁드립니다. 감사합니다.

  • Socket.io
  • 웹팩
  • react
  • typescript
  • babel
  • 클론코딩
나래 댓글 1 좋아요 2 조회수 765

회원가입 요청이 가지않는 이슈

미해결

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를 까먹었을까봐 다시 확인했지만 있었고, 아래는 서버쪽 터미널 이미지입니다. 감사합니다.

  • 웹팩
  • Socket.io
  • babel
  • typescript
  • react
  • 클론코딩
퀀텀에듀 댓글 1 좋아요 0 조회수 607

스크롤탑 동기처리 이슈.

미해결

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); }); } }, []);

  • babel
  • Socket.io
  • 웹팩
  • react
  • typescript
  • 클론코딩
김영욱 댓글 2 좋아요 0 조회수 464

npx sequelize db:create 오류에 대한 질문입니다.

해결됨

Slack 클론 코딩[실시간 채팅 with React]

PS C:\Projects\sleact\back> npx sequelize db:create Sequelize 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.1 npm version은 8.19.2 입니다. squelize 는 npm 을 통해서 설치하였고 cli도 설치하였습니다. config/config.js 에 string으로도 넣어보았고 .env 에도 넣어보았습니다. .env에 값이 나오는 것은 console.log로 확인하였습니다. MySQL commend clinent 에 들어가 password가 맞는지도 확인했는데 맞는 password 였습니다....! 그럼에도 불구하고 실행이 안됐습니다.. ㅠ 도움 주시면 감사하겠습니다.

  • squelize
  • react
  • typescript
  • 웹팩
  • babel
  • Socket.io
  • 클론코딩
퀀텀에듀 댓글 1 좋아요 0 조회수 523

채널 생성시 channelData.map is not a function

미해결

Slack 클론 코딩[실시간 채팅 with React]

채널생성 클릭하면 channeldata.map is not a function이라고 에러가 뜨는데 channelData뿌려지는곳에 ?옵셔널도 줬고.. 아래처럼 잘 작성한것같은데 어딜 놓쳤는지 모르겠습니다. 새로고침하면 추가된 채널명이 출력됩니다. workspace import fetcher from '@utils/fetcher'; import axios from 'axios'; import React, { FC, useCallback, useState } from 'react'; import { Navigate, useParams } from 'react-router-dom'; import useSWR from 'swr'; import { AddButton, Channels, Chats, Header, LogOutButton, MenuScroll, ProfileImg, ProfileModal, RightMenu, WorkspaceButton, WorkspaceModal, WorkspaceName, Workspaces, WorkspaceWrapper, } from './styles'; import gravatar from 'gravatar'; import Menu from '@components/menu'; import { Link } from 'react-router-dom'; import { IChannel, IUser, IWorkspace } from '@typings/db'; import { Button, Input, Label } from '@pages/signup/styles'; import useInput from '@hooks/useInput'; import Modal from '@components/modal'; import { toast } from 'react-toastify'; import CreateChannelModal from '@components/createChannelModal'; const Workspace: FC = ({ children }) => { const { workspace, channel } = useParams<{ workspace: string; channel: string }>(); const { data: userData, error, mutate } = useSWR<IUser | false>('/api/users', fetcher, { dedupingInterval: 2000 }); const { data: channelData } = useSWR<IChannel[]>(userData ? `/api/workspaces/${workspace}/channels` : null, fetcher); if (!userData) { return <Navigate to="/login" />; } const [showUserMenu, setShowUserMenu] = useState(false); const [newWorkspace, onChangeNewWorkspace, setNewWorkspace] = useInput(''); const [newUrl, onChangeNewUrl, setNewUrl] = useInput(''); const [showWorkspaceModal, setShowWorkspaceModal] = useState(false); const [showCreateChannelModal, setShowCreateChannelModal] = useState(false); const [showCreateWorkspaceModal, setShowCreateWorkspaceModal] = useState(false); //functions const onLogout = useCallback(() => { axios .post('/api/users/logout', null, { withCredentials: true, }) .then((res) => { mutate(res.data); }); }, []); const onClickUserProfile = useCallback(() => { setShowUserMenu(!showUserMenu); }, [showUserMenu]); const onClickCreateWorkspace = useCallback(() => { setShowCreateWorkspaceModal(true); }, []); const onCreateWorkspace = useCallback( (e) => { e.preventDefault(); if (!newWorkspace || !newWorkspace.trim()) return; if (!newUrl || !newUrl.trim()) return; //trim ->띄어쓰기 하나도 통과 돼버리는걸 막는다. axios .post( '/api/workspaces', { workspace: newWorkspace, url: newUrl, }, { withCredentials: true, }, ) .then((res) => { mutate(res.data); setShowCreateWorkspaceModal(false); setNewWorkspace(''), setNewUrl(''); }) .catch((err) => { console.dir(err); toast.error(error.response?.data, { position: 'bottom-center' }); }); }, [newWorkspace, newUrl], ); const onCloseModal = useCallback(() => { setShowCreateWorkspaceModal(false); setShowCreateChannelModal(false); }, []); const toggleWorkspaceModal = useCallback(() => { setShowWorkspaceModal(!showWorkspaceModal); }, [showWorkspaceModal]); const onClickAddChannel = useCallback(() => { setShowCreateChannelModal(true); }, []); 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 }} onCloseModal={onClickUserProfile} show={showUserMenu}> <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?.map((ws: IWorkspace) => { return ( <Link key={ws.id} to={`/workspace/${123}/channel/일반`}> <WorkspaceButton>{ws.name.slice(0, 1).toUpperCase()}</WorkspaceButton> </Link> ); })} <AddButton onClick={onClickCreateWorkspace}>+</AddButton> </Workspaces> <Channels> <WorkspaceName onClick={toggleWorkspaceModal}>Sleact</WorkspaceName> <MenuScroll> <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> {channelData?.map((v, idx) => ( <div key={idx}>{v.name}</div> ))} </MenuScroll> </Channels> <Chats> {children}</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} /> </div> ); }; export default Workspace; createChannelModal import Modal from '@components/modal'; import useInput from '@hooks/useInput'; import { Button, Input, Label } from '@pages/signup/styles'; import { IChannel, IUser } from '@typings/db'; import fetcher from '@utils/fetcher'; import axios from 'axios'; import React, { useCallback, VFC } from 'react'; import { useParams } from 'react-router-dom'; import { toast } from 'react-toastify'; import useSWR from 'swr'; interface Props { show: boolean; onCloseModal: () => void; setShowCreateChannelModal: (flag: boolean) => void; } const CreateChannelModal: VFC<Props> = ({ show, onCloseModal, setShowCreateChannelModal }) => { const [newChannel, onChangeNewChannel, setNewChannel] = useInput(''); const { workspace, channel } = useParams<{ workspace: string; channel: string }>(); const { data: userData } = useSWR<IUser | false>(`/api/users`, fetcher); const { data: channelData, mutate } = useSWR<IChannel[]>( userData ? `/api/workspaces/${workspace}/channels` : null, fetcher, ); const onCreateChannel = useCallback( (e) => { e.preventDefault(); axios .post( `/api/workspaces/${workspace}/channels`, { name: newChannel, }, { withCredentials: true }, ) .then((res) => { setShowCreateChannelModal(false); mutate(res.data); setNewChannel(''); }) .catch((err) => { console.dir(err); toast.error(err.response?.data, { position: 'bottom-center' }); }); }, [newChannel], ); return ( <Modal show={show} onCloseModal={onCloseModal}> <form onSubmit={onCreateChannel}> <Label id="channel-label"> <span>채널</span> <Input id="channel" value={newChannel} onChange={onChangeNewChannel} /> </Label> <Button type="submit">생성하기</Button> </form> </Modal> ); }; export default CreateChannelModal;

  • 웹팩
  • typescript
  • react
  • Socket.io
  • babel
  • 클론코딩
soh308 댓글 3 좋아요 0 조회수 617

안녕하세요. invailhost header 질문

미해결

Slack 클론 코딩[실시간 채팅 with React]

현재 슬랙클론 수강중인 학생입니다. 저는 군대에서 독학으로 공부중입니다. 현재 제로초님 깃허브에서 git clone 하여 그대로 데모버전을 사용하고 있습니다. 제가 사용하는 에디터는 구름ide를 사용하고 있는데 구름 ide 에서는 localhost를 제공해주지 않고, 제가 port를 설정하면 구름에서 제공해주는 사이트 주소를 사용하는 식으로 운영됩니다. 제가 본 영상에서와 같이 dependency까지 그대로 다운받고, npm run dev 명령어를 실행하면 당연히 localhost가 없기때문에 사이트 접속이 힘듭니다.... 그래서 port 3090에 맞게 url에 접속하면 invaild host header 에러가 나옵니다.. 전에 위 에러를 만났을 때는 항상 cra로 개발했기 때문에 금방 구글링으로 해결을 했는데 현재는 어떻게 해결해야 할지 모르는 상황입니다..

  • babel
  • Socket.io
  • typescript
  • react
  • 웹팩
  • 클론코딩
댓글 2 좋아요 0 조회수 263

npx sequelize db:create 오류

미해결

Slack 클론 코딩[실시간 채팅 with React]

ws@DESKTOP-9H6S8B6 MINGW64 ~/Desktop/sleact/back $ npx sequelize db:create Sequelize CLI [Node: 16.15.0, CLI: 6.4.1, ORM: 6.21.4] Loaded configuration file "config\config.js". Using environment "development". ERROR: Access denied for user 'root'@' localhost ' (using password: NO) 이런 오류가 계속 뜨고 다른 분들께서 질문하신 답변을 봐도 모르겠습니다... mysql 비밀번호는 확실하게 맞습니다.

  • Socket.io
  • babel
  • react
  • 웹팩
  • typescript
  • 클론코딩
wsws 댓글 1 좋아요 1 조회수 631

500에러 질문

미해결

Slack 클론 코딩[실시간 채팅 with React]

제로초님 깃헙코드 보고 리액트쿼리로 공부하다가 DM 보내는 로직에서 500에러가 떳습니다~!! api 문서대로 요청보냈고, 분명 서버쪽은 문제가 없을텐데 싶어서 며칠 째 고민하다 질문드려요!!! NaN으로 뜨는 부분이 백엔드 코드에서 콘솔 찍어보니까 req.query.perPage 이게 언디파인드로 전달 되더라구요. 근데 저는 perPage를 제로초님처럼 20으로 고정해서 전달하고 있는데 언디파인드로 뜨는게 이상하더라구요.ㅜㅜ +) 그리고 뮤테이션 쿼리키를 ["workspace", workspace, "dm", id, "chat"] 이렇게 주신 이유가 궁금해요!! 제가 공식문서 읽고 이해한게 배열로 줄 경우 첫번째 값이 캐싱할 때 쓰이는 이름이고 그 위에있는 애들은 mutation 안에서 사용될 외부 값을 넣어준다고 이해했었거든요!! 근데 dm 이나 chat은 사용되지 않는 것 같아서요!!

  • typescript
  • 웹팩
  • react
  • babel
  • Socket.io
  • 클론코딩
댓글 1 좋아요 0 조회수 369

npx sequelize db:create 입력시 에러 발생

미해결

Slack 클론 코딩[실시간 채팅 with React]

back 폴더에 npm i 이후 npx sequelize db:create 입력시 npm ERR! could not determine executable to run npm ERR! A complete log of this run can be found in: npm ERR! /Users/eycha/.npm/_logs/2022-08-21T06_14_10_186Z-debug-0.log 라는 에러 발생합니다. mysql 과 node 정상적으로 설치했는데 관련되서 검색해도 해결책이 없어서 질문 남깁니다.

  • react
  • Socket.io
  • babel
  • typescript
  • 웹팩
  • 클론코딩
차은엽 댓글 5 좋아요 0 조회수 2265

sleact/alecture/pages/login/styles.tsx ?

해결됨

Slack 클론 코딩[실시간 채팅 with React]

깃헙에서 sleact/alecture/pages/login/styles.tsx 파일이 비워 있는데 일부러 비워 두신거죠?

  • 클론코딩
  • react
  • babel
  • 웹팩
  • typescript
  • Socket.io
장산 댓글 1 좋아요 0 조회수 395

안녕하세요 웹팩 관련질문입니다.

해결됨

Slack 클론 코딩[실시간 채팅 with React]

안녕하세요! 웹팩 관련 질문이있습니다. 제꺼 빌드용량이 3MB로 엄청크더라구요. 그래서 원인을 알아보니 isDevelopment가 계속 development 모드로 빌드 되는게 이유였습니다. devtool설정은 아래와 같이했는데 development이다 보니까 계속 inline source map 으로 작동해서 파일크기가 큰것같더라고요. isDevelopment ? ' inline-source-map ' : ' hidden-source-map ' 차이점을 보니 npm script가 start는 webpack serve, build는 webpack만 되어있는 상태였어요. 그래서 start 에는 webpack serve --env development build에는 NODE_ENV=production webpack 를 적어주니까 production모드로 되고, 300kb로 떨어진걸 확인했어요. 그런데 start는 --env development이고, build는 NODE_ENV=production인 이유가 있나요? 둘다 --env development, --env production을 적거나 NODE_ENV=development, NODE_ENV=production으로 하는것과 차이가 있나요? 공식문서에서는 webpack dev와 prod로 파일을 다르게하는 아래방법밖에 못찾았는데, "start": "webpack serve --open --config webpack.dev.js", "build": "webpack --config webpack.prod.Js 제로초님은 어떤걸 보고 하셨는지 궁금합니다. 그리고 EnvironmentPlugin은 적지 않아도 console.log(isDevelopment)를 찍어보면 process.env.NODE_ENV 상태가 출력되고 빌드/실행도 잘되던데, 아래와같이 추가해야하는 이유가 있는지도 궁금합니다. new webpack . EnvironmentPlugin ( { NODE_ENV : isDevelopment ? 'development' : 'production' ,

  • react
  • Socket.io
  • 웹팩
  • babel
  • typescript
  • 클론코딩
댓글 1 좋아요 0 조회수 304

[06:26 부분] 정규표현식으로 문자열 변환하기 부분 질문할게요

미해결

Slack 클론 코딩[실시간 채팅 with React]

정규식으로 닉네임 찾는 부분에서요 match.match(/@\[(.+?)]\((\d+?)\)/)! 여기 이부분에서 느낌표(!)를 왜 붙여준건가요? str.match(정규표현식) 이런 형태로 작성하는 건줄 알았는데 느낌표가 붙여있어서 궁금해서 질문올립니다.

  • 웹팩
  • typescript
  • Socket.io
  • babel
  • react
  • 클론코딩
hoze12 댓글 1 좋아요 1 조회수 643

tsconfig관련 질문 있습니다

미해결

Slack 클론 코딩[실시간 채팅 with React]

슬리액트 강의 내용 일렉트론으로 작업해 보려고 따라하는 중에 tsconfig path 설정에서 오류가 생겼습니다. import 경로 위에 컨트롤 + 마우스클릭 할 경우 정상적으로 해당 파일로 이동합니다. 근데 막상 서버 실행 시에는 아래와 같은 오류가 나더라구요. 참고로 저는 CRA를 사용했습니다!! 스택오버플로우 아래 해결책도 해보았는데 해결이 안되어서 질문드립니다ㅠㅠ 제 tsconifg.json 입니다~!! 방향 잡아주시면 또 열심히 찾아보겠습니다 감사합니다!! ㅠㅠ { "compilerOptions": { "target": "es5", "lib": ["dom", "dom.iterable", "esnext"], "allowJs": true, "skipLibCheck": true, "esModuleInterop": true, "allowSyntheticDefaultImports": true, "strict": true, "forceConsistentCasingInFileNames": true, "noFallthroughCasesInSwitch": true, "module": "esnext", "moduleResolution": "node", "resolveJsonModule": true, "isolatedModules": true, "noEmit": true, "jsx": "react-jsx", "baseUrl": "./src", "paths": { "@hooks/*": ["src/hooks/*"], "@components/*": ["src/components/*"], "@pages/*": ["src/pages/*"], "@utils/*": ["src/utils/*"], "@types/*": ["src/types/*"] }, "plugins": [{ "transform": "typescript-transform-paths" }] }, "include": ["src"] }

  • Socket.io
  • 웹팩
  • babel
  • react
  • typescript
  • 클론코딩
댓글 1 좋아요 0 조회수 237

인기 태그

인프런 TOP Writers

주간 인기글