묻고 답해요
156만명의 커뮤니티!! 함께 토론해봐요.
인프런 TOP Writers
-
미해결Next + React Query로 SNS 서비스 만들기
재랜더링 최적화 문제
안녕하세요. 제가 직접 tailwind css v4를 이용해서 트위터 클론코딩을 진행하고 있는데SearchForm에서 입력이 이루어지면, SearchForm의 영향으로 인해서 다른 영역에서도 재랜더링이 일어나는 것 같습니다.먼저 묻고싶은 내용은 어떻게 하면 다른 영역은 재렌더링이 일어나지 않게 할까 입니다. 리엑트 개발자 도구로 렌더링이 일어날때 하이라이트 표시를 켰습니다. 이 때 SearchForm에 입력이 일어나면 위와같이 SearchForm만 아닌, 다른 영역에도 렌더링이 되는 모습이 보입니다. SearchForm 구성은 다음과 같이했습니다.최대한 현재 트위터의 입력 방식을 맞추어 보았습니다."use client"; import { useSearchParams } from "next/navigation"; import React, { useRef, useState, ChangeEventHandler, useEffect, memo, } from "react"; interface SearchFormProps { q?: string; } const SearchForm = () => { const [value, setValue] = useState(""); const inputRef = useRef<HTMLInputElement>(null); const searchParams = useSearchParams(); const search = searchParams.get("q"); const handleChange: ChangeEventHandler<HTMLInputElement> = (e) => setValue(e.target.value); const handleClear = () => { setValue(""); inputRef.current?.focus(); }; useEffect(() => { setValue(search ?? ""); }, []); return ( <div className="relative w-inherit h-12 group min-w-0"> {/* Border 레이어 */} <div className={` absolute inset-0 border border-default-border rounded-full transition-all duration-75 group-focus-within:border-2 group-focus-within:border-twiiter-blue `} /> {/* 내부 요소 컨테이너 */} <div className="relative w-full h-full"> <form className="flex items-center w-full h-full px-4" autoComplete="off" onSubmit={(e) => e.preventDefault()} > {/* 검색 아이콘 (외부 div 기준 위치) */} <svg className="absolute left-4 top-1/2 -translate-y-1/2 text-gray-500 pointer-events-none" width={20} height={20} viewBox="0 0 24 24" aria-hidden="true" fill="none" stroke="currentColor" strokeWidth={2} > <circle cx="11" cy="11" r="8" /> <line x1="21" y1="21" x2="16.65" y2="16.65" /> </svg> {/* Input */} <input ref={inputRef} type="search" placeholder="검색" value={value} onChange={handleChange} className=" w-full h-full pl-10 pr-10 bg-transparent text-base outline-none placeholder-gray-500 appearance-none " /> {/* Clear 버튼 (외부 div 기준 위치) */} {value && ( <button type="button" onClick={handleClear} className=" absolute right-3 top-1/2 -translate-y-1/2 w-7 h-7 flex items-center justify-center bg-gray-700 hover:bg-gray-800 rounded-full transition " tabIndex={-1} aria-label="Clear" > <svg width={16} height={16} viewBox="0 0 20 20" fill="white"> <path d="M10 8.586l4.95-4.95 1.414 1.414L11.414 10l4.95 4.95-1.414 1.414L10 11.414l-4.95 4.95-1.414-1.414L8.586 10l-4.95-4.95L5.05 3.636 10 8.586z" /> </svg> </button> )} </form> </div> </div> ); }; export default SearchForm; 이를 SearchHeader에 적용하였으며.import React from "react"; import SearchTab from "./SearchTab"; import SearchForm from "@/components/common/SearchForm"; const SearchHeader = () => { return ( <div className="w-[calc(100%-72px)] sm:pl-0 sm:max-w-[598px] fixed backdrop-blur-lg border-b-1 border-default-border bg-white/70 dark:bg-black/30"> <div className="w-full mt-2"> <SearchForm /> </div> <div className="w-full mt-1 h-[53px]"> <SearchTab /> </div> </div> ); }; export default SearchHeader; 최종적으로 /search 페이지에 이를 적용했습니다.import React from "react"; import Post from "../home/_components/Post"; import SearchHeader from "./_components/SearchHeader"; interface SearchPageProps { searchParams: Promise<{ q: string; f?: string; pf?: string }>; } const SearchPage = async ({ searchParams }: SearchPageProps) => { const { q } = await searchParams; return ( <main className="main-container"> <SearchHeader /> <div className="mt-[107px]"> <Post /> <Post /> <Post /> <Post /> <Post /> <Post /> <Post /> <Post /> <Post /> </div> </main> ); }; export default SearchPage; 관련된 layout.tsx는 다음과 같습니다.import Image from "next/image"; import Link from "next/link"; import React, { ReactNode } from "react"; import logo from "@/../public/twitter-logo.svg"; import SearchForm from "@/components/common/SearchForm"; import NavMenu from "./_components/NavMenu"; import LinkButton from "@/components/common/LinkButton"; import FollowCard from "./_components/FollowCard"; import TrendCard from "./_components/TrendCard"; import RightSection from "./_components/RightSection"; interface AfterLoginLayoutProps { children: ReactNode; modal: ReactNode; } const AfterLoginLayout = ({ children, modal }: AfterLoginLayoutProps) => { return ( <div className="overflow-y-scroll"> <div className="flex items-stretch"> <header className="flex items-end flex-col sm:flex-grow-1"> <section className="w-[72px] p-2 xl:p-0 xl:w-[275px] h-dvh"> <div className="flex flex-col w-inherit h-dvh fixed "> <Link href={"/home"}> <div className="w-14 h-14 rounded-[50%] flex justify-center items-center hover:bg-[rgba(15,20,25,0.1)]"> <Image src={logo} alt={"twitter logo"} width={40} height={40} /> </div> </Link> <NavMenu /> </div> </section> </header> <div className="flex items-start flex-col h-dvh flex-grow-1"> <div className="h-full w-[100%] sm:w-[600px] lg:w-[920px] xl:w-[990px] flex justify-between "> <main className="w-full sm:max-w-[600px] min-h-full h-fit border-l-1 border-r-1 border-default-border"> {children} </main> <div className="hidden lg:block lg:w-[290px] xl:w-[350px] h-fit relative"> <div className="flex flex-col w-inherit h-dvh fixed pt-1"> <RightSection /> </div> </div> </div> </div> </div> {modal} </div> ); }; export default AfterLoginLayout; SearchForm에 React.memo를 적용을 해보아도 변하지 않았습니다.(다른 영역, 예를 들어 main이 아닌 양 옆의 영역들에 대해서도 React.memo를 넣었지만 그래도 렌더링이 일어나고 있습니다.) 재랜더링 조건은 부모 컴포넌트가 재랜더링 되거나, props가 바뀌거나, state 변경이 일어났을 때인걸로 알고 있습니다.searchForm에서 Input만 영역에만 영향을 줘야할 것이 분명한데, 전체 영역에서 재랜더링이, 즉 layout.tsx에서 재랜더링이 일으키고 있는것 같습니다. (부모 영역) 혹시 렌더링이 어디까지 일어나는지 확인하는 (즉 최종 부모 컴포넌트까지) 방법이 있나요?그리고 이런 문제가 있을때 어떻게 최적화 할 수 있나요?p.s. 코드상 w-inherit 클래스가 이면 제가 직접 tailwind css utility에 추가하여 기능하도록 만들었습니다.+ 추가console.log()로 재랜더링이 일어나는지 확인해 보았는데 콘솔이 뜨지 않아 재랜더링이 아닌 다른 무슨 활성화(?) 인것 같아 보입니다... 하지만 SearchForm 입력 가지고 무언가 활성화 되는 것 자체가 조금 이해가 되지 않아서... 일단 재랜더링이라고 표현으로 남겨두었습니다...
-
미해결한 입 크기로 잘라먹는 Next.js(v15)
강사님의 로그와 저의 리퀘스트 메모이제이션 로그가 달라요!
넥스트 서버에서 찍히는 로그가 달라서 문의드립니다.다만 제가 백엔드쪽에서 콘솔을 찍어보니까 넥스트 로그와는 별개로 한번씩만 호출되는걸로 보여지는데 리퀘스트 메모이제이션이 잘 동작하는게 맞는지 궁금합니다 넥스트 로그 네스트 컨트롤러 로그
-
해결됨[풀스택 완성] Supabase로 웹사이트 3개 클론하기 (Next.js 14)
모듈 에러
✅ 모든 질문들은 슬랙 채널에서 답변드리고 있습니다.💡 ”로펀의 인프런 상담소” 슬랙 채널 가입하기 💡평일중에는 퇴근 이후(저녁 7시)에 답변을 받아보실 수 있고, 주말중에는 상시 답변드리고 있습니다. 모듈 에러가 뜨는데 수파베이스 설치를 잘못 한 것일까요? 검색해서 이리 저리 해보아도 잘 해결이 되지 않네요. 도와주세요~
-
해결됨Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
Parallel Route를 사용한 모달에 대해 질문이 있어요.
하드 내비게이션(새로고침, 직접 URL 접근) 불가라고 하셨는데, default.js를 활용하면, 딥 링킹과 공유 가능 URL을 지원할 수 있는걸까요??
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
서버 컴포넌트 console.log
앱 라우터의 데이터 패칭 수업 중 서버 컴포넌트에서 찍은 콘솔창은브라우저에서는 보이지 않는다고 하시는데 브라우저 콘솔에 아주 잘보이거든여? 제가 잘 못 이해한걸 까요? // 랜덤으로 추천도서 가져옴 async function RecoBooks() { //api로 데이터를 불러오면 타입스크립트는 어떤 결과값을 가져올지 몰라 타입정보를 지정해줘야한다. const response = await fetch( `${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/random` ); //예외처리 필수 if (!response.ok) { return <div>오류가 발생했습니다...</div>; } const recoBooks: BookData[] = await response.json(); //타입 : BookData[] console.log("랜덤 => ", recoBooks); //정상적으로 불러와서 렌더링까지 확인할 수 있다. return ( <div> {recoBooks.map((book) => ( <BookItem key={book.id} {...book} /> ))} </div> ); } export default function Home() { //async 제외 // 인덱스 페이지 return ( <div className={style.container}> {/* section 태그는 div 태그와 이름만 다른뿐 기능은 같다 */} <section> <h3>지금 추천하는 도서</h3> {/*books은 mock폴더안에 임시 배열데이터, list 형태로 렌더링 */} <RecoBooks /> </section> <section> <h3>등록된 모든 도서</h3> <AllBook /> </section> </div> ); }
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
서버 컴포넌트의 렌더링 과정
Next.js의 App Router 강의를 듣다가 헷갈리는 부분이 있어서 질문 드립니다!서버 컴포넌트로 초기 접속을 하게 되면 서버에서 RSC Payload와 HTML을 렌더링해서 브라우저에 보여주는걸까요? 아니면 RSC Payload가 직렬화한 HTML 정보를 가지고 있어서 바로 브라우저에 보내지는걸까요? 공식 문서에는 하이드레이션을 한다고 되어 있는데 하이드레이션을 하게 되면 두 번 렌더링이 되는거 아닌가요?? Link를 통해 서버 컴포넌트로 이동하게 되면 클라이어트 컴포넌트가 이동하는 것처럼 CSR 방식으로 동작을 하는건가요? 만약 동작을 한다 그러면, prefetch된 RSC Payload를 통해서 브라우저가 새로운 UI를 구성하는건가요?
-
해결됨바이브 코딩: Next.js + FastAPI + Faster-Whisper로 음성 메모 앱 만들기
ConnectionRefusedError: [WinError 1225] 원격 컴퓨터가 네트워크 연결을 거부했습니다
ConnectionRefusedError: [WinError 1225] 원격 컴퓨터가 네트워크 연결을 거부했습니다자꾸 이렇게 뜨면서 실행이 안되는데 어떻게 해야되나요?
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
npx prisma db push 오류 해결 부탁드립니다.
이미 다른 분들이 동일하거나 비슷한 경우를 많이 올려주셔서 다시 해봐도 도저히 해결이 안되어 문의 글 남깁니다..env 생성했고...# Connect to Supabase via connection pooling DATABASE_URL="postgresql://postgres.zbjatvpiqrregrejqyok:akswlwlak29@aws-0-ap-northeast-2.pooler.supabase.com:6543/postgres?pgbouncer=true" # Direct connection to the database. Used for migrations DIRECT_URL="postgresql://postgres.zbjatvpiqrregrejqyok:akswlwlak29@aws-0-ap-northeast-2.pooler.supabase.com:5432/postgres" 이렇게 오류가 발생합니다.C:\Users\BANG\Documents\onebite-books-server-main\onebite-books-server-main>npx prisma db pushEnvironment variables loaded from .envPrisma schema loaded from prisma\schema.prismaDatasource "db": PostgreSQL database "postgres", schema "public" at "aws-0-ap-northeast-2.pooler.supabase.com:5432"Error: Schema engine error:FATAL: Tenant or user not foundsupabase에서 계속 프로젝트 삭제 후 재생성해보고 비번도 바꿔봐도 동일한 증상입니다.확인 부탁드립니다.
-
해결됨한 입 크기로 잘라먹는 Next.js(v15)
모달 Metadata 질문입니다.
모달을 열 때는 Metadata가 제대로 설정되지 않고 새로고침 했을 때 메타데이터가 적용되는데 이 부분은 어떻게 해결을 해야 하나요?(주신 예제파일을 그대로 실행해도 같은 결과가 나옵니다.)
-
해결됨[코드캠프] 부트캠프에서 만든 '완벽한' 프론트엔드 코스
17-03 백엔드 호스트와 포트 에러
강의 45:00분에 나오는 host, port, username, password 등을 따라 작성해보고, 노션에 기입된 해당 코드 역시 시도해보았지만, 다음과 같은 에러가 계속해서 발생합니다.백엔드 프로그램을 실행합니다! 여기서 API를 만들거예요. 여기에 DB에 접속하고, 테이블을 만들 거예요. Error: connect ETIMEDOUT 34.64.244.122:5031 at TCPConnectWrap.afterConnect [as oncomplete] (node:net:1634:16) { errno: -60, code: 'ETIMEDOUT', syscall: 'connect', address: '34.64.244.122', port: 5031 }아래는 index.ts와, Board.postgres.ts 입니다.import { DataSource } from "typeorm" import { Board } from "./Board.postgres." console.log("백엔드 프로그램을 실행합니다!") console.log("여기서 API를 만들거예요.") // // console.log("여기에 DB에 접속하고, 테이블을 만들 거예요.") const AppDataSource = new DataSource({ type: "postgres", host: "34.64.244.122", port: 5031, username: "postgres", password: "postgres2022", database: "postgres", synchronize: true, logging: true, entities: [Board], }) AppDataSource.initialize() .then(() => { console.log("DB에 접속 성공했습니다. 동기화를 시작합니다.") }) .catch((error) => console.log(error)) import { BaseEntity, Column, Entity, PrimaryGeneratedColumn } from "typeorm" @Entity() export class Board extends BaseEntity { @PrimaryGeneratedColumn("increment") number!: number @Column({ type: "text" }) writer!: string @Column({ type: "text" }) title!: string @Column({ type: "text" }) contents!: string }
-
미해결Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
유튜브 영상과의 차이점 문의
유튜브에서도 이미 올려주시는것을 보고강의도 구매했는데영상이 꽤 겹치는것 같은데, 인프런 강의에서만 나와있는 영상은 어떤걸까요?
-
해결됨Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
template.tsx 가 SEO 에 주는 이점에 대한 질문
template.tsx는 페이지 전환 시 새로운 인스턴스를 생성하여 상태가 초기화되는데,이러한 특성을 활용해 SEO 메타데이터 처리의 정확성과 일관성을 높이기 위한 목적으로 사용하는 것인가요?즉, 전역 상태나 클라이언트 캐시 등으로 인해 예외적으로 SEO 메타데이터가 적용되지 않는 문제를 방지하기 위한 보완적 수단으로 보면 될까요?
-
해결됨Next.js 까보기: "쓸 줄 아는 개발자"에서 "알고 쓰는 개발자"로
자동화 스크립트 관련하여 질문있습니다.
스크립트를 수정해 동적 라우팅이나, Route Group 같은 폴더도 고려해서 pathname.ts를 구성해야 될까요?
-
해결됨[코드캠프] 부트캠프에서 만든 고농축 프론트엔드 코스
서버 502 error
백엔드 서버 키니 이렇게 나오는데 왜이런가요?
-
해결됨[코드캠프] 부트캠프에서 만든 '완벽한' 프론트엔드 코스
리액트 1강
선생님 수업 내용 똑같이 따라쳤는데 (바벨도 다운로드 코드도 쳤는데)라이브서버로 실행시켰을때 (>)신택스 에러뜨면서안녕하세요 안떠요 ㅠㅠ리액트나 바벨 설치가 안된거 아닌가요?
-
해결됨[코드캠프] 부트캠프에서 만든 '완벽한' 프론트엔드 코스
Vs code 코드 저장하면 정렬 이상하게 되요!
이런 코드가 ctrl+s 눌러서 저장하면이렇게 바뀌는데 가독성이 안좋아서 저장해도 가독성좋게 1줄로 하고싶은데해결방법이 있을까요ㅠㅠ?
-
해결됨[코드캠프] 부트캠프에서 만든 '완벽한' 프론트엔드 코스
input text 빈 공간 ""
왜 빈 공간을 " " 이렇게 나타내지 않고"" 로 붙여서 나타내나요?선생님께서 저번 수업때 ex) 1 산청딸기표현할때console.log(1+" "+산청딸기) 이런식으로 띄어쓰기는(빈공간)은 " " 가 맞지 않나요?
-
해결됨[코드캠프] 부트캠프에서 만든 '완벽한' 프론트엔드 코스
function 형식
let time=10setInterval(function(){console.log(time)},1000)강의 중setInterval에 익명함수를 집어넣는다고 하셨는데let time=10setInterval(let aa=function(){console.log(time)},1000)이 코드가 맞지 않나요?그니까 먼저 익명함수 이름부터 선언해야하지 않나요?그리고 여기서도위에 함수는 change라고 이름을 붙여줬는데밑에 함수는 이름도 없이 쓰는것이 왜 그런거인지 궁금합니다!
-
해결됨[코드캠프] 부트캠프에서 만든 '완벽한' 프론트엔드 코스
판매, 구매 목록등 판매자, 구매자 데이터를 불러오지 못합니다.
마이페이지에서 구매내역에서 seller, buyer의 _id, name 등 가져오지 못합니다.query { fetchPointTransactionsOfBuying(page: 1, search: "") { amount status statusDetail travelproduct { name seller { name } } } }graphQl 페이지에서 직접 header에 토큰 넣어도 불러오지 못하는데 어떻게 피그마에 있는 구매내역의 판매자 값을 불러올 수 있을까요?seller, buyer를 포함하면 API 요청은 되는데 에러가 떠 데이터 사용하지 못하고 제외하고 요청을 하면 정상적으로 사용할 수 있습니다.
-
해결됨웹 개발자의 연봉을 올려주는 하이브리드앱 with Expo 프레임워크
인스펙터가 웹뷰 내부의 웹을 못잡습니다.
안녕하세요 시뮬레이터 실습하고 있는 수강생입니다.아래 사진처럼 시뮬레이터로 사파리에 접속하면 맥북의 사파리 인스펙터에서 시뮬레이터 속 웹을 인지하는데요, 엑스포 앱을 통해 웹뷰 내부의 웹은 읽지 못하는 것 같아요따로 설정해야하는 것이 있을까요 ?