묻고 답해요
161만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결코로나맵 개발자가 알려주는 React + Express로 지도서비스 만들기 (Typescript)
보일러 플레이트 다운 시 빈 폴더
소스 코드 다운받았을 때 깨지는 지 빈 폴더로 나옵니다!그리고 해당 프로젝트 깃 허브 부탁드려용
-
미해결[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
이벤트 위임 관련 질문드려요!
안녕하세요!이벤트 위임이란 이벤트 버블링을 이용하여 상위 태그에 이벤트 핸들러를 할당하여 하위 태그에서 중복되는 이벤트들을 없앨 수 있다. 이 과정에서 원치 않은 이벤트 버블링를 막기 위해서는 event.stopPropagation() 함수를 사용해야 한다. 라고 이해했습니다.이벤트 위임 관련해서 구글링 해보니, 구현 방식에 있어서 자바스크립트와 리액트에서 차이가 있다고 보았는데 자료들이 부정확하고 이해하기 어려워서 질문드립니다. 리액트와 자바스크립트에서 이벤트 버블링 구현시 어떤 차이가 있으며 그 이유와 원리에 대해 설명 부탁드립니다..!항상 좋은 강의 감사드립니다이벤트 위임 관련 아래 링크 첨부합니다.https://github.com/facebook/react/issues/13635https://github.com/facebook/react/issues/13625
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
이벤트 핸들러 관련 질문드려요!
안녕하세요! 이벤트처리 함수 관련해서 질문드립니다.현재는 event를 넘겨서 처리하고 있다보니 currentTaget이니 target이니 신경 쓸 것이 많은데, <div onClick(() => onClickAlert(el.writer)} > 이렇게 바로 id의 값을 바인딩시켜줘도 되지 않나요?혹시 수업에서와 같이 <div id={el.writer} onClick={onClickAlert}> id 속성을 부여하고 이를 onClickAlert에서 event를 받아서 처리해야만 하는 상황이나 위와 같이 했을 때의 이점이 있는지 궁금합니다!항상 좋은 강의 감사드려요!
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트
docker compose 를 통한 배포 관련 오류 문의
안녕하세요. 강사님django의 기능들이 너무 많아 전체 흐름이 기억 나지 않을 때 계속해서 보고 있습니다.항상 좋은 강의 감사드립니다.drf로 만든 부분을 이번에는 pytest로 테스트 코드를 작성해보려고 하는데요.docker-compose-test.yml로 작성한 test용 mysql container를 띄웠습니다.하지만 테스트 코드를 실행하면 접근할 수 없다는 에러가 발생됩니다."Access denied for user 'project'@'localhost' (using password: YES)")구글링을 해봤고, 그래서 다음 순서로 확인을 해봤습니다.host namedb namepasswordportprint 로 출력했지만 동일한 내용으로 확인되었습니다. .env 내용.env 를 사용하여 compose에게 환경 정보를 읽어오도록 설정했습니다. DJANGO_SECRET_KEY=... # COMMON DB_ENGINE='django.db.backends.mysql' # DEVELOP DB DEV_DB_HOST='db.mysql' DEV_DB_USER='project' DEV_DB_PASSWORD='a1s2d3f4' DEV_DB_NAME='account_book' DEV_DB_PORT='3306' # TEST DB TEST_DB_HOST='test.mysql' TEST_DB_USER='test' TEST_DB_PASSWORD='a1s2d3f4' TEST_DB_NAME='test' TEST_DB_PORT='3310'docker-compose-test.yml 내용과 실행 명령어실행 명령어: docker-compose -f docker-compose-test.yml up위 명령어를 실행한 후 docker container ls 로 확인하면 다음 상태가 뜹니다.docker-compose-test.yml 내용은 다음과 같습니다. version: "3" services: test.mysql: container_name: test.mysql image: mysql:8.0.32 command: --authentication_policy=mysql_native_password restart: always environment: MYSQL_ROOT_PASSWORD: ${TEST_DB_PASSWORD} MYSQL_USER: ${TEST_DB_USER} MYSQL_PASSWORD: ${TEST_DB_PASSWORD} MYSQL_DATABASE: ${TEST_DB_NAME} TZ: Asia/Seoul volumes: - test_mysql_db:/var/lib/mysql ports: - ${TEST_DB_PORT}:3306 expose: - ${TEST_DB_PORT} volumes: test_mysql_db: django의 설정 부분은 backend/config/settings 밑에 base.py , develop.py, test.py 로 나눴습니다.위 docker compose는 아래 test.py 에 있는 db 정보와 일치하도록 했습니다.from config.settings.base import * INSTALLED_APPS += [ "debug_toolbar", ] MIDDLEWARE = [ "debug_toolbar.middleware.DebugToolbarMiddleware", ] + MIDDLEWARE # Database # https://docs.djangoproject.com/en/4.2/ref/settings/#databases DATABASES = { "default": { "ENGINE": env.str("DB_ENGINE"), # "HOST": env.str("TEST_DB_HOST"), "HOST": "localhost", "USER": env.str("TEST_DB_USER"), "PASSWORD": env.str("TEST_DB_PASSWORD"), "NAME": env.str("TEST_DB_NAME"), "PORT": env.int("TEST_DB_PORT"), "TEST": {"NAME" : "test"} }, } print(DATABASES) # 아래 내용이 출력됩니다. """ {'default': { 'ENGINE': 'django.db.backends.mysql', 'HOST': 'localhost', 'USER': 'test', 'PASSWORD': 'a1s2d3f4', 'NAME': 'test', 'PORT': 3310, 'TEST' : {'NAME' : 'test'}, } } """host를 env.str("TEST_DB_HOST")로 하면 test.mysql 을 찾을 수 없다고 뜹니다. 하지만 localhost로 하면 "Access denied for user 'test'@'localhost' (using password: YES)") 에러가 발생됩니다.mysql만 docker compose 로 띄우고, pytest로 코드를 실행했습니다. db 접속은 @pytest.mark.django_db 데코레이터를 사용했습니다. pytest.ini 설정[pytest] DJANGO_SETTINGS_MODULE = backend.config.settings.test django_debug_mode = true addopts = --create-db --no-migrations python_files = "test_*.py" markers = signup--no-migrations 옵션을 제거해도 동일한 에러가 발생됩니다. 디렉토리 구조 . ├── Dockerfile ├── Dockerfile.dev ├── README.md ├── backend │ ├── __init__.py │ ├── common │ │ ├── conftest.py │ │ └── models.py │ ├── config │ │ ├── __init__.py │ │ ├── asgi.py │ │ ├── settings │ │ │ ├── __init__.py │ │ │ ├── base.py │ │ │ ├── develop.py │ │ │ ├── production.py │ │ │ └── test.py │ │ ├── urls.py │ │ └── wsgi.py │ ├── manage.py │ ├── static │ ├── templates │ └── users │ ├── __init__.py │ ├── admin.py │ ├── apps.py │ ├── models.py │ ├── serializers.py │ ├── test │ │ ├── __init__.py │ │ ├── conftest.py │ │ ├── test_api.py │ │ └── utils.py │ ├── tests.py │ ├── urls.py │ └── views.py ├── docker-compose-dev.yml ├── docker-compose-test.yml ├── docker-compose.yml ├── poetry.lock ├── pyproject.toml └── pytest.ini 지난 번 mysql docker 관련하여 질문드렸을 때 port 부분을 알려주셔서 port 부분 정보는 일치하도록 했으나, 제 눈에는 정보가 다른 걸 찾기 어려워 혼자 해보다가 결국 올립니다 ㅠㅠ 읽어주셔서 감사합니다 ㅠㅠ
-
해결됨손에 익는 Next.js - 공식 문서 훑어보기
서버 컴포넌트 관련 질문입니다!
SSR 방식에 서버 컴포넌트와 클라이언트 컴포넌트를 둘 다 적절히 사용하는 것인가요??서버 컴포넌트는 데이터 페칭, 보안, 캐싱, JS 번들크기 감소와 같은 장점이 있고 event와 hook을 사용하지 못한다는 특징도 이야기해주셨는데, 그렇다면 데이터를 받아서(페칭해서) 클라이언트 컴포넌트에 데이터를 뿌려주는 느낌으로 조합해서 사용하는 건가요??서버컴포넌트는 event를 사용하지 않으므로, TTI를 개선하기 위해 나온 개념은 아닌거죠???
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
section8 퀴즈 에러 질문입니다
안녕하세요, section8 퀴즈를 푸는 중 에러가 계속 해결되지 않아 글을 남기게 되었습니다.글 작성 후 상품 id를 가지고 상세 화면으로 넘어오는 것 까지 정상적으로 이루어지는데,상세 화면에서 정보를 불러오지 못하고 에러가 발생하고 있습니다.아래 코드와 발생하는 에러 첨부하였습니다.혹시 제가 어떤 부분을 잘못만들어서 에러가 나는지 알 수 있을까요?? import { useQuery, gql } from "@apollo/client"; import { useRouter } from "next/router"; const FETCH_PRODUCT = gql` query fetchProduct($id: ID){ fetchProduct(productId:$id){ _id seller name detail price } }` export default function ProductView(){ const router = useRouter(); const {data} = useQuery(FETCH_PRODUCT, { variables: {productId: router.query.number} }) console.log(data) return( <div>{router.query.number} 상품명 {data.fetchProduct.seller} 판매자 {data.fetchProduct.detail} </div> ) }
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
이거 배우면은 카페24를 자유자제로 쇼핑몰을 꾸밀 수 있나요?
이거 배우면은 카페24를 자유자제로 쇼핑몰을 꾸밀 수 있나요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
모바일의 경우 리디렉션에 대해 궁금증이 있습니다.
포트원 개발자 센터를 보면, 모바일의 경우 리디렉션을 하면서 쿼리스트링으로 imp_uid 등등의 데이터를 붙여서 보내주는걸로 보입니다. 해당 경우 리코일데이터를 비롯한 모든 데이터가 초기화 되지 않나요? 그렇다면, 로그인 정보를 비롯한 이런저런 데이터들은 어떻게 유지하고 있나요?로컬스토리지나 세션스토리지에 있는 엑세스토큰등을 이용해 아예 새롭게 데이터를 불러와야 하는걸까요?
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
create-react-app 관련
npx create-react-app 이렇게 만들면 src폴더 없이 만들어지더라구요 그래서 그냥 npx 없이 만드니까 정상적으로 잘 만들어지는데 npx가 있는거와 없는거의 차이점이 뭔지 궁금합니다
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
css를 불러오지 않아도 클래스 이름을 부여하여 스타일이 가능한가요?
useParams를 이용한 영화 상세 페이지 구현 파트8분 45초에서 css 파일을 불러오지 않고도modal__poster-img 클래스 이름을 부여하자 스타일이 반영되는 것을 확인할 수 있었습니다왜 이렇게 되는 걸까요?
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
로그인 실패 에러 (500 Internal Server Error)
회원가입 시 MySQL 테이블에 이메일, 비밀번호 저장되는 것을 확인하고 로그인을 시도했는데 계속 실패해서 질문드립니다 MySQL 워크벤치로 확인한 user 테이블을 보면 회원가입은 잘 되었는데 id: 2 의 메일, 비밀번호로 로그인이 안 됩니다 console.log로 확인해보니까 패스포트 로그인 시도에서 에러가 나는 것 같기는 한데 정확한 원인을 못 찾겠습니다.. 터미널에 뜨는 메시지입니다개발자도구_네트워크 화면입니다개발자도구_콘솔 화면입니다 의심스러운 코드입니다!routes/user.js 코드const express = require('express'); const bcrypt = require('bcrypt'); const passport = require('passport'); const { User } = require('../models'); const router = express.Router(); router.post('/login', (req, res, next) => { passport.authenticate('local', (err, user, info) => { if (err) { //서버쪽 에러 console.error(err); console.log('routes/user_server err') return next(err); } if (info) { //클라이언트쪽 에러 return res.status(401).send(info.reason); } return req.login(user, async (loginErr) => { if (loginErr) { //패스포트 로그인 에러 console.error(loginErr); console.log('routes/user_loginErr') return next(loginErr); } // res.setHeader('Cookie', 'cxlhy..랜덤토큰') return res.status(200).json(user); }); })(req, res, next); }); router.post('/', async (req, res, next) => { // POST /user try { const exUser = await User.findOne({ where: { email: req.body.email, } }); if (exUser) { return res.status(403).send('이미 가입된 메일입니다.'); } const hashedPassword = await bcrypt.hash(req.body.password, 10); //10~13 await User.create({ email: req.body.email, nickname: req.body.nickname, password: hashedPassword, }); res.status(201).send('OK'); } catch (error) { console.error(error); next(error); //next로 에러 처리 (한방에), status 500 } }); module.exports = router; app.js 코드const express = require('express'); const cors = require('cors'); const session = require('express-session'); const cookieParser = require('cookie-parser'); const passport = require('passport'); const dotenv = require('dotenv'); const postRouter = require('./routes/post'); const userRouter = require('./routes/user'); const db = require('./models'); const passportConfig = require('./passport'); dotenv.config(); const app = express(); db.sequelize.sync() .then(() => { console.log('db 연결 성공'); }) .catch(console.error); passportConfig(); app.use(cors({ origin: 'http://localhost:3000', credentials: false, })); app.use(express.json()); app.use(express.urlencoded({ extended: true })); app.use(cookieParser(process.env.COOKIE_SECRET)); app.use(session({ saveUninitialized: false, resave: false, secret: process.env.COOKIE_SECRET, })); app.use(passport.initialize()); app.use(passport.session()); ~이하생략~ passport/index.js 코드const passport = require('passport'); const local = require('./local'); const { User } = require('../models'); module.exports = () => { passport.serializeUser((user, done) => { done(null, user.id); }); passport.deserializeUser(async (id, done) => { try { const user = await User.findOne({ where: { id } }); done(null, user); //req.user } catch (error) { console.error(error); done(error); } }); local(); }; passport/local.js 코드const passport = require('passport'); const { Strategy: LocalStrategy } = require('passport-local'); const bcrypt = require('bcrypt'); const { User } = require('../models'); module.exports = () => { passport.use(new LocalStrategy({ usernameField: 'email', //id칸 passwordField: 'password', //비밀번호칸 }, async (email, password, done) => { //done으로 결과 판단 try { const user = await User.findOne({ //가입된 이메일이 있는지 검사 where: { email } }); if (!user) { return done(null, false, { reason: '존재하지 않는 이메일입니다.' }); } const result = await bcrypt.compare(password, user.password) if (result) { return done(null, user); } return done(null, false, { reason: '비밀번호가 일치하지 않습니다.' }); } catch (error) { console.error(error); return done(error); } })); };
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
setStatus, 콜백함수, 변수 스코프에 대해 질문드립니다.
강사님 안녕하세요항상 상세한 답변을 주시는 점 감사드립니다.아래의 코드를 보고 질문을 받아주시면 감사하겠습니다.import './App.css'; import Counter from './Counter'; import Container from './Container'; import {useEffect, useState} from "react"; import MyHeader from './MyHeader.js' export default function App() { const [state, setState] = useState({ a: 0, b: 0 }); const onClick = () => { const c=10; setState(c=>({ a: c + 1 })); }; return ( <div className="App"> <div>a : {state.a}</div> <button onClick={onClick}>증가</button> </div> ); }1번째 경우원래는 아래의 코드처럼 setState의 콜백함수의 인자에 state를 넣는 게 맞습니다.const c=10; setState(state=>({ a: c + 1 // 이 줄의 c는 1번째 줄의 c를 가리키므로 a: 10 + 1 과 같습니다. }));이때는 a:c+1에서의 c가 함수 밖에 선언된 맨위의 const c= 10의 c를 가리킵니다. 2번째 경우 일부러 setState의 콜백함수의 인자를 state가 아닌 c로 적어봤습니다.const c=10; setState(c=>({ //이 부분 변경 state 를 지우고 c로 a: c + 1 // 이 줄에서의 c는 1번째 줄의 c를 가리키지 않습니다. }));그러자 a: c + 1 에서의 c는 1번째 줄의 c가 아닌, 콜백함수 인자로 들어간 2번째 줄의 c를 가리킵니다.그래서 변수의 스코프를 공부하고 싶어서 조언을 구하고 싶습니다. 1번째 질문을 드립니다.변수가 const, let, var 인지에 따라서 스코프가 다른 것으로 아는데콜백함수의 인자로 들어간 변수는 const인지 let인지, var 인지 질문드리고 싶습니다. 2번째 질문을 드립니다.이 부분에 대해 학습하면 좋을 자료 링크를 추천해주시면 감사하겠습니다.저도 현재 변수 스코프에 대해 다시 공부하는 중입니다.3번째 질문을 드립니다.const c=10; setState(c=>({ //이 부분 변경 state 를 지우고 c로 a: c + 1 // 이 줄에서의 c는 1번째 줄의 c를 가리키지 않습니다. })); 에서2번째 줄의 콜백함수 인자의 c는 1번째 줄의 c를 가리키지 못하는 이유에 대해 질문드리고 싶습니다.4번째 질문을 드립니다.const c=10; setState(state=>({ //이 부분 변경 state 를 지우고 c로 a: c + 1 // 이 줄에서의 c는 1번째 줄의 c를 가리키지 않습니다. }));3번째 줄의 c는 1번째 줄의 c를 가리킬 수 있는 이유에 대해 질문드리고 싶습니다감사합니다.
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
newaccessToken 질문드립니다
만약에 지금 발급된 accessToken 이 만료되지 않은 상황이라면 해당 강의에서의 aaa.toPromise().then((newAccessToekn) =>{}) 함수 실행시에 newAccessToken 이 발급되지 않는 걸까요?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 챗봇 사이트 만들기
dialogflow 줄바꿈
dialogflow에서 작성한 text reaponse에서 줄바꿈은 shift+enter로 무사히 되어있고, postman으로 확인했을 때도 되어있는데요노드리액트로 만든 localhost페이지에서는 자꾸 줄바꿈이 안되고 통째로 떠요,,왜 이럴까요ㅠ
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기
npm run dev 동작에러납니다...
PS C:\Users\Desktop\boilerplate-mern-stack> yarn dev yarn run v1.22.19 $ concurrently "npm run backend" "npm run start --prefix client" [1] [1] > client@0.1.0 start [1] > react-scripts start [1] [0] [0] > react-boiler-plate@1.0.0 backend [0] > nodemon server/index.js [0] [0] [nodemon] 1.19.4 [0] [nodemon] to restart at any time, enter `rs` [0] [nodemon] watching dir(s): *.* [0] [nodemon] watching extensions: js,mjs,json [0] [nodemon] starting `node server/index.js` [0] Server Listening on 5000 [0] MongooseError: The `uri` parameter to `openUri()` must be a string, got "undefined". Make sure the first parameter to `mongoose.connect()` or `mongoose.createConnection()` is a string. [0] at Connection.openUri (C:\Users\Desktop\boilerplate-mern-stack\node_modules\mongoose\lib\connection.js:694:11) [0] at C:\Users\Desktop\boilerplate-mern-stack\node_modules\mongoose\lib\index.js:351:10 [0] at C:\Users\Desktop\boilerplate-mern-stack\node_modules\mongoose\lib\helpers\promiseOrCallback.js:32:5 [0] at new Promise (<anonymous>) [0] at promiseOrCallback (C:\Users\Desktop\boilerplate-mern-stack\node_modules\mongoose\lib\helpers\promiseOrCallback.js:31:10) [0] at Mongoose._promiseOrCallback (C:\Users\Desktop\boilerplate-mern-stack\node_modules\mongoose\lib\index.js:1149:10) [0] at Mongoose.connect (C:\Users\Desktop\boilerplate-mern-stack\node_modules\mongoose\lib\index.js:350:20) [0] at Object.<anonymous> (C:\Users\Desktop\boilerplate-mern-stack\server\index.js:19:4) [0] at Module._compile (node:internal/modules/cjs/loader:1233:14) [0] at Module._extensions..js (node:internal/modules/cjs/loader:1287:10) [0] at Module.load (node:internal/modules/cjs/loader:1091:32) [0] at Module._load (node:internal/modules/cjs/loader:938:12) [0] at Function.executeUserEntryPoint [as runMain] (node:internal/modules/run_main:83:12) [0] at node:internal/main/run_main_module:23:47 [1] [HPM] Proxy created: / -> http://localhost:5000 [1] i 「wds」: Project is running at http://192.999.111.116/ [1] i 「wds」: webpack output is served from [1] i 「wds」: Content not from webpack is served from C:\Users\Desktop\boilerplate-mern-stack\client\public [1] i 「wds」: 404s will fallback to / [1] Starting the development server... [1] [1] Error: error:0308010C:digital envelope routines::unsupported [1] at new Hash (node:internal/crypto/hash:69:19) [1] at Object.createHash (node:crypto:138:10) [1] at module.exports (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\util\createHash.js:135:53) [1] at NormalModule._initBuildHash (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:417:16) [1] at handleParseError (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:471:10) [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:503:5 [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:358:12 [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\loader-runner\lib\LoaderRunner.js:373:3 [1] at iterateNormalLoaders (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\loader-runner\lib\LoaderRunner.js:214:10) [1] at iterateNormalLoaders (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\loader-runner\lib\LoaderRunner.js:221:10) [1] C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\react-scripts\scripts\start.js:19 [1] throw err; [1] ^ [1] [1] Error: error:0308010C:digital envelope routines::unsupported [1] at new Hash (node:internal/crypto/hash:69:19) [1] at Object.createHash (node:crypto:138:10) [1] at module.exports (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\util\createHash.js:135:53) [1] at NormalModule._initBuildHash (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:417:16) [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:452:10 [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\webpack\lib\NormalModule.js:323:13 [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\loader-runner\lib\LoaderRunner.js:367:11 [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\loader-runner\lib\LoaderRunner.js:233:18 [1] at context.callback (C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\loader-runner\lib\LoaderRunner.js:111:13) [1] at C:\Users\Desktop\boilerplate-mern-stack\client\node_modules\react-scripts\node_modules\babel-loader\lib\index.js:59:103 { [1] opensslErrorStack: [ 'error:03000086:digital envelope routines::initialization error' ], [1] library: 'digital envelope routines', [1] reason: 'unsupported', [1] code: 'ERR_OSSL_EVP_UNSUPPORTED' [1] } [1] [1] Node.js v20.5.1 [1] npm run start --prefix client exited with code 1반나절 넘게 이 오류만 붙잡고 있었는데 해결이 안되네요...사이트에 연결할 수 없음연결이 재설정되었습니다.다음 방법을 시도해 보세요.연결 확인프록시 및 방화벽 확인Windows 네트워크 진단 프로그램 실행브라우저에서 위와 같이 뜨는데 이유가 뭘까요....
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
수업 정답코드좀 알려주세요
이부분 이거 말고도 소과제 있는 부분 전부 다 정답코드 어디에 있나요? 아무리 찾아도 안나와요 자세한 경로좀 알려주세요
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
서버사이드 렌더링 적용 후, css가 풀렸다가 다시 적용되는것 같아요.
안녕하세요!서버사이드 렌더링 적용후에 css가 풀렸다가 다시적용되는 것 같은데, 해결 방법이 있을까요?로그인 후 새로고침을 하면 잠깐 첫번째 화면이 보였다가 두번째 화면을 보여줍니다. 세번째 화면은 리덕스 상태입니다.서버사이드 렌더링을 해서 user와 post의 데이터는 잘 받아오고 있는것 같습니다.
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
페이지구현 - 일기수정(Edit) 수정 에러 질문
정환님 안녕하세요.질문이 있습니다.DiaryEditor 컴포넌트로 onCreate, onEdit 함수를 전달하여일기를 생성, 수정 하는데요.이때, 일기 생성 후, 일기를 수정 하면 수정된 일기 + 수정된 일기가 1개 더 추가 생성이 되는 에러가 발생하여서요.어떤 부분이 문제인지 짐작이 안갑니다. ㅠㅠ아래 코드 캡쳐본 첨부드립니다.답변주시면 감사하겠습니다.그리고 강의 잘 듣고있습니다. 좋은 강의 감사합니다 :) App 컴포넌트Edit 컴포넌트DiaryEditor 컴포넌트
-
미해결Slack 클론 코딩[실시간 채팅 with React]
onScroll 스크롤 위치 유지가 안됩니다 ㅠ
import Chat from '@components/Chat'; import { ChatZone, Section, StickyHeader } from '@components/ChatList/style'; import { IChat, IDM } from '@typings/db'; import React, { FC, RefObject, VFC, forwardRef, useCallback, useRef } from 'react'; import { Scrollbars } from 'react-custom-scrollbars'; interface Props { scrollRef: RefObject<Scrollbars>; chatSections: { [key: string]: IDM[] }; setSize: (f: (index: number) => number) => Promise<IDM[][] | undefined>; isEmpty: boolean; isReachingEnd: boolean; } const ChatList: VFC<Props> = (({ chatSections, setSize, isEmpty, scrollRef, isReachingEnd}) => { const onScroll = useCallback((values) => { // 끝에 도달하면 불러오지 않기 if(values.scrollTop === 0 && !isReachingEnd){ console.log('가장 위'); setSize((prevSize) => prevSize + 1).then(()=>{ // 스크롤 위치 유지 if(scrollRef?.current){ scrollRef.current?.scrollTop(scrollRef.current?.getScrollHeight() - values.scrollHeight); } }); } }, []); return ( <ChatZone> <Scrollbars autoHide ref={scrollRef} onScrollFrame={onScroll}> {Object.entries(chatSections).map(([date, chats]) => { return ( <Section className={`section-${date}`} key={date}> <StickyHeader> <button>{date}</button> </StickyHeader> {chats.map((chat) => ( <Chat key={chat.id} data={chat} /> ))} </Section> ); })} </Scrollbars> </ChatZone> ); }); export default ChatList; 이쪽 코드는 문제가 없는것같은데 희한하게 위치가 유지가 되지않고 원래처럼 쭉 올라가버립니다.. ref쪽이 문제인가요..? 혹시몰라 DirectMessage 컴포넌트도 아래에 첨부하겠습니다.import React, { useCallback, useEffect, useRef } from 'react'; import gravator from 'gravatar'; import useSWR, { mutate } from 'swr'; // swr 인피니티스크롤링 전용 메서드 import useSWRInfinite from 'swr/infinite'; import { IDM, IUser } from '@typings/db'; import fetcher from '@utils/fetcher'; import { useParams } from 'react-router'; import ChatBox from '@components/ChatBox'; import { Container, Header } from '@pages/DirectMessage/style'; import ChatList from '@components/ChatList'; import useInput from '@hooks/useInput'; import axios from 'axios'; import makeSection from '@utils/makeSection'; import Scrollbars from 'react-custom-scrollbars'; const DirectMessage = () => { const { workspace, id } = useParams<{ workspace: string; id: string }>(); const { data: userData } = useSWR(`http://localhost:3095/api/workspaces/${workspace}/users/${id}`, fetcher); // 내정보 const { data: myData } = useSWR(`http://localhost:3095/api/users`, fetcher); const [chat, onChangeChat, setChat] = useInput(''); // 과거 채팅리스트에서 채팅을 치면 최신목록으로 바로 스크롤을 내려줄려면 ref를 // 이 컴포넌트에서 props로 내려줘야하기 때문에 forwardRef를 사용해서 props로 넘겨준다 // 💡 HTML 엘리먼트가 아닌 React 컴포넌트에서 ref prop을 사용하려면 React에서 제공하는 forwardRef()라는 함수를 사용해야 합니다 const scrollbarRef = useRef<Scrollbars>(null); // 채팅 받아오는곳 (setSize : 페이지수를 바꿔줌) // useSWRInfinite를 쓰면 [{id:1},{id:2},{id:3},{id:4}] 1차원배열이 [[{id:1},{id:2}],[{id:3},{id:4}]] 2차원배열이 된다. const { data: chatData, mutate: mutateChat, setSize, } = useSWRInfinite<IDM[]>( (index) => `http://localhost:3095/api/workspaces/${workspace}/dms/${id}/chats?perPage=20&page=${index + 1}`, fetcher, ); // 데이터 40 개중에 20개씩 사져오면 첫번째페이지부터 20 + 20 + 0 세번째 페이지 0 이되면 isEmpty, isReachingEnd는 true가 됨 // 반대의 상황에서 데이터가 45개면 20 + 20 + 5 isEmpty는 0이 아니라서 false isReachingEnd는 여전히 데이터 가져옴 const isEmpty = chatData?.[0]?.length === 0; const isReachingEnd = isEmpty || (chatData && chatData[chatData.length - 1]?.length < 20) || false; const onSubmitForm = useCallback( (e) => { e.preventDefault(); if (chat?.trim() && chatData) { const savedChat = chat; // 💡 옵티미스틱 UI // 서버쪽에 다녀오지 않아도 성공해서 데이터가 있는거처럼 보이게 미리 만듦 mutateChat((prevChatData) => { // infinite 스크롤링은 2차원 배열이다. prevChatData?.[0].unshift({ // 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) // 옵티미스틱 UI 할땐 이부분이 항상 false .then(()=>{ setChat(''); // 버튼클릭 시 기존 채팅지우기 scrollbarRef.current?.scrollToBottom(); // 채팅 첬을때 맨 아래로 }) axios .post( `http://localhost:3095/api/workspaces/${workspace}/dms/${id}/chats`, { content: chat, }, { withCredentials: true, }, ) .then(() => { mutateChat(); // SWR에서 데이터를 다시 불러와서 캐시를 갱신하는 역할을 합니다. }) .catch(() => { console.error; }); } }, [chat, chatData, myData, userData, workspace, id], ); // (채팅이 최신것을 아래에 두기 위함) = 기존것 데이터를두고 새 데이터를 뒤집어서 출력 / flat() 배열을 1차원 배열로 만들어줌 const chatSections = makeSection(chatData ? [...chatData].flat().reverse() : []); // 로딩 시 스크롤바 제일 아래로 useEffect(()=>{ if(chatData?.length === 1){ // 채팅 데이터가 있어서 불러온 경우 scrollbarRef.current?.scrollToBottom(); // 가장 아래쪽으로 내려줌 } },[chatData]) // 로딩 if (!userData || !myData) { return null; } return ( <Container> <Header> <img src={gravator.url(userData.email, { s: '24px', d: 'retro' })} alt={userData.nickname}></img> <span>{userData.nickname}</span> </Header> {/* 컴포넌트 위치를 미리 지정해도 좋다. */} {/* 전역 상태관리 라이브러리를 사용해도 컴포넌트상황에따라 props 로 넘겨줌*/} <ChatList scrollRef={scrollbarRef} chatSections={chatSections} setSize={setSize} isEmpty={isEmpty} isReachingEnd={isReachingEnd} /> <ChatBox chat={chat} onChangeChat={onChangeChat} onSubmitForm={onSubmitForm} /> </Container> ); }; export default DirectMessage;
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
섹션 13 대댓글 과제 관련 질문
안녕하세요 과제로 받은 자유게시판 대댓글 기능 구현과 관련한 질문이 있어 글 남깁니다 우선 포트폴리오 과제를 진행할 때 사용하는 플레이그라운드 주소는https://backend-practice.codebootcamp.co.kr/graphql다음과 같습니다 플레이그라운드를 확인해보니 대댓글과 관련된 쿼리와 뮤테이션은UseditemQuestions, UseditemQuestionAnswers 인 것 같은데요대댓글과 관련된 다른 질문들을 통해 댓글=질문, 대댓글=질문에 대한 답변으로 생각하면 된다는 답변을 보았습니다 현재 자유게시판 댓글과 관련된 과제를 진행할 때 사용한 쿼리와 뮤테이션은BoardComments 인데요그러면 BoardComment 쿼리와 뮤테이션을 사용해 구현한 댓글 기능을 UseditemQuestion으로 변경해야 대댓글 기능을 구현할 수 있는 건가요?