1:16 에서 not found.tsx가 보이는 이유는 @폴더명으로 만든 슬롯이 layout 에서 props로 값이 들어와야 하는데 @modal/i/flow/login 으로 page.tsx가 이동해버려서 layout에서 props로 가져올 modal 값이 없어져 404가 뜨는것이고, 메인 페이지에서는 모달이 필요 없기에 default.tsx를 만들어서 해결하는 것으로 이해하면 될까요?
안녕하세요 선생님 좋은 강의 정말 감사합니다. 다름이 아니라, 강의 중에선 generateStaticParams 에 관하여 다루진 않는 것 같아서 혼자서 공부중인데 그럼에도 여전히 궁금하고 확실하게 이해되지 않는 몇가지가 있어서 질문드립니다~! 기존 Next12에서 SSG(정적페이지 Pre-Rendering)을 Next13에서는 generateStaticParams 로 대체 된 것이 맞을까요? (동적라우팅페이지 포함) generateStaticParams 를 이용하여 증분정적생성(ISR) 형식으로 배포하려면 기존 fetch 옵션에 동일하게 { next: { revalidate: 60 } } 를 추가해주면 되는게 맞을까요? Next12에서는 데이터를 패칭한 정적페이지를 미리 생성해놓음으로서, 유저에게 빠른 속도로 페이지를 제공한다는 장점이 있다는 것을 공부했던 기억이 있습니다. 그런데, Next13 이후부터는 서버 '컴포넌트' 단위의 개발을 지향하는 듯 한데 generateStaticParams 을 이용하여 개발하는 것이 어떤 의미인지 잘 이해가 되지 않습니다~! 단지 Next13에서 정적페이지 생성을 위한 함수를 남겨둔 것이라고만 이해하면 좀 쉬울까요? 서버 컴포넌트 는 generateStaticParams 로 build하는 페이지에선 사용할 수 없는 것일까요? 저는 아직 대규모 프로젝트를 진행해본 적이 없는 주니어 개발자입니다. 보통 현업에서 동적라우팅 SSG 페이지를 대량으로 생성하여 배포하는 경우가 많을까요? 보통 어떤 경우에 많이 사용하실까요? 바쁘실텐데 질문이 많아 정말 죄송합니다 ㅠㅠ! 날이 많이 추워졌는데 건강에 유의하셨으면 좋겠습니다. 감사합니다~!
AntDesign만 사용하면 SyntaxError: Cannot use import statement outside a module 에러가 나옵니다. 구글링 해서 package.json에 " type":"module" 을 작성하면 된다고 하는데 작성하면 ReferenceError: module is not defined in ES module scope 에러가 나옵니다 어떻게 해결하면 좋을까요?
from typing import List from fastapi import FastAPI, Body, HTTPException, Depends from pydantic import BaseModel from sqlalchemy.orm import Session from database.orm import ToDo from database.connection import get_db from database.repository import get_todos from schema.response import ListToDoResponse, ToDoSchema app = FastAPI() @app.get("/") def heath_check_handler(): return {"ping": "pong"} todo_data = { 1: { "id": 1, "contents": "실전! FastAPI 섹션 0 수강", "is_done": True, }, 2: { "id": 2, "contents": "실전! FastAPI 섹션 1 수강", "is_done": False, }, 3: { "id": 3, "contents": "실전! FastAPI 섹션 2 수강", "is_done": False, }, } @app.get("/todos", status_code=200) def get_todos_handler( order: str | None = None, session: Session = Depends(get_db), ) -> ListToDoResponse: todos: List[ToDo] = get_todos(session=session) if order and order == "DESC": return ListToDoResponse( todos=[ToDoSchema.from_orm(todo) for todo in todos[::-1]] ) return ListToDoResponse( todos=[ToDoSchema.from_orm(todo) for todo in todos] ) @app.get("/todos/{todo_id}", status_code=200) def get_todo_handler(todo_id: int): todo = todo_data.get(todo_id) if todo: return todo raise HTTPException(status_code=404, detail="ToDo Not Found") class CreateToDoRequest(BaseModel): id: int contents: str is_done: bool @app.post("/todos", status_code=201) def create_todo_handler(request: CreateToDoRequest): todo_data[request.id] = request.dict() return todo_data[request.id] @app.patch("/todos/{todo_id}", status_code=200) def update_todo_handler( todo_id: int, is_done: bool = Body(..., embed=True) ): todo = todo_data.get(todo_id) if todo: todo["is_done"] = is_done return todo raise HTTPException(status_code=404, detail="ToDo Not Found") @app.delete("/todos/{todo_id}") def delete_todo_handler(todo_id: int): todo = todo_data.pop(todo_id, None) if todo: return raise HTTPException(status_code=404, detail="ToDo Not Found") from typing import List from pydantic import BaseModel class ToDoSchema(BaseModel): id: int contents: str is_done: bool class Config: orm_mode = True class ListToDoResponse(BaseModel): todos: List[ToDoSchema] from typing import List from sqlalchemy import select from sqlalchemy.orm import Session from database.orm import ToDo def get_todos(session: Session) -> List[ToDo]: return list(session.scalars(select(ToDo))) from sqlalchemy import create_engine from sqlalchemy.orm import sessionmaker DATABASE_URL = "mysql+pymysql://root:todos@127.0.0.1:3306/todos" engine = create_engine(DATABASE_URL, echo=True) SessionFactory = sessionmaker(autocommit=False, autoflush=False, bind=engine) def get_db(): session = SessionFactory() try: yield session finally: session.close() from sqlalchemy import Boolean, Column, Integer, String from sqlalchemy.orm import declarative_base Base = declarative_base() class ToDo(Base): __tablename__ = 'todo' id = Column(Integer, primary_key=True, index=True) contents = Column(String(256), nullable=False) is_done = Column(Boolean, nullable=False) def __repr__(self): return f"ToDo(id={self.id}, contents={self.contents}, is_done={self.is_done})" 에러가 납니다. 파이썬 콘솔 <input>:1: PydanticDeprecatedSince20: The from_orm method is deprecated; from schema.response import ToDoSchema from datagbase.orm import ToDo Traceback (most recent call last): File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode coro = func() ^^^^^^ File "<input>", line 1, in <module> File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\_pydev_bundle\pydev_import_hook.py", line 21, in do_import module = self._system_import(name, args, *kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ModuleNotFoundError: No module named 'datagbase' from database.orm import ToDo todo = ToDo(id=100, contents="test", is_done=True) ToDoSchema.from_orm(todo) <input>:1: PydanticDeprecatedSince20: The from_orm method is deprecated; set model_config['from_attributes']=True and use model_validate instead. Deprecated in Pydantic V2.0 to be removed in V3.0. See Pydantic V2 Migration Guide at https://errors.pydantic.dev/2.5/migration/ Traceback (most recent call last): File "C:\Program Files\JetBrains\PyCharm 2023.3.2\plugins\python\helpers\pydev\pydevconsole.py", line 364, in runcode coro = func() ^^^^^^ File "<input>", line 1, in <module> File "C:\Users\manag\pyProject\todos\Lib\site-packages\typing_extensions.py", line 2499, in wrapper return arg(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\pydantic\main.py", line 1126, in from_orm raise PydanticUserError( pydantic.errors.PydanticUserError: You must set the config attribute from_attributes=True to use from_orm http://localhost:8000/docs#/default/get_todos_handler_todos_get 접속시 터미널 INFO: 127.0.0.1:56312 - "GET /docs HTTP/1.1" 200 OK INFO: 127.0.0.1:56312 - "GET /openapi.json HTTP/1.1" 200 OK 2024-01-23 16:06:15,108 INFO sqlalchemy.engine.Engine BEGIN (implicit) 2024-01-23 16:06:15,109 INFO sqlalchemy.engine.Engine SELECT todo.id, todo.contents, todo.is_done FROM todo 2024-01-23 16:06:15,109 INFO sqlalchemy.engine.Engine [cached since 826.5s ago] {} 2024-01-23 16:06:15,113 INFO sqlalchemy.engine.Engine ROLLBACK INFO: 127.0.0.1:56312 - "GET /todos HTTP/1.1" 500 Internal Server Error ERROR: Exception in ASGI application Traceback (most recent call last): File "C:\Users\manag\pyProject\todos\Lib\site-packages\uvicorn\protocols\http\h11_impl.py", line 404, in run_asgi result = await app( # type: ignore[func-returns-value] ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\uvicorn\middleware\proxy_headers.py", line 84, in call return await self.app(scope, receive, send) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\applications.py", line 1054, in call await super().__call__(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\applications.py", line 123, in call await self.middleware_stack(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\errors.py", line 186, in call raise exc File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\errors.py", line 164, in call await self.app(scope, receive, _send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\middleware\exceptions.py", line 62, in call await wrap_app_handling_exceptions(self.app, conn)(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app raise exc File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app await app(scope, receive, sender) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 762, in call await self.middleware_stack(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 782, in app await route.handle(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 297, in handle await self.app(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 77, in app await wrap_app_handling_exceptions(app, request)(scope, receive, send) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 64, in wrapped_app raise exc File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\_exception_handler.py", line 53, in wrapped_app await app(scope, receive, sender) File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\routing.py", line 72, in app response = await func(request) ^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 299, in app raise e File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 294, in app raw_response = await run_endpoint_function( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\fastapi\routing.py", line 193, in run_endpoint_function return await run_in_threadpool(dependant.call, **values) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\starlette\concurrency.py", line 40, in run_in_threadpool return await anyio.to_thread.run_sync(func, *args) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\to_thread.py", line 56, in run_sync return await get_async_backend().run_sync_in_worker_thread( ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\_backends\_asyncio.py", line 2134, in run_sync_in_worker_thread return await future ^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\anyio\_backends\_asyncio.py", line 851, in run result = context.run(func, *args) ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\src\main.py", line 48, in get_todos_handler todos=[ToDoSchema.from_orm(todo) for todo in todos] ^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\typing_extensions.py", line 2499, in wrapper return arg(*args, **kwargs) ^^^^^^^^^^^^^^^^^^^^ File "C:\Users\manag\pyProject\todos\Lib\site-packages\pydantic\main.py", line 1126, in from_orm raise PydanticUserError( pydantic.errors.PydanticUserError: You must set the config attribute from_attributes=True to use from_orm
안녕하세요 선생님 도메인 연결을 했는데, 처음에 Front 도메인을 입력한 뒤 ?가 붙는 원인을 어떻게 알 수 있는지 궁급합니다. 도메인 연결 후 login후 Network => Headers-> RequestURL, Access-Control-Allow-Orign, SetCookie, Application->Cookies에는 도메인주소와 쿠키가 있고, 백엔드 도메인 입력시에는 물음표 안생깁니다. 둘다 화면은 잘 나옵니다. 백엔드 도메인 입력시) 프론트 도메인 입력시) 로그인시 network, application)
안녕하세요! 제로초님 [리뉴얼] React로 NodeBird SNS 만들기 강의의 섹션 6. AWS에 배포하기: 프론트 서버 배포하기 강의를 진행 중인 수강생 입니다! 우분투 프론트 서버는 구동이 되지만 프론트 IP 주소 사이트가 페이지 응답이 되지 않아 질문 올립니다! '로컬 리소스를 로드할 수 없습니다' 에러가 콘솔에 출력 되었지만 새로 고침을 하면서 없어졌습니다! Not allowed to load local resource: chrome-error://chromewebdata/#buttons 사전에 아래 사항을 정확히 확인 후 질문을 올립니다! 1. EC2 프론트 서버와 백엔드 인스턴스 상태는 잘 실행 중이며, 프론트 퍼블릭 IPv4가 틀리지 않았는지 확인하였습니다. 2. 로컬 프론트 경로에서 npm run build를 하였습니다. -> 저의 경우 우분투 프론트 서버에서 npm run build를 하면 메모리가 부족해 멈춤 현상이 나타납니다. -> 그래서 .next를 Git LFS로 관리하였고, 로컬 프론트에서 빌드에 성공하였습니다. 3. 윈도우 서비스에서 MySQL 서비스를 실행한 상태입니다. 4. 우분투 백엔드 서버 실행에 성공한 상태입니다! 5. 로컬 프론트 경로에서 node_module과 .next를 삭제했다가 npm i와 build를 통해 다시 만들었습니다. 6. about.js는 잠시 바탕 화면으로 옮겼습니다. 우분투 프론트 서버에 아래 명령어를 순서대로 입력하였습니다. (우분투 프론트 서버의 경우 sudo를 붙이지 않아도 되었습니다.) sudo git pull >>> 메모리 부족 문제로 npm run build는 로컬 프론트에서 진행하고 아래 작업을 마저 진행했습니다. <<< sudo npx pm2 reload all npx pm2 start npm -- start sudo npx pm2 monit 우분투 프론트 서버가 실행된 상태입니다. 우분투 백엔드 서버에 아래 명령어를 순서대로 입력하였습니다. sudo git pull sudo npx pm2 reload all sudo npx pm2 monit 우분투 백엔드 서버가 실행된 상태입니다. back/app.js 실제 프론트 서버 주소의 CORS 요청을 허용하였습니다. cors 요청 주소들을 변수로 빼서 작성하였습니다. // 로컬 프론트 서버, 노드버드 닷컴, 실제 프론트 서버 URL IP 주소 요청만 허용 const corsOkUrl = ['http://localhost:3000', 'nodebird.com', 'http://52.79.86.100' ]; . . . // 미들웨어 연결 app.use(cors({ /* 특정 url에서 요청했을 때만 cors 허용 */ origin: corsOkUrl, /* 사용자 인증이 필요한 쿠키 전달 허용 */ credentials: true, })); . . . // http://54.180.201.249 : 실제 백엔드 서버 URL IP 주소인 80번 포트로 서버 실행 app.listen(80, () => { console.log('서버 실행 중!'); }); back/config/config.js 실제 백엔드 주소가 들어가는 부분 코드에 모두 'backUrl'을 변수로 넣어주었습니다. // 실제 백엔드 서버 URL IP 주소 내보내기 export const backUrl = 'http://54.180.201.249'; front와 back의 package.json 이 문제를 해결하기 위해 먼저 노드버드 커뮤니티를 살펴보았습니다. 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=49016&category=questionDetail&tab=community&q=164898 저와 비슷하게 프론트 서버 구동에 성공하였으나 페이지 응답이 되지 않는 작성자 분이 계셨습니다. 글과 똑같이 우분투 프론트 서버 터미널에서 ctrl+c로 sudo npx pm2 monit을 끄고 pm2 list를 입력하면 status가 errored 임을 확인할 수 있었습니다. 보안 그룹에서 http 80번 포트가 열려있음에도 status는 errored 였습니다. Not allowed to load local resource 에러 해결, 우분투 프론트 서버 페이지 응답 등의 키워드로 검색하였으나 이미지 외부 경로 지정하기 관련 글들만 있어 방법이 맞는지 의심스럽습니다... 프론트 서버 구동 시 어떻게 하면 페이지 응답이 안되는 문제를 해결할 수 있을까요? 질문 글이 많이 김에도 끝까지 읽어주셔서 감사합니다 제로초님 강의 항상 잘 보고 있습니다!
React Query 공식 문서에 보면 queryClient 인스턴스를 생성해서 바로 QueryClientProvider의 client로 넘겨주고 있는데 제로초님께서는 useState의 초기 값으로 QueryClient의 인스턴스를 생성해서 넘겨주는 방법을 사용하셨는데요. 이 두가지 방법 중에 어떤 것을 사용해야 좋을지 궁금합니다. // 공식 문서 const queryClient = new QueryClient() function App() { return ( <QueryClientProvider client={queryClient}> <Todos /> </QueryClientProvider> ) } // 제로초님 강의 function ReactQueryProvider({children} : Props) { const [client] = useState( new QueryClient({ defaultOptions: { queries: { refetchOnWindowFocus: false, retry: false, } } } ) ) return <QueryClientProvider client={queryClient}></QueryClientProvider> }
크롬 개발자 도구에서 페이로드 확인을 하면 fetchBoards가 두번 요청을 합니다. 시작점을 확인을 해보면 createUploadLink.js에서 빈 값으로 요청을 하고 두 번째 요청에서는 제대로 index.tsx에서 값을 넣고 refetch를 진행을 합니다. fetchBoards가 1,3번 이고 fetchBoardsCount가 2번 입니다. 사용하는데 있어 아무런 문제 없이 사용이 가능한데 왜 이런 현상이 있는지 해결을 하고 싶습니다. 첫 마운트가 되거나 API요청을 하면 불필요한 fetchBoards, fetchBoardsCount가 createUploadLink.js에서 요청이 가는데 ApolloClient Setting 부분에서 요청이 가는 걸 확인 했습니다. const uploadLink = createUploadLink({ uri: "http://backend-practice.codebootcamp.co.kr/graphql", }); const client = new ApolloClient({ link: ApolloLink.from([uploadLink]), cache: new InMemoryCache(), }); refetch하는 전체 코드입니다. // test - refetch 문제 export default function Hom(): JSX.Element { const { data, refetch } = useQueryFetchBoards(); const { data: dataBoardsCount, refetch: refetchBoardsCount } = useQueryFetchBoardsCount(); const router = useRouter(); const render = useRef(false); useEffect(() => { // 첫 마운트 실행 막음 if (!render.current) { render.current = true; console.log("처음 실행됨"); return; } const search = String(router.query.search); const page = Number(router.query.page) || 1; if (search === "undefined") { void refetch({ page }); console.log("검색X"); } else { void refetch({ page, search }); void refetchBoardsCount({ search }); console.log("검색O"); } console.log("Hom Search: ", search); }, [router.query]); return ( <> <SearchBar /> {data?.fetchBoards.map((el, index) => ( <div key={index}>{el.title}</div> ))} <Pagination count={dataBoardsCount?.fetchBoardsCount} /> </> ); } 여기서 <SearchBar /> , <Pagination />는 router.push에서 query로 ?search= , ?page= 쿼리스트링 만드는 역할만 하고 있고 전체 부모 컴포넌트에서 useEffetch로 refetch하고 있습니다. "next": "13", "react": "^18.2.0", "apollo-upload-client": "^17.0.0", 입니다.
redirect는 try/catch문 안에 있으면 안돼서 그 위해 shouldRedirect의 값으로 조건문을 만들어 if문 안에서만 redirect하게 하셨는데, 이후에 catch문에서 return을 넣어주시더라고요. 그러면 shouldRedirect라는 변수를 쓰지 않아도 어차피 catch문이 실행된 경우에는 return 되니까 redirect를 아래에 그냥 배치해도 상관없지 않나 질문드립니다.