react router 사이트에서 최신 스펙에 대한 튜토리얼을 보면, framework mode, data mode, declarative mode 3가지로 나뉘어 있습니다. 여기서 이 3가지 방식은 각각의 tutorial 에서 보여주는 install하는 방법도 다르고, 그 안에서 route 생성하고 layout 만드는것도 코드 방식이 다 갈리는 것 같습니다. 제가 react router 강의를 거의 시작하지 못한 상태이고, 자세히 몰라서 확실하게 말을 할순 없지만, router 를 만드는 방식을 보면, 강좌의 버전과 지금 현재 버전은 달라도, data mode의 튜토리얼에서 설명하는 코드 방식이 강좌와 매우 비슷한것 같습니다. ex) import {createBrowserRouter, RouterProvider} from 'react-router-dom' 으로 시작하는 것이 똑같습니다. 이 3가지 모드는 뭐가 다른건가요? 강좌에서 나온 홈페이지에서도 이런 형식은 아니었던것 같은데 혼란스럽습니다. 일단 저는 npm i react-router-dom 으로 설치했고, 강좌에 나온 코드를 일단 따라가고는 있는데, 최신스펙과 차이를 어떻게 받아들여야 할지 모르겠습니다. 예를 들어, 최신 스펙에서는 설치코드 부터 'npm i react-router'로 뒤에 '-dom'이 붙지 않습니다. 그럼에도 router생성 과정에서 import {createBrowserRouter, RouterProvider} from 'react-router-dom' 과 같이 코드가 거의 똑같은데 어떻게 받아들어야 하나요? 혹시 강사님은 최신스펙의 react router를 사용하시나요? 그렇다면 강좌에 나온 코드 그대로 최신스펙에서 가져다 써도 문제가 없는지 알 수 있을까요?(경험이 있으시다면, 변경된점에 대해도 알고 계실것 같아서요)
그랩님, 강의 잘 듣고 있습니다. 다름이 아니라, 상품 상세 페이지 에러와 의문점이 있어서 어떻게 해결해야 하는지 궁금한 사항이 있어 질문 드리게 되었습니다. 일단 src/main/index.js 소스 코드를 첨부합니다. import './index.css'; import axios from "axios"; import React from 'react'; import {Link} from 'react-router-dom'; function MainPage(){ const [products, setProducts]=React.useState([]); React.useEffect( function(){ axios.get("제 mock 서버 주소 넣었습니다/products") .then(function(result){ const products=result.data.products; setProducts(products); }).catch(function(error){ console.error("에러 발생:",error); }); },[]); return ( <div> <div id="header"> <div id="header-area"> <img src="../images/icons/logo.png" /> </div> </div> <div id="body"> <div id="banner"> <img src="../images/banners/banner1.png" /> </div> <h1>판매되는 상품들</h1> <div id="product-list"> { products.map(function(product, index){ return ( <div className="product-card"> <Link className="product-link" to={`/products/${product.id}`}> <div> <img className="product-img" src={product.imageUrl} /> </div> <div className="product-contents"> <span className="product-name">{product.name} </span> <span className="product-price">{product.price}원 </span> <div className="product-seller"> <img className="product-avatar" src="../images/icons/avatar.png" /> <span>{product.seller}</span> </div> </div> </Link> </div> ); }) } </div> </div> <div id="footer"></div> </div> ); } export default MainPage; 2.src/product/index.js 소스 첨부합니다. import {useParams} from 'react-router-dom'; import axios from "axios"; import { useEffect, useState } from 'react'; function ProductPage(){ // const params=useParams(); const {id} = useParams(); const [product, setProduct] = useState(null); useEffect(function(){ axios.get('제 mock 서버 주소 넣었습니다/products/${id}' ) .then(function (result) { setProduct(result.data); // console.log(result); }).catch(function(error){ console.error(error); } ); },[]); console.log(product); // console.log(params); return <h1>상품 상세 페이지 {id} 상품</h1>; } export default ProductPage; -->여기서부터 의문점과 문제점이 발생하게 되니 읽어주시고 해결할 수 있는 방법을 알려주시면 좋겠습니다. 위 소스에서 axios.get('제 mock 서버 주소 넣었습니다/products/ ${id}') 처럼 소스를 달러 중괄호 아이디 입력하면 , 아래와 같은 첨부 사진처럼 에러 가 납니다. --> 위 에러 첨부 사진은 어떻게 해결해야 할까요? 3. 하지만, 위 소스대로 입력 안하면 axios.get('제 mock 서버 주소 넣었습니다 /products/1 ') 하면 제대로 데이터를 오류 없이 아래 첨부 사진처럼 받아 오는 것 을 알 수 있습니다. 3-1. 그랩님, 강의 소스에서 처럼 axios.get('제 mock 서버 주소 넣었습니다/products/ ${id} ')해서 하면 위 첨부 사진 처럼 에러가 나는데요, 성공적으로 오류 없이 불러오고 싶은데요 , 어떻게 해야 하나요? 단계별로 어떻게 소스를 수정해야하는지 알려주시면 좋겠습니다. 확인하시면 답변 부탁 드립니다.
73강 7분 50초 내용입니다. 투두리스트 프로젝트의 List.jsx에서 TodoItem.jsx로 prop을 넘길 때 강의에서는 todos.map((todo) => {return (<TodoItem key={todo.id} {...todo} />;} 위 처럼 작성하고 있습니다. 저는 props를 spread syntax가 아닌 객체 자체로 한 번에 전달해보려고 아래와 같이 작성했습니다. todos.map((todo) => {return <TodoItem key={todo.id} todo={todo} />;} 그런데 이렇게 작성하면 다음과 같은 에러가 발생합니다: Each child in a list should have a unique "key" prop. todos 배열의 각 요소에는 고유한 id가 있다는 것을 확인했고, 동일한 코드에서 todo={todo}를 {...todo}로 변경하면 경고 없이 정상적으로 동작합니다. 저는 단순히 {...todo}는 객체 속성을 각각 개별 props로 넘기고, {todo}는 하나의 객체로 넘기는 차이만 있다고 생각했는데, 이 두 방식의 어떤 차이로 인해 이런 경고가 발생하는지 궁금합니다.
📤 before request jwtUtil.ts:30 ✅ Response Received jwtUtil.ts:34 📦 Content-Type: application/json jwtUtil.ts:35 🧾 typeof res.data : string content-type은 json 형식으로 맞춰 주었는데 정작 데이터가 String으로 와서 list에 뿌려주지를 못하고 있습니다. Postman으로 확인했을 때는 정상적으로 JSON 데이터를 반환받는데 리액트에서 확인할려면 res.data가 "{\"dtoList\":[{\"tno\":115,\"title\":\"123zzzㅋㅋㅋㅋ\",\"content\":null,\"complete\":false,\"dueDate\":\"2025-08-07\",\"writer\":\"123\"} 위와 같이 스트링 형식으로 변환되어서 들어와서 오류가 생깁니다. 어디가 문제일까요..ㅠㅠ
1. 앱 라우터에서는 왜 페이지 이동 전에 프리패칭(prefetching)이 이뤄지지 않는 것처럼 보일까요? 페이지 라우터(Page Router) 방식에서는 링크가 뷰에 등장하면 해당 링크의 JS 번들이 자동으로 프리패칭되는 것으로 알고 있습니다. 그런데 앱 라우터의 동작 구조를 설명한 도식(2번 사진)에서는, 사용자가 실제로 페이지 이동을 요청한 이후에 JS 번들과 RSC Payload를 받는 것으로 표현되어 있습니다. 페이지 라이팅과 달라진 점이 RSC payload를 보내주는 것이라 하셨는데 도식에서는 언제 JS 번들을 보내주는지에 차이가 있어보여서 질문드립니다. 2. 앱라우터 방식에서 클라이언트 컴포넌트만 JS 번들에 포함된다는 설명과 관련해서, 다음 내용이 맞는지 확인 부탁드립니다. 초기 접속 시 서버에서 서버컴포넌트를 RSC 페이로드로 해석하고 완성된 HTML을 보내준다. 초기 접속 시 브라우저는 해당 페이지의 클라이언트 컴포넌트 JS Bundle만 받는다. 이후, JS Bundle과 HTML을 하이드레이션 한다. 페이지 전환 시, 새로 이동하는 페이지의 JS Bundle과 함께 서버 컴포넌트에 대한 RSC Payload도 함께 받아 브라우저에서 조합된다. 즉, 페이지 전환 전에 프리패칭이 없다. 이렇게 이해하는게 맞을까요?
지난강의에서 useImmer에서 활용한 update함수에서는 push, splice와 같은 현재의 객체를 변환시키는 api를 활용했었습니다. 그래서 immer 가 적용된 상황에서는, 현재 객체를 변환시키는 것만이 답일것이라 생각해서, 오히려 filter api를 써야 코드가 더 간단해지는 상황에서는 useState를 따로 분리해서 써야 고민하고 있었습니다. 그런데 이번 강의에서 useImmerReducer에서 활용하는 것을 보아하니, State가 아니라 Immer 이 적용된 케이스더라도, return으로 새로운 객체를 반환하거나, 직접 객체에 변화를 주거나 하는 방법이 둘다 적용이 되는것으로도 보이는것 같더라구요? case 'deleted':에서도 draft.filter에 return 이 적용되면, immerReducer라도 잘 작동하고, return을 없애고, break로 나오게 하면, 변화가 아무래도 적용이 안되더라구요(당연하겠죠... 원래 객체에 변화를 준것이 아니니) 그래서 immer나 immerReducer를 활용한다는 것은 useState을 확장시키는 느낌인건가요? 직접객체에 변화를 주는것 뿐만아니라, useState에서 했던것처럼 새로운 객체를 만들어 return하는 것 '까지' 가능한건가요? 만약 immer가 적용된 상황에서, 직접 객체를 변환하는 코드와, 새로운 객체를 만들어 return 하는 코드가 하나에 전부 적용되어 있다면 어떻게 작용하나요? 다시 말해, draft.push로 '변경사항이 immer에 반영되고', 동시에return으로 draft.filter한 값을 보내면, 어떻게 작용하며, 어떤 로직이 적용되나요? 감사합니다
expo-location 때부터 모듈을 설치를 해도 해당 모듈이 없다는 메시지가 뜹니다. eas build --platform android --profile development 명령어로 새로 빌드하면 되긴 하는데, 모듈 하나 설치할 때마다 빌드하면 5분씩 넘게 걸리는데 다른 방법이 있을까요? 아니면 제가 놓치고 있는게 있을까요?
seo 관련해서 궁금한게 있습니다. seo 최적화라는게 크롤링 봇이 서버에서 렌더링된 html을 크롤링하고 인덱싱하는걸로 알고 있습니다. 만약 서버 fetch 를 했지만 data 자체는 렌더링하지 않은 경우는 크롤링 봇이 어떻게 인식을 하는지 궁금합니다. 예를 들어 서버 fetch를 했지만 아래와 같이 서스펜스 역할하는 로직으로 인해 클라이언트 환경에서 hydrate 된 이후에 데이터가 렌더링된다면 서버에서 fetch는 이루어졌지만 렌더링된건 아니기 때문에 크롤링봇이 데이터를 인식하지 못하게 되는걸까요?? export function ConditionalClientWrapper({ children, fallback, }: ConditionalClientWrapperProps) { const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); if (!mounted) return fallback ?? null; return children; } <ConditionalClientWrapper fallback={<Loading />}> //dataList에서 서버 fetch 가 이루어집니다. <dataList /> </ConditionalClientWrapper> SEO 최적화를 위한 조건이 데이터 렌더링인지 단순 서버 fetch 만하면 되는건지 궁금합니다. 추가로 리액트 쿼리의 prefetch를 사용하면 seo 최적화를 가질 수 있는건가요?? 감사합니다!
처음에 development build로 진행해도 위와 같은 오류가 발생해서, npx rimraf node_modules , npm i , npx rimraf android 순서대로 실행한 후에 다시 npm run android 로 빌드하려고 하는데, 다음과 같은 오류가 발생합니다. C:\Users\swu\threads-clone>npm run android > threads-clone@1.0.0 android > expo run:android √ Created native directory √ Updated package.json | no changes √ Finished prebuild TypeError: Cannot read properties of undefined (reading 'android:enabled') TypeError: Cannot read properties of undefined (reading 'android:enabled') at C:\Users\swu\threads-clone\node_modules\@expo\config-plugins\src\android\Manifest.ts:219:20 at Array.filter (<anonymous>) at Object.getRunnableActivity (C:\Users\swu\threads-clone\node_modules\@expo\config-plugins\src\android\Manifest.ts:218:90) at getMainActivityAsync (C:\Users\swu\threads-clone\node_modules\@expo\cli\src\run\android\resolveLaunchProps.ts:36:49) at resolveLaunchPropsAsync (C:\Users\swu\threads-clone\node_modules\@expo\cli\src\run\android\resolveLaunchProps.ts:51:24) at resolveOptionsAsync (C:\Users\swu\threads-clone\node_modules\@expo\cli\src\run\android\resolveOptions.ts:51:9) at runAndroidAsync (C:\Users\swu\threads-clone\node_modules\@expo\cli\src\run\android\runAndroidAsync.ts:30:17)
배포를 준비하고 있는데 개발/로컬 환경에서는 문제가 없이 잘 되다가 상용 환경에 배포를 하려고하니 에러가 발생하고 있습니다. 빌드는 에러 없이 잘 되었는데 pm2 start를 하니 [TypeError: Cannot read properties of undefined (reading 'filter') 타입에러가 갑자기 나타나버렸습니다. 우선 filter 사용하는 부분에 대한 예외처리들을 넣어주었는데 동일한 에러가 계속 발생하고 있습니다. 어떠한 경우에 이런 에러가 발생하는 것일까요?