묻고 답해요
147만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
순위 정보를
불러오고 있어요
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
CSS
영화 상세페이지 구현에서 className으로 modal_poster-img를 주니까 다른 곳에 있던 css가 적용되는데 위에 import하지 않아도 가능한건가요??
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
local storage
저장할 때밑에 코드를 쓰면 에러가 뜹니다ㅠㅠ어떻게 해결해야하나요?const initalTodoData = localStorage.getItem("todoData") ? JSON.parse(localStorage.getItem("todoData")) : []; function App() { const [todoData, setTodoData] = useState([initalTodoData]);
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
list컴포넌트 생성하기
List 컴포넌트 생성하기에서 props로 key={data.id}를 넘겨주는데 저기서는 사용하지 않는데 넘겨주어야 하나요? 빼도 상관 없나요??
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 유튜브 사이트 만들기
이미지 깨짐
선생님 url 까지는 받아왔는데 왜 이미지가 깨지는지 모르겠습니다하고 이미지 url로 타고 들어가면 404 에러도 나오는데 왜 이미지를 찾지 못하는지 모르겠습니다 app.post("/api/video/thumbnail", (req, res) => { let filePath = ""; let fileDuration = ""; //비디오 정보 가져오기 ffmpeg.ffprobe(req.body.url, function (err, metadata) { if (err) { console.error("Error getting video metadata:", err); return res.json({ success: false, err }); } console.dir(metadata); console.log(metadata.format.duration); fileDuration = metadata.format.duration; //썸네일 생성 ffmpeg(req.body.url) .on("filenames", function (filenames) { console.log("Will generate" + filenames.join(", ")); console.log(filenames); filePath = "uploads/thumbnails/" + filenames[0]; console.log(filePath); }) .on("end", function () { console.log("Screenshots taken"); return res.json({ success: true, url: filePath, fileDuration: fileDuration, }); }) .on("error", function (err) { console.error("Error generating thumbnails:", err); return res.json({ success: false, err }); }) .screenshots({ count: 3, folder: "uploads/thumbnails", size: "320x240", filename: "thumbnail-%b.jpeg", });404의 원인은 잘못된 url 인걸로 아는데 한 번 봐주셨으면 감사하겠습니
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
ssh xxxxx로 우분투에 들어가려니까 port 22: Connection timed out
nginx 부분을 따라하다가실수로 서버에서 나갔다가 다시 들어가려니까ssh: connect to host zzimzzim-front port 22: Connection timed out위와같은 에러가나면서 갑자기 들어가지지 않습니다.검색했는데도 해결되지 않아서 답답해다가이럴땐 어떤걸 참고하면 좋을지 조언 주시면 감사하겠습니다. ㅠ
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
sudo certbot --nginx 에러
ubuntu@ip-172-31-37-191:~/react-nodebird/prepare/front$ sudo certbot --nginx Saving debug log to /var/log/letsencrypt/letsencrypt.log Which names would you like to activate HTTPS for? We recommend selecting either all domains, or all domains in a VirtualHost/server block. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 1: zzimzzim.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Select the appropriate numbers separated by commas and/or spaces, or leave input blank to select all options shown (Enter 'c' to cancel): Requesting a certificate for zzimzzim.com Certbot failed to authenticate some domains (authenticator: nginx). The Certificate Authority reported these problems: Domain: zzimzzim.com Type: connection Detail: 3.37.101.58: Fetching http://zzimzzim.com/.well-known/acme-challenge/SNUl0WTK7OKWJ-oYyHTrIFuh67ww_P11CUJXw2zWRZk: Timeout during connect (likely firewall problem) Hint: The Certificate Authority failed to verify the temporary nginx configuration changes made by Certbot. Ensure the listed domains point to this nginx server and that it is accessible from the internet. Some challenges have failed. Ask for help or search for solutions at https://community.letsencrypt.org. See the logfile /var/log/letsencrypt/letsencrypt.log or re-run Certbot with -v for more details.위와같은 에러가 발생합니다.다른 질문들을 보고 제로초님https://www.zerocho.com/category/NodeJS/post/5ef450a5701d8a001f84baeb 따라해보았는데 해결되지 않아서 여쭤봅니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
Minified React error 콘솔에러 (hydrate)
안녕하세요 선생님카카오톡 공유하기 까지 듣고 화면을 테스트해보고 있는데Minified React error 이 에러가 떠서 질문드립니다. 메인화면, 상세보기에서 게시글이 있을때 나옵니다.Uncaught Error: Minified React error #418; visit https://reactjs.org/docs/error-decoder.html?invariant=418 for the full message or use the non-minified dev environment for full errors and additional helpful warnings. at lg (framework-ecc4130bc7a58a64.js:9:46457) at i (framework-ecc4130bc7a58a64.js:9:121052) at oO (framework-ecc4130bc7a58a64.js:9:99019) at framework-ecc4130bc7a58a64.js:9:98886 at oF (framework-ecc4130bc7a58a64.js:9:98893) at oS (framework-ecc4130bc7a58a64.js:9:93932) at x (framework-ecc4130bc7a58a64.js:33:1364) at MessagePort.T (framework-ecc4130bc7a58a64.js:33:1894)검색해봤더니 hydrate 쪽 이슈더라구요.혼자서 풀어보다가 잘 풀리지 않아서 여쭤봅니다.혹시 제로초님은 저런 에러가 나지 않으시는지난다면 어느 로직을 확인해야할지 조언 부탁드립니다./pages/post/[id].jsimport axios from 'axios'; import Head from 'next/head'; import { useRouter } from 'next/router'; import { useSelector } from 'react-redux'; import AppLayout from '../../components/AppLayout'; import PostCard from '../../components/PostCard'; import { loadPost } from '../../reducers/post'; import { loadMyInfo } from '../../reducers/user'; import wrapper from '../../store/configurStore'; const Post = () => { const router = useRouter(); const { id } = router.query; const { singlePost } = useSelector((state) => state.post); return ( <AppLayout> {singlePost ? ( <> <Head> <title> {singlePost?.User.nickname} 님의 글 </title> <meta name="description" content={singlePost.content} /> <meta property="og:title" content={`${singlePost.User.nickname}님의 게시글`} /> <meta property="og:description" content={singlePost.content} /> <meta property="og:image" content={ singlePost.Images[0] ? singlePost.Images[0].src : 'https://nodebird.com/favicon.ico' } /> <meta property="og:url" content={`https://nodebird.com/post/${id}`} /> </Head> <PostCard post={singlePost}>{id}번 게시글</PostCard> </> ) : ( <div>존재하지 않는 게시물입니다.</div> )} </AppLayout> ); }; export const getServerSideProps = wrapper.getServerSideProps( (store) => async ({ req, params }) => { const cookie = req ? req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; // 쿠키가 브라우저에 있는경우만 넣어서 실행 // (주의, 아래 조건이 없다면 다른 사람으로 로그인 될 수도 있음) if (req && cookie) { axios.defaults.headers.Cookie = cookie; } await store.dispatch(loadMyInfo()); await store.dispatch(loadPost(params.id)); }, ); export default Post; /components/PostCard.jsimport { RetweetOutlined, HeartOutlined, HeartTwoTone, MessageOutlined, EllipsisOutlined, } from '@ant-design/icons'; import { Card, Popover, Button, Avatar, List } from 'antd'; import dayjs from 'dayjs'; import Link from 'next/link'; import PropTypes from 'prop-types'; import { useState, useCallback, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import CommentForm from './CommentForm'; import Followbutton from './FollowButton'; import PostCardContent from './PostCardContent'; import PostImages from './PostImages'; import { removePostRequestAction, likePostRequestAction, unLikePostRequestAction, retweetRequestAction, } from '../reducers/post'; dayjs.locale('ko'); const PostCard = ({ post }) => { // const { me: {id} } = useSelector((state) => state.user); // const id = me && me.id; // const id = me?.id; // 옵셔널 체이닝 연산자 const { removePostLoading } = useSelector((state) => state.post); const dispatch = useDispatch(); const [commentFormOpend, setCommentFormOpend] = useState(false); const id = useSelector((state) => state.user.me?.id); const liked = post.Likers.find((d) => d.id === id); const onLike = useCallback(() => { if (!id) { alert('로그인이 필요합니다.'); } dispatch(likePostRequestAction(post.id)); }, [id]); const onUnLike = useCallback(() => { if (!id) { alert('로그인이 필요합니다.'); } dispatch(unLikePostRequestAction(post.id)); }, [id]); const onToggleComment = useCallback(() => { setCommentFormOpend((prev) => !prev); }, []); const onRemovePost = useCallback(() => { if (!id) { alert('로그인이 필요합니다.'); } dispatch(removePostRequestAction({ id: post.id })); }, [id]); const onRetweet = useCallback(() => { if (!id) { alert('로그인이 필요합니다.'); } dispatch(retweetRequestAction(post.id)); }, [id]); return ( <div style={{ marginTop: 10 }}> <Card cover={post.Images[0] && <PostImages images={post.Images} />} actions={[ // 배열안에 들어가는 것들은 다 key를 넣어줘야 한다. <RetweetOutlined key="retweet" onClick={onRetweet} />, liked ? ( <HeartTwoTone key="heart" twoToneColor="#eb2f96" onClick={onUnLike} /> ) : ( <HeartOutlined key="heart" onClick={onLike} /> ), <MessageOutlined key="comment" onClick={onToggleComment} />, <Popover key="more" content={ <Button.Group> {id && post.User?.id === id ? ( <> <Button type="primary" key="modify"> 수정 </Button> <Button type="danger" key="delete" onClick={onRemovePost} loading={removePostLoading} > 삭제 </Button> </> ) : ( <Button type="dashed" key="report"> 신고 </Button> )} </Button.Group> } > <EllipsisOutlined /> </Popover>, ]} extra={id && <Followbutton post={post} />} title={ post.RetweetId ? `${post.User.nickname}님이 리트윗하셨습니다.` : null } > {post.RetweetId && post.Retweet ? ( <Card cover={ post.Retweet.Images[0] && ( <PostImages images={post.Retweet.Images} /> ) } > <div style={{ float: 'right' }}> {dayjs(post.createdAt).format('YYYY.MM.DD')} </div> <Card.Meta avatar={ <Link href={`/user/${post.Retweet.User.id}`}> <Avatar>{post.Retweet.User?.nickname[0]}</Avatar> </Link> } title={post.Retweet.User?.nickname} description={<PostCardContent postData={post.Retweet.content} />} /> </Card> ) : ( <> <div style={{ float: 'right' }}> {dayjs(post.createdAt).format('YYYY.MM.DD')} </div> <Card.Meta avatar={ <Link href={`/user/${post.User.id}`}> <Avatar>{post.User?.nickname[0]}</Avatar> </Link> } title={post.User?.nickname} description={<PostCardContent postData={post.content} />} /> </> )} </Card> {commentFormOpend && ( <div> {/* 게시글의 아이디 위해서 post 넘겨줌 */} <CommentForm post={post} /> <List header={`${post.Comments.length}개의 댓글`} itemLayout="horizontal" dataSource={post.Comments} renderItem={(item) => ( <List.Item key={item.id}> <List.Item.Meta title={item.User.nickname} avatar={ <Link href={`/user/${item.User.id}`}> <Avatar>{item.User.nickname[0]}</Avatar> </Link> } description={item.content} /> </List.Item> )} /> </div> )} </div> ); }; PostCard.propTypes = { post: PropTypes.shape({ id: PropTypes.number, User: PropTypes.object, content: PropTypes.string, createdAt: PropTypes.string, Comments: PropTypes.arrayOf(PropTypes.object), Images: PropTypes.arrayOf(PropTypes.object), Likers: PropTypes.arrayOf(PropTypes.object), RetweetId: PropTypes.number, Retweet: PropTypes.objectOf(PropTypes.any), }).isRequired, }; export default PostCard; 여유되실때 한번 봐주시면 감사하겠습니다
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
카카오 공유했을 때 이전에 작성했던 글이 나오는 버그
안녕하세요 선생님보너스 강의 전까지 보고 카카오 공유하기 까지 테스트하고 있는데버그를 발견한것 같아서 어떻게 해결할지 여쭤보려 올립니다.위처럼 post/5의 게시글을 작성하고카카오톡에 공유를 하면이전에 썼던 (로컬에서 썼었던) 내용이 보여집니다.혹시 기존 데이터베이스를 리셋하거나 추가적인 작업이 필요한건지 궁금합니다.
-
미해결따라하며 배우는 리액트 A-Z[19버전 반영]
검색어 입력 후 초기화하는 방법 궁금합니다!
안녕하세요. 강의 수강 중에 추가적으로 구현하고 싶은 기능이 있는데 어떻게 해야할지 모르겠어서.. 질문 남깁니다. 검색창에 검색어를 입력하면 SearchPage에 관련 영화 포스터들이 나오고 그 중에 하나를 클릭해서 영화 상세 페이지(DetailPage)로 이동했을 때 검색창을 초기화하고 싶은데 어떻게 해야 하는지 궁금합니다.
-
해결됨[리뉴얼] React로 NodeBird SNS 만들기
프론트서버 배포 후 EADDRINUSE에러 발생
안녕하세요 제로초님덕분에 front배포 잘 하게 되었습니다.그후 접속해서 테스트했는데, 회원가입할 때 connect_refused가 발생해 로그를 찾아보았습니다.EADDRINUSE를 발견하고 원인을 찾으려고 뒤져봤는데 해결되지 않아 여쭤봅니다. ㅠfront = 13.125.119.94 back = 13.125.252.5 아래는 설정한 내용/front/package.json"scripts": { "dev": "next dev", "build": "cross-env ANALYZE=true NODE_ENV=production next build", "start": "cross-env NODE_ENV=production next start -p 80", }, /back/packge.json"scripts": { "dev": "nodemon app", "start": "cross-env NODE_ENV=production pm2 start app.js" }, /back/app.js// node에서는 import / export 안쓰고 require / module.exports 사용 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 morgan = require('morgan'); const path = require('path'); const hpp = require('hpp'); const helmet = require('helmet'); const postRouter = require('./routes/post'); const postsRouter = require('./routes/posts'); const userRouter = require('./routes/user'); const hashtahRouter = require('./routes/hashtag'); const db = require('./models'); // sequelize에서 model 모두 등록 // express에서 그 sequelize를 등록해야 한다. const passportConfig = require('./passport'); dotenv.config(); const app = express(); db.sequelize .sync() .then(() => { console.log('db연결 성공!'); }) .catch(console.error); passportConfig(); // 운영용 빌드 if (process.env.NOD_ENV === 'production') { app.use(morgan('combined')); // 로그볼 수 있게 해주는 것 // 보안에 도움되는 패키지들 app.use(hpp()); app.use(helmet()); } else { app.use(morgan('dev')); // 로그볼 수 있게 해주는 것 } app.use( cors({ origin: ['http://localhost:3000', 'nodebird.com', 'http://13.125.119.94'], credentials: true, }) ); app.use('/', express.static(path.join(__dirname, 'uploads'))); 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()); app.use('/post', postRouter); app.use('/posts', postsRouter); app.use('/user', userRouter); app.use('/hashtag', hashtahRouter); app.listen(80, () => { console.log('서버 실행 중'); }); 프론트 실행화면백엔드 실행 화면 아래는 에러 내용입니다./front 에러AxiosError: connect ECONNREFUSED 13.125.252.5:443 0|npm | at AxiosError.from (file:///home/ubuntu/react-nodebird/prepare/front/node_modules/axios/lib/core/AxiosError.js:89:14) 0|npm | at RedirectableRequest.handleRequestError (file:///home/ubuntu/react-nodebird/prepare/front/node_modules/axios/lib/adapters/http.js:610:25) 0|npm | at RedirectableRequest.emit (node:events:517:28) 0|npm | at eventHandlers.<computed> (/home/ubuntu/react-nodebird/prepare/front/node_modules/follow-redirects/index.js:38:24) 0|npm | at ClientRequest.emit (node:events:517:28) 0|npm | at TLSSocket.socketErrorListener (node:_http_client:501:9) 0|npm | at TLSSocket.emit (node:events:517:28) 0|npm | at emitErrorNT (node:internal/streams/destroy:151:8) 0|npm | at emitErrorCloseNT (node:internal/streams/destroy:116:3) 0|npm | at process.processTicksAndRejections (node:internal/process/task_queues:82:21) 0|npm | at Axios.request (file:///home/ubuntu/react-nodebird/prepare/front/node_modules/axios/lib/core/Axios.js:45:41) 0|npm | at process.processTicksAndRejections (node:internal/process/task_queues:95:5) 0|npm | at async y (/home/ubuntu/react-nodebird/prepare/front/.next/server/chunks/414.js:1:1838) { 0|npm | port: 443, 0|npm | address: '13.125.252.5', 0|npm | syscall: 'connect', 0|npm | code: 'ECONNREFUSED', 0|npm | errno: -111, 0|npm | config: { 0|npm | transitional: { 0|npm | silentJSONParsing: true, 0|npm | forcedJSONParsing: true, 0|npm | clarifyTimeoutError: false 0|npm | }, cause: Error: connect ECONNREFUSED 13.125.252.5:443 0|npm | at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1555:16) { 0|npm | errno: -111, 0|npm | code: 'ECONNREFUSED', 0|npm | syscall: 'connect', 0|npm | address: '13.125.252.5', 0|npm | port: 443 0|npm | } back 에러 | Warning: connect.session() MemoryStore is not 0|app | designed for a production environment, as it will leak 0|app | memory, and will not scale past a single process. 0|app | Error: listen EADDRINUSE: address already in use / 0|app | at Server.setupListenHandle [as _listen2] (node:net:1800:21) 0|app | at listenInCluster (node:net:1865:12) 0|app | at Server.listen (node:net:1964:5) 0|app | at Function.listen (/home/ubuntu/react-nodebird/prepare/back/node_modules/express/lib/application.js:635:24) 0|app | at Object.<anonymous> (/home/ubuntu/react-nodebird/prepare/back/app.js:75:5) 0|app | at Module._compile (node:internal/modules/cjs/loader:1364:14) 0|app | at Module._extensions..js (node:internal/modules/cjs/loader:1422:10) 0|app | at Module.load (node:internal/modules/cjs/loader:1203:32) 0|app | at Module._load (node:internal/modules/cjs/loader:1019:12) 0|app | at Object.<anonymous> (/home/ubuntu/react-nodebird/prepare/back/node_modules/pm2/lib/ProcessContainerFork.js:33:23) { 0|app | code: 'EADDRINUSE', 0|app | errno: -98, 0|app | syscall: 'listen', 0|app | address: '/', 0|app | port: -1 0|app | } front monit back monit 비슷한 질문들이 올라와 있어서 (sudo) npx pm2 kill 해보거나 다른 검색들을 해봤는데 원인을 모르겠더라구요어떤 부분을 수정해야할지 어떤부분을 확인해봐야할지 봐주시면 정말 감사하겠습니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
npm run build 에러
안녕하세요 제로초님프론트 서버를 npm run build 하니까아래와 같은 에러가 나오는데검색해서 찾아봐도 잘 모르겠더라구요.혹시 어느 부분을 확인해보고 어떤 부분을 수정해야할지 조언해주실 수 있을까요?빌드하는것만 몇일째라 ㅠ답답합니다. Collecting page data ./home/ubuntu/react-nodebird/prepare/front/node_modules/rc-util/es/omit.js:1 import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; ^^^^^^ SyntaxError: Cannot use import statement outside a module at internalCompileFunction (node:internal/vm:76:18) at wrapSafe (node:internal/modules/cjs/loader:1283:20) at Module._compile (node:internal/modules/cjs/loader:1328:27) at Module._extensions..js (node:internal/modules/cjs/loader:1422:10) at Module.load (node:internal/modules/cjs/loader:1203:32) at Module._load (node:internal/modules/cjs/loader:1019:12) at Module.require (node:internal/modules/cjs/loader:1231:19) at mod.require (/home/ubuntu/react-nodebird/prepare/front/node_modules/next/dist/server/require-hook.js:65:28) at require (node:internal/modules/helpers:177:18) at 5514 (/home/ubuntu/react-nodebird/prepare/front/.next/server/pages/signup.js:7:10601) /home/ubuntu/react-nodebird/prepare/front/node_modules/rc-util/es/omit.js:1 import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; ^^^^^^ SyntaxError: Cannot use import statement outside a module at internalCompileFunction (node:internal/vm:76:18) at wrapSafe (node:internal/modules/cjs/loader:1283:20) at Module._compile (node:internal/modules/cjs/loader:1328:27) at Module._extensions..js (node:internal/modules/cjs/loader:1422:10) at Module.load (node:internal/modules/cjs/loader:1203:32) at Module._load (node:internal/modules/cjs/loader:1019:12) at Module.require (node:internal/modules/cjs/loader:1231:19) at mod.require (/home/ubuntu/react-nodebird/prepare/front/node_modules/next/dist/server/require-hook.js:65:28) at require (node:internal/modules/helpers:177:18) at 5514 (/home/ubuntu/react-nodebird/prepare/front/.next/server/pages/signup.js:7:10601) > Build error occurred Error: Failed to collect page data for /signup at /home/ubuntu/react-nodebird/prepare/front/node_modules/next/dist/build/utils.js:1268:15 at process.processTicksAndRejections (node:internal/process/task_queues:95:5) { type: 'Error' } /pages.index.jsimport axios from 'axios'; import { useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; import AppLayout from '../components/AppLayout'; import PostCard from '../components/PostCard'; import PostForm from '../components/PostForm'; import { loadPosts, loadPostsError } from '../reducers/post'; import { loadMyInfo } from '../reducers/user'; import wrapper from '../store/configurStore'; // 프론트, 브라우저 같이 실행 const Home = () => { const { me } = useSelector((state) => state.user); const { mainPosts, hasMorePosts, loadPostsLoading, retweetError } = useSelector((state) => state.post); const dispatch = useDispatch(); useEffect(() => { if (retweetError) { alert(retweetError); } }, [retweetError]); useEffect(() => { const onScroll = () => { if ( window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300 ) { if (hasMorePosts && !loadPostsLoading) { const lastId = mainPosts[mainPosts.length - 1]?.id; dispatch(loadPosts({ lastId, limit: 10 })); } } }; window.addEventListener('scroll', onScroll); return () => { window.removeEventListener('scroll', onScroll); }; }, [hasMorePosts, loadPostsLoading, mainPosts.length]); return ( <AppLayout> {me && <PostForm />} {mainPosts && mainPosts[0] ? mainPosts.map((post) => <PostCard key={post.id} post={post} />) : null} </AppLayout> ); }; export const getServerSideProps = wrapper.getServerSideProps( (store) => async ({ req }) => { console.log('getServerSideProps start--------------------------'); console.log(req.headers); const cookie = req ? req.headers.cookie : ''; axios.defaults.headers.Cookie = ''; // 쿠키가 브라우저에 있는경우만 넣어서 실행 // (주의, 아래 조건이 없다면 다른 사람으로 로그인 될 수도 있음) if (req && cookie) { axios.defaults.headers.Cookie = cookie; } await store.dispatch(loadPosts()); await store.dispatch(loadMyInfo()); }, ); export default Home;
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
front 서버 npm run build 중에 발생한 에러들
안녕하세요 제로초님front 서버를 빌드하던중에 빌드가 된줄알고 pm2 monit으로 확인해보니 Could not find a production build in the '.next' directory 이런 에러가 떠있었습니다. 확인해봤더니 아래와 같은 에러 들이 엄청 나오더라구요.warning도 아니고 다 error들이라 검색해보고 .eslintrc를 고쳐봤는데도 잘 안되서 여쭤봅니다 ㅠ 다른 분들은 이런 에러 없이 잘 되는거같은데 전 왜이런지 도와주시면 감사하겠습니다 ㅠ ㅠ npm run build 했을때 나타나는 에러중 일부/components/LoginForm.js 11:1 Error: Unexpected tab character. no-tabs 14:1 Error: Unexpected tab character. no-tabs 17:19 Error: Function component is not a function declaration react/function-component-definition 18:1 Error: Unexpected tab character. no-tabs 18:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 19:1 Error: Unexpected tab character. no-tabs 19:1 Error: Expected indentation of 4 spaces but found 2 tabs. indent 20:1 Error: Unexpected tab character. no-tabs 20:1 Error: Expected indentation of 4 spaces but found 2 tabs. indent 21:1 Error: Unexpected tab character. no-tabs 21:1 Error: Expected indentation of 4 spaces but found 2 tabs. indent 22:1 Error: Unexpected tab character. no-tabs 22:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 23:1 Error: Unexpected tab character. no-tabs 23:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 25:1 Error: Unexpected tab character. no-tabs 25:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 26:1 Error: Unexpected tab character. no-tabs 26:1 Error: Expected indentation of 4 spaces but found 2 tabs. indent 27:1 Error: Unexpected tab character. no-tabs 27:1 Error: Expected indentation of 6 spaces but found 3 tabs. indent 27:4 Warning: Unexpected alert. no-alert 28:1 Error: Unexpected tab character. no-tabs 28:1 Error: Expected indentation of 4 spaces but found 2 tabs. indent 29:1 Error: Unexpected tab character. no-tabs 29:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 31:1 Error: Unexpected tab character. no-tabs 31:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 32:1 Error: Unexpected tab character. no-tabs 32:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 33:1 Error: Unexpected tab character. no-tabs 33:1 Error: Expected indentation of 4 spaces but found 2 tabs. indent 34:1 Error: Unexpected tab character. no-tabs 34:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 36:1 Error: Unexpected tab character. no-tabs 36:1 Error: Expected indentation of 2 spaces but found 1 tab. indent 37:1 Error: Unexpected tab character. no-tabs 37:3 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 38:1 Error: Unexpected tab character. no-tabs 38:4 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 39:1 Error: Unexpected tab character. no-tabs 39:5 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 39:20 Error: Unexpected usage of singlequote. jsx-quotes 40:1 Error: Unexpected tab character. no-tabs 40:5 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 41:1 Error: Unexpected tab character. no-tabs 41:5 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 42:1 Error: Unexpected tab character. no-tabs 42:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 42:11 Error: Unexpected usage of singlequote. jsx-quotes 43:1 Error: Unexpected tab character. no-tabs 43:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 44:1 Error: Unexpected tab character. no-tabs 44:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 45:1 Error: Unexpected tab character. no-tabs 45:1 Error: Expected indentation of 7 spaces but found 6 tabs. indent 46:1 Error: Unexpected tab character. no-tabs 46:1 Error: Expected indentation of 7 spaces but found 6 tabs. indent 47:1 Error: Unexpected tab character. no-tabs 48:1 Error: Unexpected tab character. no-tabs 48:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 49:1 Error: Unexpected tab character. no-tabs 49:7 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 50:1 Error: Unexpected tab character. no-tabs 50:8 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 50:29 Error: Unexpected usage of singlequote. jsx-quotes 50:42 Error: Unexpected usage of singlequote. jsx-quotes 50:62 Error: Unexpected usage of singlequote. jsx-quotes 51:1 Error: Unexpected tab character. no-tabs 51:8 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 52:1 Error: Unexpected tab character. no-tabs 53:1 Error: Unexpected tab character. no-tabs 54:1 Error: Unexpected tab character. no-tabs 55:1 Error: Unexpected tab character. no-tabs 56:1 Error: Unexpected tab character. no-tabs 56:4 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 57:1 Error: Unexpected tab character. no-tabs 57:5 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 57:20 Error: Unexpected usage of singlequote. jsx-quotes 58:1 Error: Unexpected tab character. no-tabs 58:5 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 59:1 Error: Unexpected tab character. no-tabs 59:5 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent 60:1 Error: Unexpected tab character. no-tabs 60:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 60:11 Error: Unexpected usage of singlequote. jsx-quotes 61:1 Error: Unexpected tab character. no-tabs 61:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 62:1 Error: Unexpected tab character. no-tabs 62:6 Error: Expected indentation of 2 space characters but found 0. react/jsx-indent-props 63:1 Error: Unexpected tab character. no-tabs 63:1 Error: Expected indentation of 7 spaces but found 6 tabs. indent 64:1 Error: Unexpected tab character. no-tabs 64:1 Error: Expected indentation of 7 spaces but found 6 tabs. indent 65:1 Error: Unexpected tab character. no-tab .eslintrc, next.config.js 는 제로초님의 깃헙과 동일하게 했습니다..eslintrc{ "parser": "@babel/eslint-parser", "parserOptions": { "ecmaVersion": 2020, "sourceType": "module", "ecmaFeatures": { "jsx": true }, "babelOptions": { "presets": ["next/babel"] }, "requireConfigFile": false }, "env": { "browser": true, "node": true, "es6": true }, "extends": ["airbnb"], "plugins": ["import", "react-hooks", "jsx-a11y"], "rules": { "jsx-a11y/label-has-associated-control": "off", "jsx-a11y/anchor-is-valid": "off", "no-console": "off", "no-underscore-dangle": "off", "react/forbid-prop-types": "off", "react/jsx-filename-extension": "off", "react/jsx-one-expression-per-line": "off", "react/jsx-props-no-spreading": "off", "object-curly-newline": "off", "linebreak-style": "off", "no-param-reassign": "off", "max-len": "off", "react/react-in-jsx-scope": "off" } } next.config.jsconst withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true", }); module.exports = withBundleAnalyzer({ images: { domains: ["react-nodebird.s3.ap-northeast-2.amazonaws.com", "react-nodebird-s3.s3.amazonaws.com"], }, compress: true, compiler: { styledComponents: { ssr: true, displayName: true, }, }, webpack(config, { webpack }) { const prod = process.env.NODE_ENV === "production"; return { ...config, mode: prod ? "production" : "development", devtool: prod ? "hidden-source-map" : "inline-source-map", plugins: [...config.plugins], }; }, }); /package.json{ "name": "react-nodebird", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "next dev", "build": "cross-env ANALYZE=true NODE_ENV=production next build", "start": "cross-env NODE_ENV=production next start -p 80" }, "author": "", "license": "MIT", "dependencies": { "@ant-design/icons": "^5.3.6", "@next/bundle-analyzer": "^14.2.3", "@reduxjs/toolkit": "^2.2.3", "antd": "^5.8.3", "axios": "^1.6.8", "babel-plugin-styled-components": "^2.1.4", "cross-env": "^7.0.3", "dayjs": "^1.11.11", "lodash": "^4.17.21", "next": "^14.2.3", "next-redux-wrapper": "^8.1.0", "pm2": "^5.3.1", "prop-types": "^15.8.1", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.51.3", "react-redux": "^9.1.1", "react-slick": "^0.30.2", "redux": "^5.0.1", "redux-saga": "^1.3.0", "shortid": "^2.2.16", "styled-components": "^6.1.8", "swr": "^2.2.5" }, "devDependencies": { "@babel/eslint-parser": "^7.24.5", "@faker-js/faker": "^8.4.1", "babel-eslint": "^10.1.0", "eslint": "^8.57.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.2" } } 깃헙 : https://github.com/dydcodydco/react-nodebird
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
서버 실행하고 브라우저로 들어갔을때 404에러
안녕하세요 제로초님서버 실행하고 브라우저로 들어갔을때 404에러가 나오는건정상적인 실행결과가 아닌건가요?제대로 작동하고 있는것 같은데... 저랑 같은 상태로 보이시는 분의 질문이 있는걸 보고 혹시나해서 여쭤봅니다.https://www.inflearn.com/questions/685249/%EC%84%9C%EB%B2%84-%EC%8B%A4%ED%96%89%EC%8B%9C-404%EC%97%90%EB%9F%AC-%EA%B4%80%EB%A0%A8%ED%95%B4%EC%84%9C-%EC%A7%88%EB%AC%B8%EB%93%9C%EB%A6%AC%EA%B2%A0%EC%8A%B5%EB%8B%88%EB%8B%A4
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
css 서버사이드 랜더링이 적용되지 않아서 문의 드립니다.
https://www.inflearn.com/course/lecture?courseSlug=%EB%85%B8%EB%93%9C%EB%B2%84%EB%93%9C-%EB%A6%AC%EC%95%A1%ED%8A%B8-%EB%A6%AC%EB%89%B4%EC%96%BC&unitId=49018&category=questionDetail&tab=community&q=1075492안녕하세요 제로초님!위의 질문 답변을 보고 css 서버사이드 랜더링을 하기위해서 이것저것 해보았는데 적용이 안되서 문의 드립니다..babelrc 작성next.config.js에서도 옵션으로 가능하다고해서 수정_document.js 수정빌드 하고 npm start하고 테스트위 링크의 답변 참고해서 @ant-design/cssinjs 적용해봄 그럼에도 적용안되더라구요 ㅠpages/_docuemnts.js (이 전에는 제로초님깃헙의 것을 썼었습니다. 안돼서 @ant-design/cssinjs 적용한 버전입니다.import React from "react"; import Document, { Html, Head, Main, NextScript } from "next/document"; import { createCache, extractStyle, StyleProvider } from "@ant-design/cssinjs"; import { ServerStyleSheet } from "styled-components"; export default class MyDocument extends Document { static async getInitialProps(ctx) { const cache = createCache(); const sheet = new ServerStyleSheet(); const originalRenderPage = ctx.renderPage; try { ctx.renderPage = () => originalRenderPage({ enhanceApp: (App) => (props) => ( <StyleProvider cache={cache}> <App {...props} /> </StyleProvider> ), }); const initialProps = await Document.getInitialProps(ctx); const style = extractStyle(cache, true); return { ...initialProps, styles: ( <> {initialProps.styles} <style dangerouslySetInnerHTML={{ __html: style }} /> </> ), }; } catch (error) { console.error(error); } finally { sheet.seal(); } } render() { return ( <Html> <Head /> <body> <Main /> <NextScript /> </body> </Html> ); } } next.config.jsconst withBundleAnalyzer = require("@next/bundle-analyzer")({ enabled: process.env.ANALYZE === "true", }); module.exports = withBundleAnalyzer({ images: { domains: ["react-nodebird.s3.ap-northeast-2.amazonaws.com", "react-nodebird-s3.s3.amazonaws.com"], }, compress: true, compiler: { styledComponents: { ssr: true, displayName: true, }, }, webpack(config, { webpack }) { const prod = process.env.NODE_ENV === "production"; return { ...config, mode: prod ? "production" : "development", devtool: prod ? "hidden-source-map" : "inline-source-map", plugins: [...config.plugins], }; }, }); .eslintrc{ "parser": "@babel/eslint-parser", "parserOptions": { "ecmaVersion": "latest", "sourceType": "module", "ecmaFeatures": { "jsx": true }, "requireConfigFile": false, "babelOptions": { "presets": ["next/babel"] } }, "env": { "browser": true, "node": true, "es6": true }, "extends": [ "airbnb", "next/babel" ], "plugins": ["import", "react-hooks", "jsx-a11y"], "rules": { "react/react-in-jsx-scope": "off", "jsx-a11y/label-has-associated-control": "off", "jsx-a11y/anchor-is-valid": "off", "no-console": "off", "no-underscore-dangle": "off", "react/forbid-prop-types": "off", "react/jsx-filename-extension": "off", "react/jsx-one-expression-per-line": "off", "react/jsx-props-no-spreading": "off", "object-curly-newline": "off", "linebreak-style": "off", "no-param-reassign": "off", "max-len": "off" } } /.babelrc{ "presets": ["next/babel"], "plugins": [ [ "styled-components", { "ssr": true, "displayName": true } ] ] } https://github.com/dydcodydco/react-nodebird혹시나해서 깃헙 주소도 남깁니다.마지막으로 하나 더 궁금한게 있습니다.이 강의를 내껄로 만들고, 다음강의 슬랙까지 강의보고 하면중고신입으로 개발자 이직할 수 있을지도 궁금합니다.좋은 강의 정말 감사합니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
팔로워 3명씩 불러오고 데이터 합쳐주는걸로 바꾸고 서버요청을 무한으로하고있습니다.
안녕하세요 제로초님.강의중에 말씀해주셨건걸 참고해서팔로워, 팔로잉을 3명 호출하고, 이후에 다음3명씩 호출하고 불러온 데이터를 합쳐서 리스트를 만드는식으로 바꿔봤습니다.그런데 이슈가 한번 불러오기, 더보기 다 작동하는데 서버 요청을 무한으로 하고 있습니다.어떤 부분을 수정해야할지 봐주실 수 있을까요?limit은 3으로 고정, page를 조절해서 다음 3명씩/pages/profile.jsimport Head from "next/head"; import { useDispatch, useSelector } from "react-redux"; import { useCallback, useEffect, useState } from "react"; import { useRouter } from "next/router"; import axios from "axios"; import useSWR from "swr"; import { loadFollowersRequestAction, loadFollowingsRequestAction, loadMyInfo } from "../reducers/user"; import AppLayout from "../components/AppLayout"; import NicknameEditForm from "../components/NicknameEditForm"; import FollowList from "../components/FollowList"; import wrapper from "../store/configurStore"; const fetcher = (url) => axios.get(url, { widthCredentials: true }).then((result) => { console.log("fetcher----------------------"); return result.data; }); const Profile = () => { const router = useRouter(); const dispatch = useDispatch(); const { me } = useSelector((state) => state.user); const [followersLimit, setFollowersLimit] = useState(1); const [followingsimit, setFollowingsLimit] = useState(1); const [followers, setFollowers] = useState([]); const [followings, setFollowings] = useState([]); const { data: followersData, error: followerError, isLoading: followerLoading, } = useSWR(`http://localhost:3065/user/followers?page=${followersLimit}`, fetcher, { onSuccess: (data) => { setFollowers((prev) => [...prev, ...data]); }, }); const { data: followingsData, error: followingError, isLoading: followingLoading, } = useSWR(`http://localhost:3065/user/followings?page=${followingsimit}`, fetcher, { onSuccess: (data) => { setFollowings((prev) => [...prev, ...data]); }, }); useEffect(() => { if (!(me && me.id)) { router.push("/"); } }, [me && me.id]); const loadMoreFollowings = useCallback(() => { setFollowingsLimit((prev) => prev + 1); }, []); const loadMoreFolloweers = useCallback(() => { setFollowersLimit((prev) => prev + 1); }, []); if (!me) { return <div>내정보 로딩중...</div>; } if (followerError || followingError) { console.error(followerError || followingError); return <div>팔로잉/팔로워 로딩 중 에러 발생...</div>; } return ( <> <Head> <title>내 프로필 | NodeBird</title> </Head> <AppLayout> <NicknameEditForm /> <FollowList header='팔로워' data={followers} onClickMore={loadMoreFolloweers} loading={followerLoading} /> <FollowList header='팔로잉' data={followings} onClickMore={loadMoreFollowings} loading={followingLoading} /> </AppLayout> </> ); }; export const getServerSideProps = wrapper.getServerSideProps((store) => async ({ req }) => { console.log(req.headers); const cookie = req ? req.headers.cookie : ""; axios.defaults.headers.Cookie = ""; if (req && cookie) { axios.defaults.headers.Cookie = cookie; } await store.dispatch(loadMyInfo()); }); export default Profile; /routes/userl.js// GET /user/followers 팔로워즈 불러오기 router.get("/followers", isLoggedIn, async (req, res, next) => { try { // 나를 먼저 찾고 const user = await User.findOne({ where: { id: req.user.id }, }); // 내 팔로워즈 get 하기 const limit = parseInt(req.query.limit, 10) || 3; // 기본값 3 const page = parseInt(req.query.page, 10) || 1; // 기본값 1 const offset = (page - 1) * limit; const followers = await user.getFollowers({ limit, offset }); res.status(200).json(followers); } catch (error) { console.error(error); next(error); } }); // GET /user/followings 팔로잉즈 불러오기 // 미들웨어... (req, res, next) 이 콜백함수도 미들웨어 router.get("/followings", isLoggedIn, async (req, res, next) => { try { const user = await User.findOne({ where: { id: req.user.id }, }); const limit = parseInt(req.query.limit, 10) || 3; // 기본값 3 const page = parseInt(req.query.page, 10) || 1; // 기본값 1 const offset = (page - 1) * limit; const followings = await user.getFollowings({ limit, offset }); res.status(200).json(followings); } catch (error) { console.error(error); next(error); } });
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
해시태그 검색에서 throttle에 관해 질문있습니다.
해시태그 검색에서 throttle에 관해 질문있습니다.해시태그 검색을 하게 되면 throttle때문에 5초 이후에 검색이 되고 있습니다.스크롤할 때에는 유용하지만 하나를 클릭하고, 5초 이내에 클릭하게되면 url은 바뀌지만 게시글은 바뀌지 않고 ux에 좋지않아보입니다. const loadHashtagPostsThrottle = async (payload) => { const queryStr = setQuerystring(payload); const url = `/hashtag/${encodeURIComponent(payload.tag)}${queryStr ? "?" + queryStr : ""}`; const response = await axios.get(url); return response; }; export const loadHashtagPosts = createAsyncThunk("post/loadHashtagPosts", _.throttle(loadHashtagPostsThrottle, 5000)); 특저 유저의 게시글을 검색할때도 비슷한 현상이 나올거같은데 이럴땐 어떻게 하면 ux를 좋게 할 수 있을지 궁금합니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
full reload 될때는 서버 데이터를 호출하는데 그 이후로 새로고침할대는 호출하지 않아서 답답합니다
안녕하세요 제로초님full reload 될때는 서버 데이터를 호출하는데 그 이후로 새로고침할대는 호출하지 않아서 답답합니다.구글링하고 제로초님 로직을 따라 만들어보다가posts게시물이 내려오도록 수정을 했는데,이상하게 처음엔 서버에 요청하고 데이터를 내려받아서 게시물이 보이는데, 그이후 새로고침하면 서버 호출까지도 안하는것 같습니다.이젠 좀 나오나 싶었는데, full reload될때만 되서 여유되실 때 로직한번 봐주시면 감사하겠습니다 ㅠ / pages/index.jsimport { useDispatch, useSelector } from "react-redux"; import AppLayout from "../components/AppLayout"; import PostForm from "../components/PostForm"; import PostCard from "../components/PostCard"; import { useEffect } from "react"; import { loadPostsRequestAction } from "../reducers/post"; import { loadMyInfoRequestAction } from "../reducers/user"; import wrapper from "../store/configurStore"; import axios from "axios"; import { END } from "redux-saga"; // 프론트, 브라우저 같이 실행 const Home = () => { const { me } = useSelector((state) => state.user); const { mainPosts, hasMorePosts, loadPostsLoading, retweetError } = useSelector((state) => state.post); const dispatch = useDispatch(); useEffect(() => { if (retweetError) { alert(retweetError); } }, [retweetError]); useEffect(() => { const onScroll = () => { if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) { if (hasMorePosts && !loadPostsLoading) { const lastId = mainPosts[mainPosts.length - 1]?.id; dispatch(loadPostsRequestAction({ lastId, limit: 10 })); } } }; window.addEventListener("scroll", onScroll); return () => { window.removeEventListener("scroll", onScroll); }; }, [hasMorePosts, loadPostsLoading, mainPosts]); return ( <AppLayout> {me && <PostForm />} {/* 순서가 바뀌거나 삭제될 수 있는 리스트들에 key값으로 index를 쓰면 안됀다. */} {/* 반복문이 있고 바뀌지 않는 리스트일 경우에만 사용해도 된다. */} {mainPosts.map((post) => ( <PostCard key={post.id} post={post} /> ))} </AppLayout> ); }; export const getServerSideProps = wrapper.getServerSideProps((store) => async ({ req }) => { store.dispatch(loadPostsRequestAction()); store.dispatch(loadMyInfoRequestAction()); store.dispatch(END); await store.sagaTask.toPromise(); // 사가 작업 완료 대기 console.log("state", store.getState()); }); export function reportWebVitals(metric) { console.log(metric); } export default Home; /pages/_app.jsimport PropTypes from "prop-types"; import Head from "next/head"; import { Provider } from "react-redux"; import wrapper from "../store/configurStore"; const NodeBird = ({ Component, ...rest }) => { const { store, props } = wrapper.useWrappedStore(rest); const { pageProps } = props; return ( <Provider store={store}> <Head> <meta charSet='utf-8' /> <meta name='viewport' content='width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0' /> <title>NodeBird</title> </Head> <Component {...pageProps} /> </Provider> ); }; NodeBird.propTypes = { Component: PropTypes.elementType.isRequired, pageProps: PropTypes.any.isRequired, }; export function reportWebVitals(metric) { // console.log("-----------------------------------"); // console.log(metric); } export default NodeBird; store/configureStore.jsimport { createWrapper } from "next-redux-wrapper"; import { configureStore } from "@reduxjs/toolkit"; import reducer from "../reducers"; import user from "../reducers/user"; import post from "../reducers/post"; import createSagaMiddleware from "redux-saga"; import rootSaga from "../sagas"; // redux-thunk를 참조해서 만든 미들웨어 const loggerMiddleware = ({ dispatch, getState }) => (next) => (action) => { return next(action); }; const sagaMiddleware = createSagaMiddleware(); function getServerState() { return typeof document !== "undefined" ? JSON.parse(document.querySelector("#__NEXT_DATA__").textContent)?.props.pageProps.initialState : undefined; } const serverState = getServerState(); const makeStore = () => { // configureStore: store 를 생성 const store = configureStore({ reducer: { user, post, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat([sagaMiddleware, loggerMiddleware]), preloadedState: serverState, // SSR }); store.sagaTask = sagaMiddleware.run(rootSaga); return store; }; const wrapper = createWrapper(makeStore, { debug: process.env.NODE_ENV === "development", }); export default wrapper; /reducers.js/post.js import { HYDRATE } from "next-redux-wrapper"; import { createSlice } from "@reduxjs/toolkit"; import shortId from "shortid"; import produce from "immer"; export const initialState = { mainPosts: [], imagePaths: [], hasMorePosts: true, loadPostsLoading: false, // 게시글들 불러오는 중 loadPostsDone: false, loadPostsError: null, addPostLoading: false, // 게시글 추가 시도중 addPostDone: false, addPostError: null, removePostLoading: false, // 게시글 제거 시도중 removePostDone: false, removePostError: null, addCommentLoading: false, // 댓글 추가 시도중 addCommentDone: false, addCommentError: null, likePostLoading: false, // 좋아요 시도중 likePostDone: false, likePostError: null, unLikePostLoading: false, // 좋아요 취소중 unLikePostDone: false, unLikePostError: null, uploadImagesLoading: false, // 이미지 업로드 시도중 uploadImagesDone: false, uploadImagesError: null, retweetLoading: false, // 리트윗 시도중 retweetDone: false, retweetError: null, }; const postSlice = createSlice({ name: "post", initialState, reducers: {loadPostsRequestAction: (state, action) => { console.log("-------------------요청-------------------"); state.loadPostsLoading = true; state.loadPostsDone = false; state.loadPostsError = null; }, loadPostsSuccessAction: (state, action) => { console.log("-------------------성공-------------------"); state.loadPostsLoading = false; state.loadPostsDone = true; state.mainPosts = [... state.hasMorePosts = action.payload.length === 10; }, loadPostsFailureAction: (state, action) => { console.log("-------------------실패-------------------"); state.loadPostsLoading = false; state.loadPostsError = action.payload; }, }, extraReducers: (builder) => builder .addCase(HYDRATE, (state, action) => { console.log("HYDRATE", action); return { ...state, ...action.payload.post, }; }) .addDefaultCase((state) => state), }); export const { loadPostsRequestAction, loadPostsSuccessAction, loadPostsFailureAction, } = postSlice.actions; export default postSlice.reducer;
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
getServerSideProps에서 데이터가 제대로 내려오지 않는듯합니다.
안녕하세요 제로초님https://github.com/ZeroCho/react-nodebird/blob/master/toolkit/front/pages/index.js위 내용을 참고해서코드를 작성해보았습니다.import { useDispatch, useSelector } from "react-redux"; import AppLayout from "../components/AppLayout"; import PostForm from "../components/PostForm"; import PostCard from "../components/PostCard"; import { useEffect } from "react"; import { loadPostsRequestAction } from "../reducers/post"; import { loadMyInfoRequestAction } from "../reducers/user"; import wrapper from "../store/configurStore"; import axios from "axios"; // 프론트, 브라우저 같이 실행 const Home = () => { const { me } = useSelector((state) => state.user); const { mainPosts, hasMorePosts, loadPostsLoading, retweetError } = useSelector((state) => state.post); const dispatch = useDispatch(); useEffect(() => { if (retweetError) { alert(retweetError); } }, [retweetError]); useEffect(() => { const onScroll = () => { if (window.scrollY + document.documentElement.clientHeight > document.documentElement.scrollHeight - 300) { if (hasMorePosts && !loadPostsLoading) { const lastId = mainPosts[mainPosts.length - 1]?.id; dispatch(loadPostsRequestAction({ lastId, limit: 10 })); } } }; window.addEventListener("scroll", onScroll); return () => { window.removeEventListener("scroll", onScroll); }; }, [hasMorePosts, loadPostsLoading, mainPosts]); return ( <AppLayout> {me && <PostForm />} {/* 순서가 바뀌거나 삭제될 수 있는 리스트들에 key값으로 index를 쓰면 안됀다. */} {/* 반복문이 있고 바뀌지 않는 리스트일 경우에만 사용해도 된다. */} {mainPosts.map((post) => ( <PostCard key={post.id} post={post} /> ))} </AppLayout> ); }; export const getServerSideProps = wrapper.getServerSideProps((store) => async ({ req }) => { const cookie = req ? req.headers.cookie : ""; axios.defaults.headers.Cookie = ""; if (req && cookie) { axios.defaults.headers.Cookie = cookie; } await store.dispatch(loadPostsRequestAction()); await store.dispatch(loadMyInfoRequestAction()); console.log("state", store.getState()); }); export default Home; 그런데 await에서 await' has no effect on the type of this expression.ts(80007이런 경고문 때문인지이전 영상에서 말씀해주셨던것처럼 데이터를 success까지 기다리지 않는건지,빈값들만 오고 있습니다.혹시 어디를 살펴보면 좋을지 알 수 있을까요?{ "name": "react-nodebird", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { "dev": "next dev", "build": "next build", "start": "next start" }, "author": "", "license": "MIT", "dependencies": { "@ant-design/icons": "^5.3.6", "@reduxjs/toolkit": "^2.2.3", "antd": "^5.8.3", "axios": "^1.6.8", "next": "^14.2.3", "next-redux-wrapper": "^8.1.0", "react": "^18.3.1", "react-dom": "^18.3.1", "react-hook-form": "^7.51.3", "react-redux": "^9.1.1", "react-slick": "^0.30.2", "redux": "^5.0.1", "shortid": "^2.2.16", "styled-components": "^6.1.8" }, "devDependencies": { "@faker-js/faker": "^8.4.1", "babel-eslint": "^10.1.0", "eslint": "^8.57.0", "eslint-config-airbnb": "^19.0.4", "eslint-plugin-import": "^2.29.1", "eslint-plugin-jsx-a11y": "^6.8.0", "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.2" } } 환경은 위와같습니다.감사합니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
다른 페이지갔다가 오면 게시글 불러와지는 이슈
게시글을 끝까지 스크롤하고,다른 페이지에 다녀오면다른 페이지갔다가 오면 게시글 불러와지는 이슈를 발견했습니다.index.js에서 게시글 불러오는 부분에mainposts의 조건을 붙여서 실행하면될거같은데차후 강의에서 해결해주시는 이슈인지 궁금합니다.아니면 저만 그런건지 여쭤봅니다!감사합니다.
-
미해결[리뉴얼] React로 NodeBird SNS 만들기
도메인과 S3연결 후 AWS 요금 과금문제 문의드립니다.
강의를 보고 따라하다가 오늘 보니 저번 달 사용량에 관련된 요금이 결제되었다고 메일을 받았습니다.. Amazon Virtual Private Cloud 에서 좀 많이 나왔고,,Amazon Route 53에도 요금이 나왔네요..총 만원정도 과금이 되었는데 어떤건지 몰라서 어디부분을 삭제해야 비용이 발생하지 않는걸까요?강의를 잘 보고 따라했는데.. 당황스럽습니다...
주간 인기글
순위 정보를
불러오고 있어요