createBoard(createBoardInput: $createBoardInput) { _id } 이 부분에서 _id만 작성하는 이유가 fetchBoard를 할 때 게시글의을 불러오는 기준을 id로 하겠다는 의미인걸까요? 2. apolloclient 를 사용하는 코드들을 안 보고 혼자 힘으로 작성 하는게 너무 어렵습니다.. 다음 수강을 계속 들으면서 계속 사용하게 될텐데 하면서 적응해 나가야 할지, 혼자 작성이 가능할 때 까지 계속 영상 돌려보며 연습을 해야할지 모르겠어요 어떻게 하면 좋을까요?
초기 접속 요청을 할 때, Next.js에서는 서버 컴포넌트와 클라이언트 컴포넌트 모두 사전 렌더링을 한 후에 html을 제공하고 이후 Hydration 과정이 이루어지는 것으로 알고 있습니다. 만약 클라이언트 컴포넌트에서 useState 와 같은 훅을 호출해서 사용하는 경우, 서버에서 이런 컴포넌트를 어떻게 렌더링하는지 궁금합니다. 최상위 page 컴포넌트가 아래와 같이 있고, // page.tsx import Client from "@/components/client"; export default function Home() { return ( <div> initial html <div> <Client /> </div> </div> ); } page 컴포넌트에서 불러오는 클라이언트 컴포넌트가 아래와 같을 때 "use client"; import { useState } from "react"; export default function Client() { const [count, setCount] = useState(0); const handleClickPlusButton = () => { setCount(count + 1); }; const handleClickMinusButton = () => { setCount(count - 1); }; return ( <div> I am Client Component <div>count: {count}</div> <div> <button onClick={handleClickPlusButton}>+</button> <button onClick={handleClickMinusButton}>-</button> </div> </div> ); } 서버에서 클라이언트 컴포넌트를 렌더링 할 때, useState 와 같은 훅을 무시하고 렌더링을 진행한다고 생각하여 count에 값이 없을 것이라고 예상을 했지만, 서버에서 초기에 응답해준 html 파일을 보면 count가 0이 되어있었습니다. 서버에서 클라이언트 컴포넌트를 렌더링 할 때 이런 훅을 어떻게 처리하는지, 또 만약 브라우저의 window 객체에 접근하게 될 때는 어떻게 처리하는지 궁금합니다!
사전 렌더링 시 처음에 서버 측에서 리액트 앱을 실행해서 모든 리액트 컴포넌트들을 HTML로 변환한다고 하셨는데 저는 거기에 인터렉션 코드를 포함한 모든 리액트 코드가 들어있는 걸로 이해를 했었습니다. 근데 그 후에 인터렉션 코드를 추가로 보내야 된다고 해서 좀 헷갈렸는데요 그럼 처음에 서버에서 HTML로 변환한 JS 파일에는 인터렉션 코드를 제외한 모든 리액트 코드가 들어있는 걸까요?
안녕하세요. 면접준비에 도움이 될 거 같고 개념적으로도 궁금해서 질문드립니다. 장바구니에서 삭제를 하면 갱신되는데에 동작원리에서 처음엔 router.replace(router.asPath) 때문에 url이 변경되진 않아도 단순하게 /cart 로 이동이란 동작을 해서 페이지를 다시 그린다고 생각했습니다. CartList 는 CartPage 의 자식 컴포넌트이다. CartPage 는 getServerSideProps 로 서버에서 받아온 데이터를 프롭스(carts)로 받으며, 그 프롭스를 CartList 에게 전달해주고 있다. CartList 는 부모컴포넌트에게 받은 carts 프롭스를 통해 장바구니 목록을 보여주고 있다. 장바구니에서 상품을 삭제하면, 선택한 상품을 서버에서 삭제하고 router.replace 를 통해( router.push 도 동일) 현재 페이지(asPath)인 /cart 로 이동한다. /cart 페이지(즉, CartPage.jsx )가 리렌더링된다. 리액트는 리렌더링되면 컴포넌트의 모든 코드를 다시 실행하게 된다.(고 알고 있습니다.) 그로 인해 getServerSideProps 가 다시 실행되고 갱신된(장바구니에서 상품을 삭제한) 데이터를 다시 CartPage 에게 프롭스로 내려주게 된다. 프롭스가 변경됐으니 자식 컴포넌트인 CartList 도 리렌더링되어 모든 코드가 다시 실행된다. 바뀐 장바구니 데이터로 보여지게 된다. 라고 생각했는데요. https://nextjs.org/docs/pages/building-your-application/data-fetching/get-server-side-props#behavior 공식문서를 살펴보니 사용자가 Link 컴포넌트 또는 router를 통해 페이지를 방문할 때 , Next.js는 서버에 API 요청을 보내 getServerSideProps를 실행 합니다. 라고 되어있습니다. 이러면, 현재 CartList 는 CartPage 의 자식 컴포넌트이다. CartPage 는 getServerSideProps 로 서버에서 받아온 데이터를 프롭스(carts)로 받으며, 그 프롭스를 CartList 에게 전달해주고 있다. CartList 는 부모컴포넌트에게 받은 carts 프롭스를 통해 장바구니 목록을 보여주고 있다. 장바구니에서 상품을 삭제하면, 선택한 상품을 서버에서 삭제한다. router.replace 를 통해( router.push 도 동일) 현재 페이지(asPath)인 /cart 로 이동한다. router를 통해 페이지를 방문했으므로 CartPage 의 getServerSideProps 가 다시 실행되고 갱신된 데이터를 CartPage 에게 프롭스로 내려주게 된다. 프롭스가 변경됐으니 자식 컴포넌트인 CartList 도 리렌더링되어 모든 코드가 다시 실행된다. 바뀐 장바구니 데이터로 보여지게 된다. 이렇게 이해하면 될까요? 그리고, getServerSideProps 가 있는 페이지 컴포넌트는 getServerSideProps 가 재실행되면 자동으로 리렌더링되게 되는 구조인가요? 설명해주셨는데 제가 놓친거면 죄송합니다.
범샘님! 빠른 답변 및 업데이트 감사합니다, 답변해주신것처럼 section1, section4에서 스크롤문제가 발생합니다. 이 부분은 질문드리기 전에 확인한 부분이라 해결하였으나, 다만 답변해주신 두번째 경우는 제가 드린 질문의 방향과 조금 달라 재질문 드립니다. section4까지 스크롤을 내린후, 다시 section3까지 스크롤을 end-section3 지점까지 올리고, 다시 section4로 스크롤 할 경우 스크롤이 작동되지 않습니다. 이 부분은 첫번째 질문 드린 경우와 비슷한 상황인거 같은데, 이번에는 반대로 스크롤하는 경우라 direction을 down으로 하는 조건문을 추가하면 되는건지, 조금 더 명확한 답변과 코드를 확인하고 싶어 다시 질문드립니다. 여러모로 바쁘실텐데, 감사합니다!
안녕하세요, 쉬운 강의 덕분에 gsap 을 쉽게 접하고 사용할 수 있어서 감사합니다. 근데 해당 부분 구현중에 범샘께서 작성하신 코드(ScrollTrigger-finished)에서 확인해보면 1) section3 도달 후, section2로 스크롤을 올리는 경우 2) section4 도달 후, section3에서 다시 section4 로 스크롤을 내리는 경우 해당 2가지 경우에서 section03을 기준으로 스크롤이 위아래로 작동을 잘 하지 않습니다. if(currentPageIndex === 3) return; 때문인 것 같은데, 스크롤을 자유롭게 올렸다 내렸다 하면서 페이지를 확인할 수 있도록 하려고 하는데 잘 안되네요. 코드를 어떤 방식으로 수정해야할지 질문 남깁니다. 감사합니다.
안녕하세요! NextJS 에 대한 Flow 설명중 질문이 있습니다 9:01 Timeline 유저의 접속요청시 해당 페이지에 대한 내용만 랜더링하여 HTML 을 반환하는 걸까요? 그게 아니고 설명하신 모든 컴포넌트에 대한 렌더링이 이루어지는 것이라면 CSR 방식과 마찬가지로 HTML 반환이 늦어지지 않나 싶습니다 또한 사전 렌더링이 NextJS 서버가 부팅시 이루어지는 행위인지 궁금합니다! (서버 부팅시 랜더링된 HTML 이 생성되는지)
▲ Next.js 14.2.8 - Local: http://localhost:3000 - Environments: .env ✓ Starting... ✓ Ready in 4.2s ○ Compiling / ... ✓ Compiled / in 3.5s (1022 modules) GET / 200 in 4384ms GET / 200 in 81ms ✓ Compiled /api/auth/[...nextauth] in 364ms (493 modules) GET /api/auth/session 200 in 2386ms ○ Compiling /login ... ✓ Compiled /login in 1020ms (1035 modules) GET /api/auth/session 200 in 1561ms GET /login?_rsc=1pqm1 200 in 126ms ○ Compiling /(.)i/flow/login ... ✓ Compiled /(.)i/flow/login in 731ms (1050 modules) GET /api/auth/providers 200 in 44ms GET /api/auth/csrf 200 in 19ms [auth][error] CallbackRouteError: Read more at https://errors.authjs.dev#callbackrouteerror [auth][cause]: TypeError: Failed to parse URL from undefined/api/login at node:internal/deps/undici/undici:13178:13 [auth][details]: { "code": "ERR_INVALID_URL", "input": "undefined/api/login", "provider": "credentials" } POST /api/auth/callback/credentials? 200 in 40ms GET /api/auth/session 200 in 26ms 윈도우 인데 memurai설치가 도저히 안 되어서 그냥 redis 설치했습니다. 백엔드 코드 실행시키면 redis connected라고도 뜨고, service에도 실행중도 뜨고, hello world도 잘 뜹니다. REDIS_URL=redis://127.0.0.1:6379 //백엔드 env NEXT_PUBLIC_BASE_URL=http://localhost:3000 //z-com 에 있는 .env 이거로도 고쳐봤습니다. localhost:3000/login 여기로 넘어는 가는데 로그인이 안 됩니다. 깃허브에서 코드 잘 가져왔고, 회원가입도 잘 되는데 로그인만 안 됩니다. 뭐가 문제일까요 ㅠㅠ
it('최소 가격 또는 최대 가격을 수정하면 setMinPrice과 setMaxPrice 액션이 호출된다.', async () => { const { user } = await render(<ProductFilter />); const minPriceInput = screen.getByPlaceholderText('최소 금액'); const maxPriceInput = screen.getByPlaceholderText('최대 금액'); await user.type(minPriceInput, '10'); await user.type(maxPriceInput, '10000'); expect(setMinPriceFn).toHaveBeenCalledWith('10'); expect(setMaxPriceFn).toHaveBeenCalledWith('10000'); }); 전 이런식으로 작성했습니다. 단위 테스트에서 알려주신 AAA패턴을 해당 통합테스트에서도 적용하면 깔끔할 것 같아서 이렇게 작성했어요. 어차피 검증할건 setMaxPriceFn & setMinPriceFn이 호출됐는지 여부라 최소금액 및 최대금액 인풋을 연속적으로 조작하게 했습니다. 혹시 이렇게 하면 문제가 있는지 궁금합니다
기초부터 배우는 Next YTMusic 클론 코딩 (with next.js 14, UI 마스터)
안녕하세요. 우선 소개부터 드리자면 저는 FE 개발자나 그쪽을 지망하는 것은 아니고 백엔드를 업으로 하고 있고 집에서 홈서버에 제 개인 서비스를 배포할 목적으로 해당 강의를 수강하게 되었습니다. 사실 제가 프론트의 세계는 잘 몰라서 질문 드립니다. 혹시 페이지 로드 속도 & 검색 엔진 노출도가 배포 플랫폼에 영향을 받을까요? 다른 말로는, versel 을 통해 프론트를 배포하는 것이 배포가 쉬운 것 이외에 서비스의 퀄리티에도 도움을 주는 장점이 있을까요 ?
[코드팩토리] [초급] NestJS REST API 백엔드 완전 정복 마스터 클래스 - NestJS Core
현재 듣고 있는 강의 부분은 Guard chapter에서 basic, bearer guard를 적용하는 부분입니다. @Injectable() export class BearerTokenGuard implements CanActivate { constructor( private readonly authService: AuthService, private readonly usersService: UsersService, ) {} async canActivate(context: ExecutionContext): Promise<boolean> { const req = context.switchToHttp().getRequest(); const rawToken = req.headers['authorization']; if (!rawToken) { throw new UnauthorizedException('토큰이 없음'); } const token = this.authService.extractTokenFromHeader(rawToken, true); const result = await this.authService.verifyToken(token); // payload 반환 /** * req 객체에 넣을 정보 * 1) 사용자 정보 - user 객체 자체 * 2) token - token * 3) tokenType - access | refresh */ const user = await this.usersService.getUserByEmail(result.email); req.user = user; req.token = token; req.tokenType = result.type; return true; } } 제 개인적인 생각으로는 적어도 제목에 적힌 두 엔드포인트에 대해서는 현재의 BearerTokenGuard를 적용하는 것이 굳이 라는 생각이 듭니다. refreshToken을 이용하여 새로운 토큰을 발급받는 역할을 하는 두 엔드포인트에 대해 다른 줄은 다 문제가 크게 없다고 생각하지만 req.user = user;로 굳이 요청에 user 객체를 붙이는 것은 굳이라는 생각이 듭니다. 제 낮은 식견으로는 위 두 엔드포인트에 대한 guard는 또 따로 만들어야 한다고 생각이 드는데 강사님 생각이 궁금합니다.
2.5) 원시타입 VS 객체타입 약 08:50. 안녕하세요, 강사님의 강의를 만족하며 잘 듣고있는 수강생입니다. 해당부분에 다소 오해의 소지가 될 내용으로 추가 강의 업데이트시 반영되었으면 하는부분이 있어서 올려봅니다. '객체의 참조값을 복사함' 이라는 문장은 맞다고 볼 수 있지만, 이를 얕은 복사라 부르기엔 오해의 소지가 많을것으로 보입니다. o2는 o1의 포인터값을 그대로 똑같이 가지고 있을 뿐, o2가 가리키는 값이 o1과 동일하게 '새로운 값이 만들어지지 않았기 때문' 입니다. 또한, '새로운 객체를 생성하면서 프로퍼티만 따로 복사함'이라는 문장또한 맞다고 볼 수 있지만, 이를 깊은 복사라 부르기엔 오해의 소지가 역시 많을것으로 보입니다. 실제로 공식문서에서도 이를 논하기에는 쓸모없다고 얘기하고있지만, 그러면서 Shallow copy에 대해서 아래와 같이 강조하고있습니다. For shallow copies, only the top-level properties are copied, not the values of nested objects. 때문에, 추가적인 nested objects에 문제가 따르며 실제로 이때문에 이를 얕은복사라고 많은 개발자들이 소통하고 있는것으로 알고있습니다. 특히, '원본 객체가 수정될 수 없어 안전함' 까지 있으니, 더욱더 top-level의 중요성이 강조되지 않는 것으로 보여 모호한것으로 보입니다. 평소 강사님의 강의, 강연등을 즐겨듣고 있는 수강생으로써 약간의 다소 오해의 소지가 있는부분을 언급해 볼 뿐이오니 너그러이 내용을 참조해주시면 감사하겠습니다. 항상 감사합니다. 이상입니다.
안녕하세요? 바탕화면에 codecamp-frontend 라는 폴더를 만들고, 그 아래에 class 라는 폴더를 만들어서 리액트 첫 보일러플레이트를 만들었습니다. section01 폴더도 만들고, 차근차근 하고 있습니다. 그런데, 깃허브로 바탕화면에 있는 codecamp-frontend 라는 폴더를 관리해주고 싶은데, 배운 대로 git init 을 하고 git add . 을 하니, 터미널에서, 이 폴더의 하위에 있는 class 라는 폴더가 서브모듈이 된다고 경고가 뜹니다. 그래서 검색을 해서 어찌어찌 되돌리고, 하위에 있는 class 폴더만 깃허브 리포지토리로서 관리하게 되었습니다. 그런데 class라는 이름의 리포지토리가 있는 것이 마음에 안 들고, 몇 가지 질문이 생겼습니다. 리액트 앱은 그 자체를 단독으로, 하나의 리포지토리로서 관리해주는 것이 맞나요? class 라는 이름의 리포지토리가 있는 것이 알아보기 어렵고 중복이 쉬워 이름을 바꾸고 싶습니다. 바꿔주어도 상관없을까요? 깃이 꼬이지 않을까요? 깃과 깃허브로 리액트 앱들을 하나의 폴더(리포지토리(저장소))로 모아서 관리하려면 어떻게 관리해 주어야 하는 건지 궁금합니다. 감사합니다.