묻고 답해요
158만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Next.js 시작하기
컴포넌트가 렌더링되어 HTML이 생성되는 곳 (getServerSideProps VS useEffect)
안녕하세요 :) 섹션 9 부분을 다 듣고 나서 명확히 이해가 가지 않는 부분이 있어 질문드립니다. getServerSideProps를 이용하여 페이지를 로딩할 때는 "컴포넌트가 렌더링되어 HTML이 생성되는 곳"이 프론트 서버(Next.js 서버)이고,useEffect를 이용하여 페이지를 로딩할 때는 "컴포넌트가 렌더링되어 HTML이 생성되는 곳"이 클라이언트(브라우저)라고 이해하는게 맞을까요?
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
클라이언트 컴포넌트로의 전환
강사님 안녕하세요.학습을 거의 끝낸 상태라 거의 마지막 질문이 될 것 같기도 한데요^^클라이언트 컴포넌트는 서버 컴포넌트를 Import 할 수 없기 떄문에 Next 는 서버 컴포넌트를 클라이언트 컴포넌트로 동작시킨다고 배웠습니다.그런데 만약 이러한 서버 컴포넌트에 async 방식의 api 코드가 포함되어 있는 경우에는 이런 코드가 클라이언트 방식으로 동작하면 문제가 발생할 것 같은데요.결국, 이런 상황에서는 서버 컴포넌트를 그대로 두어서는 안되고 강의에서 설명하신 합성 방식으로 변경을 하거나 아니면 해당 서버 컴포넌트의 API 로직을 react-query 나 useEffect 훅을 이용해서 실행될 수 있는 클라이언트 컴포넌트로 리팩토링을 해야만 되는거 같은데 제가 올바로 이해한 게 맞을까요?
-
미해결한 입 크기로 잘라먹는 Next.js(v15)
리퀘스트 메모이제이션이 동작을 안하는것 같습니다.
/app/(with-searchbar)/page.tsx/app/layout.tsx터미널 첨부한 사진과 같이 수업내용에 따라 코드를 작성하였고, 선생님의 화면과는 다르게 저렇게 같은 GET 호출이 두번이 나오네요... 옵션을 따로 추가하는것으로 바뀌었을까요??npm run dev를 껐다가 다시 실행해도 마찬가지의 결과가 나옵니다!
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
12.15강의 10분 Edit페이지에서 삭제하기(onDelete) 기능 질문
TypeError: onDelte is not a functiononDelete를 함수로 인식하지 못하고 있다고 합니다. 오탈자가 문제인건지 잘 모르겠습니다....import "./App.css"; import { useReducer, useRef, createContext } from "react"; import { Route, Routes } from "react-router-dom"; import Home from "./pages/Home"; import Diary from "./pages/Diary"; import New from "./pages/New"; import Notfound from "./pages/Notfound"; import Edit from "./pages/Edit"; // 1. "/" : 모든 일기를 조회하는 Home 페이지 // 2. "/new" : 새로운 일기를 작성하는 New 페이지 // 3. "/diary" : 일기를 상세히 조회하는 Diary 페이지 const mockData = [ { id: 1, createdDate: new Date("2024-11-04").getTime(), emotionId: 1, content: "1번 일기 내용", }, { id: 2, createdDate: new Date("2024-11-03").getTime(), emotionId: 2, content: "2번 일기 내용", }, { id: 3, createdDate: new Date("2024-10-07").getTime(), emotionId: 3, content: "3번 일기 내용", }, ]; function reducer(state, action) { switch (action.type) { case "CREATE": return [action.data, ...state]; case "UPDATE": return state.map((item) => { String(item.id) === String(action.id) ? action.data : item; }); case "DELETE": return state.filter((item) => String(item.id) !== String(action.id)); default: return state; } } export const DiaryStateContext = createContext(); export const DiaryDispatchContext = createContext(); function App() { const [data, dispatch] = useReducer(reducer, mockData); const idRef = useRef(4); //기본 일기 추가 const onCreate = (createdDate, emotionId, content) => { dispatch({ type: "CREATE", data: { id: idRef.current++, createdDate, emotionId, content, }, }); }; // 기존 일기 수정 const onUpdate = (id, createdDate, emotionId, content) => { dispatch({ type: "UPDATE", data: { id, createdDate, emotionId, content, }, }); }; // 기존 일기 삭제 const onDelete = (id) => { dispatch({ type: "DELETE", id, }); }; return ( <> <DiaryStateContext.Provider value={data}> <DiaryDispatchContext.Provider value={{ onCreate, onUpdate, onDelete }}> <Routes> <Route path="/" element={<Home />} /> <Route path="/new" element={<New />} /> <Route path="/diary/:id" element={<Diary />} /> <Route path="/edit/:id" element={<Edit />} /> <Route path="*" element={<Notfound />} /> </Routes> </DiaryDispatchContext.Provider> </DiaryStateContext.Provider> </> ); } export default App; import Header from "../components/Header"; import Button from "../components/Button"; import Editor from "../components/Editor"; import { useParams, useNavigate } from "react-router-dom"; import { useContext } from "react"; import { DiaryDispatchContext } from "../App"; const Edit = () => { const params = useParams(); const nav = useNavigate(); const { onDelte } = useContext(DiaryDispatchContext); const onClickDelete = () => { if (window.confirm("일기를 정말 삭제할까요? 다시 복구되지 않아요!")) { //일기 삭제 로직 //console.log(params.id); onDelte(params.id); nav("/", { replace: true }); } }; return ( <div> <Header title={"일기 수정하기"} leftChild={<Button onClick={() => nav(-1)} text={"< 뒤로 가기"} />} rightChild={ <Button onClick={onClickDelete} text={"삭제하기"} type={"NEGATIVE"} /> } /> <Editor /> </div> ); }; export default Edit;
-
미해결코드로 배우는 React 19 with 스프링부트 API서버
섹션 3 부트 프로젝트 생성 및 확인 / 엔티티 클래스 만들기 강의가 재생되지 않습니다.
섹션 3 부트 프로젝트 생성 및 확인 / 엔티티 클래스 만들기 강의가 재생되지 않습니다.크롬으로 보던 중 무한로딩이 떠서 시크릿모드 및 다른 브라우저로 시도해봤지만 여전히 재생되지 않습니다.다른 영상은 잘 재생되는데, 섹션 3 부트 프로젝트 생성 및 확인 / 엔티티 클래스 만들기 강의만 재생되지 않네요. 확인 한 번 부탁드립니다!
-
미해결Next + React Query로 SNS 서비스 만들기
searchParams 질문있습니다.
const onClickHot = () => { setCurrent('hot'); router.replace(`/search?q=${searchParams.get('q')}`) } 이 코드가 있으면 q=null일때 주소가 http://localhost:3000/search?q=null이렇게 이동되는데 제로초님은 아무런 검색어가 없는데 어떻게 null로 안나오죠?null체크를해서 주소를 2개 분기해도 될거같긴한데 제로초님은 q가 null일땐 주소창의 쿼리가 안생기더라고요 . 뭐가다른건지 모르겠네요ㅠ
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
백엔드서버에서 요청은 정상적이나 데이터를 못가져오는 현상
안녕하세요.책 데이터를 불러오지 못해서 문의 드립니다.스웨거에서도 아무 데이터를 못 불러오는데 혹시 어떤 문제일까요? npx prisma db push 도 잘 완료 하였고백엔드 서버도 start 해 놓은 상태입니다.
-
해결됨[React / VanillaJS] UI 요소 직접 만들기 Part 1
무한스크롤 리액트버전 | 16분 31초
16분 31초에 const useInfiniteFetcher =() => {} 여기 부분을 보게 되면pageData는 async에서 받아와서 promise가 되었는데강사님은 따로 .then을 안하셨는데 어떻게 가능한가요??
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
개발자 모드 질문입니다
디버그 모드가 되는 것 같은데 이유를 모르겠습니다. 뭐라 검색해봐야할까요? 아님 제가 코드 오타가 난걸까요?이전에 components탭에서 볼 수 있던 값들이 안 보여서 질문드립니다.
-
해결됨비전공자를 위한 진짜 입문 올인원 개발 부트캠프
그랩선생님, 질문 답변 부탁 드립니다.vscode에서 npm install -g create-react-app 입력 후 에러 입니다.
(* nodejs 설치를 https://nodejs.org/en/download/ 에 들어가서 Prebuilt Installer 메뉴에서v22.11.0(LTS)를 설치하였습니다.)안녕하세요, 수고가 많으십니다.강의 잘 듣고 공부하다 모르는 부분이 있어 에러사항은 아래에 요약하여 적었습니다.일단 react 시작하기 강의를 듣고 있던 중 처음 부분에서 vscode 터미널에서 명령어 npm install -g create-react-app 입력 후 아래 에러가 발생하여어떻게 해야 해결 할 수 있는지 답을 알고 싶어서 글을 쓰게 되었습니다. 1.첫번째로 vscode 실행 후 npm install -g create-react-app 명령어 입력하니 에러 요약: 경로를 확인하라는문제가 발생하였습니다. 첫번쨰 에러 발생 한 후 vscode를 종료하고 다시 시작하니 또 다시 이번엔 새로운 에러가 발생하였습니다. 에러 요약: 자세한 내용은 마이크로소프트 링크 주소 참조하라는 메시지 에러가 발생하였습니다. 현재까지 2가지 에러가 순서대로 나타내고 있는데요, 어떻게 하면 해당 사항을 해결 할 수 있을까요? 상세하고 자세한 답변 부탁드립니다.감사합니다.
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
Next.js vs React.js
강사님, 안녕하세요.강의를 들으면서 살짝 혼란스러운 부분이 있습니다.사실 Next.js 도 바탕은 React 인데요.React 에서 제일 많이 언급되고 중요시되는 부분은 상태(state)관리라고 생각이 되는데Next.js 로 SSR 위주의 페이지를 작성하게 되면 결국 상태관리는 최소화하게 되는 것인데이게 React 의 컨셉과 맞는 것인지 살짝 이해가 되지 않습니다.(강의에서도 state 는 거의 언급이 되지 않고요) 그렇다고 상태관리를 최대한 활용하는 CSR 위주의 개발을 하게 되면 Next.js 의 장점을 거의 얻지 못하게 될 것 같기도 하고요.저는 Next.js 가 제공하는 프레임워크 측면의 혜택을 얻고자 Next.js 로 어플리케이션 구축을 해보고 싶은데 해당 어플리케이션이 CSR 의 비중이 적지 않을 것 같아서 좀 망설여지는 부분이 있습니다. 현대 애플리케이션들은 사용자들과의 상호작용이 적을 수가 없을텐데 대다수의 앱들이 Next.js 의 SSR 위주의 개발로 충분히 커버가 가능한 것일까요?
-
해결됨따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
docker compose up 오류
postgres 강의 중 docker compose up을 실행하면 아래와 같이 오류가 뜹니다.version: "3" services: db: image: postgres: latest container_name: postgres restart: always ports: - "5432:5432" environment: POSTGRES_USER: "${DB_USER_ID}" POSTGRES_PASSWORD: "${DB_USER_PASSWORD}" volumes: - ./data:/var/lib/postgresql/datayml 파일은 수업 그대로 위/아래와 같이 작성했는데 4번쨰 줄 postgres 부분이 인식이 안되는것 같아서 이것 때문인지... 구글링을 해봐도 해결 방법을 모르겠습니다!
-
미해결Next + React Query로 SNS 서비스 만들기
error.js 와 loading.js 에 대한 질문이 있습니다.
Next에서 자체적으로 제공하는 에러 바운더리인 error.js 와 서스펜스인 loading.js는 '서버 컴포넌트'의 에러와 로딩만 처리하는 것인가요? 예를 들어 서버 컴포넌트인 page.tsx의 하위 클라이언트 컴포넌트에서 에러가 발생했을 때는 error.js에서 캐치가 안 되는 것인가요...?
-
미해결따라하며 배우는 노드, 리액트 시리즈 - 기본 강의
7강중에서
혹시 뭐가 문제 일까요..?const express = require('express'); // 내가 설치한 express 모듈을 가져온다. const app = express() // 새로운 express 앱을 만든다. const port = 5000 // 포트 const bodyParser = require('body-parser'); const {User} = require("./models/User"); // User 가져옴 //application/x-www-form-urlencoded app.use(bodyParser.urlencoded({extended:true})) // 바디 파서가 클라이언트에서 오는정보를 서버에서 분석해서 가져올수있게 하는것 //application/josn app.use(bodyParser.json()); // 애는 json타입을 분석해서 가져옴 const mongoose = require('mongoose'); mongoose.connect('mongodb+srv://jin:0000@jin.p3agn.mongodb.net/?retryWrites=true&w=majority&appName=jin',{ useNewUrlParser: true, useUnifiedTopology: true }).then(()=> console.log('MongoDB Connected...')) .catch(err => console.log(err)) app.get('/', (req, res) => { // 앱을 넣은 후에 루트디렉토리에 오면 헬로월드 실행? res.send('Hello World!') }) app.post('/register',(req,res) => { //회원 가입 할때 필요한 정보들을 클라이언트에서 가져오면 // 그것들을 데이터 베이스에 넣어준다. const user = new User(req.body) // user 정보들을 데이터베이스에 넣기위해 req.body로 작성하면됨 // req.body 에는 정보들 있음 user.save((err,userInfo)=>{ // 만약 저장을 할때 err가 있을때 클라이언트한테 json형식으로 알려줌 if(err) return res.json({success:false, err}) // err 메세지 전달 return res.status(200).json({ // status200은 성공했다는 의미 success:true }) }) // save는 몽고디비에서 오는 메서드 // req.body 정보들이 user모델에 저장이됨 }) app.post('/register', async (req, res) => { try { const user = new User(req.body); // user 정보들을 데이터베이스에 넣기위해 req.body로 작성하면됨 // req.body 에는 정보들 있음 const userInfo = await user.save(); // 만약 저장을 할때 err가 있을때 클라이언트한테 json형식으로 알려줌 res.status(200).json({ success: true, userInfo }); } catch (err) { // err 메세지 전달 res.json({ success: false, err }); } }); app.listen(port, () => { console.log(`Example app listening on port ${port}`) //앱을 포트 5000번에서 실행 })
-
해결됨한 입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지
캐시를 기다리는 중. 질문드립니다
공통 컴포넌트 만들기 과정에서 Header left right버튼을 넣어서 수정하고 랜더링하는 과정에서 무한 대기로 빠집니다.Header를 삭제하면 랜더링이 잘 되는데, 동일하게 코드를 따라했음에도 Header를 넣으면 "캐시를 기다리는 중"이라는 문구와 함께 대기 상태로 접어듭니다원인을 잘 모르겠습니다
-
해결됨따라하며 배우는 노드, 리액트 시리즈 - 레딧 사이트 만들기(NextJS)(Pages Router)
부록) remark 강의 중 parmas 오류
부록 따라가고 있는데 그대로 소스 코드를 작성해서 실행하면 localhost에 아래와 같이 오류가 뜹니다.오류 메시지가 [id].tsx 파일에 아래와 같이 뜨긴 하는데 강의 중 강사님 화면에도 그렇고 강의 자료에도 똑같이 오류 메시지(빨간 줄)가 있더라구요. next13부터 라우팅 방식이 달라졌다고 하던데 버전 문제인건지...아래 params 오류 제외하고는 모두 동일한 소스 코드를 작성했고 오류도 없습니다.해결 방법이 궁금합니다. **혹시 몰라서 [id].tsx 랑 post.ts 코드 전체 첨부합니다.<id.tsx>import React from 'react' import Head from 'next/head' import { GetStaticPaths, GetStaticProps } from 'next' import { getAllPostIds, getPostData, getSortedPostsData } from '../../lib/post' const Post = ({postData}: { postData: { title: string date: string contentHtml: string } }) => { return ( <div> <Head> <title>{postData.title}</title> </Head> <article> <h1>{postData.title}</h1> <div> {postData.date} </div> <div dangerouslySetInnerHTML={{__html: postData.contentHtml}} /> </article> </div> ) } export default Post export const getStaticPath: GetStaticPaths =async () => { const paths = getAllPostIds(); return{ paths, fallback: false } } export const getStaticProps: GetStaticProps =async ({params}) => { const postData = await getPostData(params.id as string) return { props: { postData } } }<post.ts>import fs from 'fs' import path from 'path' import matter from 'gray-matter' import { remark } from 'remark'; import remarkHtml from 'remark-html/lib'; const postsDirectory = path.join(process.cwd(), 'posts') console.log('process.cwd()', process.cwd()); console.log('postsDirectory.cwd()', postsDirectory); export function getSortedPostsData(){ //Get file names under /posts const fileNames = fs.readdirSync(postsDirectory) console.log('fileNames', fileNames); //fileNames ['pre-rendering.md', 'ssg-ssr.md'] const allPostsData = fileNames.map(fileName => { //Remove ".md" from file name to get id const id = fileName.replace(/\.md$/, '') //Read markdown file as string const fullPath = path.join(postsDirectory, fileName) const fileContents = fs.readFileSync(fullPath, 'utf8') //Use gray-matter to parse the post metadata section const matterResult = matter(fileContents) //Combine the data with the id return{ id, ...(matterResult.data as {date: string; title: string}) } }) //Sort posts by date return allPostsData.sort((a,b) => { if(a.date<b.date){ return 1 } else{ return -1 } }) } export function getAllPostIds(){ const fileNames = fs.readdirSync(postsDirectory); return fileNames.map(fileName => { return { params: { id: fileName.replace(/\.md$/, '') } } }) } export async function getPostData(id: string){ const fullPath = path.join(postsDirectory, `${id}.md`) const fileContents = fs.readFileSync(fullPath, 'utf-8') const matterResult = matter(fileContents); const processedContent = await remark().use(remarkHtml).process(matterResult.content); const contentHtml = processedContent.toString(); return { id, contentHtml, ...(matterResult.data as {date: string; title: string}) } }
-
미해결파이썬/장고 웹서비스 개발 완벽 가이드 with 리액트 (장고 4.2 기준)
외래키 관계라는게 무슨 의미인지 잘 모르겠습니다.
안녕하세요 강사님.post 모델과 코멘트, 즉, post 테이블과 코멘트는 외래키 관계라고 설명해주셨는데, 제가 db용어를 잘 모르고, 찾아봐도 와닿지 않아서 이해가 잘 되지 않았습니다. 감사합니다.
-
해결됨Next + React Query로 SNS 서비스 만들기
route handlers 에 대한 질문이 있습니다
안녕하세요, app router에 대해 계속 공부하다가 route handlers 에 대한 궁금증이 해결되지 않아 질문하게 됐습니다. Next app router에서 정확히 route handlers를 사용해야 하는 이유가 무엇인가요?제가 생각했을 땐 서버 데이터 캐싱이나 API 엔드포인트를 숨길 수 있다는 장점이 있는데 이건 서버 컴포넌트에서 fetch하는 것으로도 대체가 되는데 route handlers를 사용해야 하는 특별한 이유가 따로 있는 것인가요? 모든 API를 route handlers로 하면 Next서버에 부하가 걸릴텐데 어떻게 해결할 수 있을까요? 이 부분은 공식문서에서 제가 못 찾은 것 같은데, 만약 외부 백엔드 API가 있고 여기에 데이터 요청을 할 때클라이언트 컴포넌트에서의 모든 API 요청을 1차로 route handler에 하고 여기서 외부 백엔드 API로 요청하게되면 route handlers에 요청이 몰리게 되는데 이때 Next 서버에 걸리는 부하를 어떻게 해소할 수 있을까요?
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
[id].tsx 서버사이트 호출시 2회씩 되는데요 ㅠㅠ
안녕하세요.[id].tsx 소스인데요 .. fetch를 2씩 호출되는 걸까요? ㅠ2번째 호출될때는 id 값에 undefinded 로 되어서 페이지 오류가 발생됩니다 ㅠㅠ뭐가 잘못 된것일까요?캡쳐 보내드립니다.
-
미해결손에 익는 Next.js - 공식 문서 훑어보기
안녕하세요 generateStaticParams 관해서 질문
// [country]/layout.tsx const SUPPORTED_LANGS = ['kr', 'us']; interface LangMap { [key: string]: string; } const LANG_MAP: LangMap = { kr: 'ko', us: 'en' }; export function generateStaticParams() { return SUPPORTED_LANGS.map(country => ({country})); } export const metadata: Metadata = { title: "Create Next App", description: "Generated by create next app", }; export default function RootLayout({ children, params, }: { children: React.ReactNode; params: { country: string }; }) { return ( <html lang={LANG_MAP[params.country]}> <body> <TanstackQueryProvider> <div className='container'> <BannerWrap/> <Header/> <main>{children}</main> <Footer/> </div> </TanstackQueryProvider> </body> </html> ); }import Banner from "@/component/Banner"; import { getQueryClient } from "@/component/TanstackQueryOption"; import { fetchBanner } from "@/fetch/getReviews"; import { dehydrate, HydrationBoundary } from "@tanstack/react-query"; export default function BannerWrap () { const queryClient = getQueryClient(); queryClient.prefetchQuery({ queryKey:['banners'], queryFn: fetchBanner, }) return ( <HydrationBoundary state={dehydrate(queryClient)}> <Banner /> </HydrationBoundary> ) } 빌드 후 next start로 테스트 중 의문점이 들어서 질문드립니다!generateStaticParams 와 fetch의 revalidate 10초, tanstackQuery staleTime 10초 로 설정후RootLayout 에서 BannerWrap에 prefetchQuery와 HydrationBoundary 를 통하여 data를 prefetch하고있는데 이게 layout이 전역에서 실행되서 그런지 생성된 페이지 개수만큼 요청을 날리는데 next에서는 같은 요청이 중복되지 않도록 요청을 캐시하고 중복 요청을 제거 한다고 배웠는데이렇게 중복으로 요청하는 이유는 뭘까요?