나 이정민
4일차 포켓몬은괴물이다프로젝트 본문
<button onClick={() => navigate("/detail")}>디테일 카드로 이동</button>
<Link to={"/detail"}>ㅇ</Link>
트러블슈팅-
useNavigate( ) 훅 사용하기
react-router-dom 으로 페이지 이동을해야한다
지금 구현할 목표는 dex페이지(도감페이지)에서 각각의 카드를 누를때마다 detail페이지(상세페이지)로 이동하게하는게 목적이다. Link와 location 그리고 BrowerRouer방법은 절대 아닌것같았다. Link로할수도있나?싶어서 css초기화도 했으니 되려나싶었는데 밑에언더라인이 생기는걸보고 이방법이아니구나 싶었다. 그래서 useNavigate를 이용해서 버튼을 만들었다 온클릭해서 콜백함수안에 return 으로 navigate( ) 안에 경로를 넣는방법이다 그리고 임포트까지.
그런데 버튼으로 했더니 내가만들어놓은 카드css가 망가졌다 그래도 해야하나싶었다 . 싹다갈아엎어야하나 생각하니 힘이빠져서 gpt에 쳐봤는데 어우 다행이였다. button 뿐만이 아니라 다른 태그 대부분이 onclick이 가능한것이다. 이런행운이. 너무 기뻤다. 바로써봤다. 되는거다 너무신기신기. 그런데 예상한 오류가 발생했다. 추가버튼이다. filter를 사용해야하나 if문을 써야하나? 매우 심각해졌다. 하지만 배열이 아니고, js문법 어떻게 사용했더라 싶어서 gpt에 검색했더니 이게왠걸 event 로 부모태그로부터 온이벤트 방지해주는 이벤트방법이 있는것이다. e.stopPropagation( ); 와 감사했다. 매우기뻤다. 추가로직에 온클릭안에 바로 이벤트넣어서 적용해봤다. 와 성공! 예에에에 좋은시작이다.ㅋㅋㅋ
querystring으로 가져오기! 리스트를 map 해줄때마다 useNavigate를 이용해서 경로에 포켓몬.id 를 넣어줘서 각카드의 추가부분을제외한 모든 부분을클릭할때 디테일페이지로넘어가게되는데 그부분을 누를때 그 카드의포켓몬의 id가
나올수있게해준다.그래서 카드를 눌러서 보면 페이지이동과함께 path부분이 누른포켓몬의 id로 바뀌는것을 볼수가있다. 그리고나서 querystring으로 가져올수있는 useLocation을이용할것이다 일단
{pokemons.map((pokemon) => {
return (
<MainBox1
onClick={() => {
navigate(`/detail?id=${pokemon.id}`);
}}
key={pokemon.id}
>
<PokemonCard CreatedPokemon={CreatedPokemon} pokemon={pokemon} />
</MainBox1>
먼저 URL 을 가져오는 기본구조에대해 JS방식부터 하나씩보았다. 그랬더니 생성자함수가 new가 나왔다. 자세히 다시 보니 예전에 봤을땐 전혀이해안되던것들이 이해가되서 하나씩 읽어보게됐다. 그렇게 class 문법까지 한번 보게됐다.
그리고 react querystring에대해 한번 읽어본후 에 로직을 봤다. 나의단점인 ~구현하라는 문장을 보고 이해하는게 제일 어려웠다. 컴포넌트를 만들라고해서 만들었는데 부모컴포넌트 와 자식컴포넌트가 당연하게도 웹페이지 를담당하는 최상위홈페이지가 부모가 될텐데 문제만 보면 자꾸 이걸 이해를못하고 gpt와 하나씩 보며 다완성했을때 이해하게된다. ㅠㅠ 그리고 끝엔 항상 다음번엔 바로이해할수있을거같다라는 마음이든다. 자식컴포넌트에서 로직을 다만들어서 부모로옮겨주고 다시 자식으로props를 해준다든가 혹은 부모에서 다만들때 이게부모가맞는지 자식인건지 헷갈려하며 만드는 의미이다.
우선 useLocation을 사용한다. navigate와 같이 함수내부최상위에 작성해준다 const location = useLocation( );
여기에 location 을 콘솔로 찍어보면
hash: ""
key: "vda"
pathname: "/works"
search: ""
state: null
이러한 객체를 가지고있고 키와 값형태로되어있는데 Object 객체형태이다
url의 접근이가능해진것이다. 그리고나서 location.search를 해준다 쿼리스트링부분이다. 그리고 JS문법처럼 new 생성자함수 그리고 쿼리스트링을 쉽게다룰수있게해주는 new URLSearchPrams( ) 를작성해준다
그리고 변수로 두고 const searchParams = new URLSearchParams(location.search);
serachParams에서 id를 가지고와야한다. 가지고올때는 get을사용해야하고 . 으로 접근해서 id 를 가지고온다 객체타입에 접근할때 쓰는 방법처럼이다.
searchParams.get("id") 이런식으로 가져온다.
id는 문자열타입으로 값이 들어가있다. 그렇기에 넘버타입으로 만들어주는데 parseInt 와 Number가 있는데 나는 Number가 보기쉬워서 이걸 사용했다.
const pokemonId = Number(searchParams.get("id")); 이렇게할수있다. 그러면이제 url로 선택된 카드의 id가 나올수있게된다.
그럼 url로선택된 카드ID와 전체포켓몬리스트에 있는 ID랑 일치하는것을 return해주는것을 만든다 find를 사용할것이고, 천제포켓몬리스트를 임포트해서 가져와서 find배열 메서드를 사용해준다
const pokemon = MOCK_DATA.find((poke) => {
return poke.id === pokemonId;
}); 그리고나서 pokemon을 이용하여 return 값으로 객체 접근 방법으로 로직해준다
return (
<div>
<h2>{pokemon.korean_name}</h2>
<img src={pokemon.img_url} alt={pokemon.korean_name} />
<p>{pokemon.types}</p>
<p>{pokemon.description}</p>
</div>
);
img = src에서 " " 은 지워준다 { } js문법을 사용할것이기에 중괄호만 작성해준다. 그리고 밑에 return 부분만 컴포넌트로 따로분리해서 넣어둔다. 그렇게되면 " PokemonDetail 컴포넌트를 생성하여, queryString으로 전달받은 포켓몬 ID를 통해 상세 정보를 표시합니다 " 여기 에서 return 부분은 PokemonDetail 컴포넌트로 분리할수있고 ueryString으로 전달받은 포켓몬 ID를 통해 상세 정보를 표시를 부모인 메인컴포넌트로 둘수있게된다.
📌 정리 (React에서 쿼리 스트링 다루기)
기능 코드
쿼리 읽기 useLocation(), new URLSearchParams(location.search)
쿼리 추가 useNavigate(), navigate("/products?category=pokemon")
쿼리 변경 params.set("category", "pokemon") + navigate()
쿼리 삭제 params.delete("category") + navigate()
react-router-dom 에대하여,,,
react-router-dom 기본 로직이다 ( 변경전 )
import { BrowserRouter, Route ,Routes } from "react-router-dom";
import Home from "../pages/Home"
const Router = ( ) => {
return (
<BrowserRouter>
<Layout>
<Routes>
<Route path='/' element={<Home />} />
</Routes>
</Layout>
</BrowserRouter>
)
}
export default Router;
모든 페이지의 공통된 푸터와 헤더를 적용해주고싶을때에는! Routes와 BrowserRouter사이에 자식컴포넌트를 넣어주고 children으로 props를 전해주면 사용가능하다! ( 변경후 )
function Layout ( { children } ) {
return (
<div>
<Header/>
<div>{children } </div>
<Footer/>
</div>
);
};
다이나믹 라우트에 대하여!
URL path 의 유동적인 값을넣어 특정페이지로이동하게끔하는 구현방법이다.
<Route path="/Works/:id" element={<Works />} />
<BrowserRouter>
<Layout>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/About" element={<About />} />
<Route path="/Contact" element={<Contact />} />
<Route path="/Works" element={<Works />} />
</Routes>
</Layout>
</BrowserRouter>
PokemonDetail 컴포넌트를 생성하여, queryString으로 전달받은 포켓몬 ID를 통해 상세 정보를 표시합니다.
PokemonDetail 가 포켓몬ID를받아서 상세정보표시하는거고
누구로부터 전달받는지
works에 정보가있고 멥으로 뿌려주고
<div key work.id>
<div>할일 : { work.id} </div>
<Link to={`/works/${work.id } ` } >
<span>Go to : { work.todo} </span>
</Link>
<div>
const MOCK_DATA = ()=>{
}
import { useLocation } from " react-router-dom";
const Works = ( ) => {
const location = useLocation( );
console.log( location) ; 아래에 콘솔결과적어둠!
return (
<div>현재 페이지: { location.pathname.slice(1)</div>
)
}
-> location // Object 객체형태이고
hash: ""
key: "vda"
pathname: "/works"
search: ""
state: null
이러한 키 벨류 형식으로 된 객체를 가지고있다는것을알수있다!!!
Error 처리방법-
만약 Vite가 없다면, node_modules가 손상된 것이므로 삭제 후 다시 설치합니다:
rm -rf node_modules yarn.lock
yarn install
yarn dev
parseInt() 메서드란?
parseInt()는 문자열을 정수로 변환하는 함수이다
console.log(parseInt("42")); // 42 (문자열 "42"를 숫자 42로 변환)
console.log(parseInt("10px")); // 10 (앞에 있는 숫자만 변환)
console.log(parseInt("abc")); // NaN (숫자가 없으므로 변환 실패)
parseInt(값, 10)에서 10의 의미
parseInt()의 두 번째 인자는 **기수(radix)**라고 해요.
기수는 어떤 진법으로 변환할 것인지를 나타내요.
parseInt("1010", 2); // 2진수 -> 10진수 변환: 10
parseInt("1010", 10); // 10진수 그대로 변환: 1010
parseInt("1010", 16); // 16진수 -> 10진수 변환: 4112
parseInt(searchParams.get("id"), 10)의 의미
const searchParams = new URLSearchParams("?id=5");
const pokemonId = parseInt(searchParams.get("id"), 10);
console.log(pokemonId); // 5 (문자열을 숫자로 변환)
- searchParams.get("id") → "5" (문자열)
- parseInt("5", 10) → 5 (숫자로 변환)
즉, ?id=5처럼 URL에서 가져온 문자열 데이터를 숫자로 변환하는 역할을 한다.
1️⃣ URL 객체란?
JavaScript에서 new URL()을 사용하면 URL을 쉽게 다룰 수 있는 객체를 만들 수 있습니다.
const url = new URL("https://example.com/products?category=pokemon&type=fire");
console.log(url);
✅ 위 코드를 실행하면 url 객체가 다음과 같은 속성들을 가지게 됩니다.
속성설명값
url.href | 전체 URL | "https://example.com/products?category=pokemon&type=fire" |
url.protocol | 프로토콜 | "https:" |
url.host | 도메인 + 포트 | "example.com" |
url.hostname | 도메인 | "example.com" |
url.pathname | 경로(path) | "/products" |
url.search | 쿼리 스트링(검색 부분) | "?category=pokemon&type=fire" |
url.searchParams | 쿼리 스트링을 객체처럼 다룰 수 있는 URLSearchParams | URLSearchParams { "category" → "pokemon", "type" → "fire" } |
2️⃣ url.search가 필요한 이유
url.search는 "?"부터 시작하는 쿼리 스트링 부분만 포함하는 속성입니다.
즉, "?category=pokemon&type=fire" 이 값이 들어갑니다.
❌ 잘못된 예시 (url.products는 존재하지 않음!)
console.log(url.products); // ❌ undefined (이런 속성 없음)
🔴 products는 URL 속성이 아니라 pathname(경로)의 일부이므로 존재하지 않음!
✅ 올바른 예시 (url.search 사용)
console.log(url.search); // ✅ "?category=pokemon&type=fire"
3️⃣ new URLSearchParams(url.search)는 무엇을 하는가?
URLSearchParams는 쿼리 스트링을 쉽게 다룰 수 있도록 도와주는 객체입니다.
const params = new URLSearchParams(url.search);
console.log(params.get("category")); // "pokemon"
console.log(params.get("type")); // "fire"
✅ params.get("category") → "pokemon" 값 가져옴
✅ params.get("type") → "fire" 값 가져옴
✅ 1. new 키워드는 언제 사용될까?
new 키워드는 JavaScript에서 생성자 함수(Constructor Function)를 호출할 때 사용됩니다.
이것은 새로운 객체를 만들고 초기화하는 역할을 합니다.
✅ 2. URLSearchParams도 생성자 함수!
URLSearchParams는 쿼리 스트링을 다루기 위한 JavaScript의 내장 객체입니다.
즉, 새로운 URLSearchParams 인스턴스를 만들려면 new를 붙여야 합니다!
📌 URLSearchParams 사용 예제
const params = new URLSearchParams("?category=pokemon&type=fire");
console.log(params.get("category")); // "pokemon"
console.log(params.get("type")); // "fire"
✅ new URLSearchParams()를 사용하면 쿼리 스트링을 객체처럼 다룰 수 있음!
URLSearchParams는 생성자 함수이므로 new를 붙여야 함!
✔ new는 새로운 객체를 생성할 때 사용됨!
쿼리스트링
url 에서 ? 는 쿼리스트링을 시작하는 알림이고 그뒤에 key와 value형식으로 작성된다.
서버는 key 라는 키를 받아 value라는 값을 제공해준다.
q라는키와 포켓몬이라는값이라면
search?q=포켓몬 이렇게작성할수있다.
2개이상의 키와벨류를 더하려면 중간에 & 를 붙여주면된다.
JS에서 쿼리스트링 만드는 기본구조방식-
const params = new URLSearchParams({ category: "pokemon", type: "fire" });
console.log(params.toString()); // "category=pokemon&type=fire"
const url = `https://example.com/products?${params.toString()}`;
console.log(url); // "https://example.com/products?category=pokemon&type=fire"
쿼리스트링 읽는 기본구조 방식-
const url = new URL("https://example.com/products?category=pokemon&type=fire");
const params = new URLSearchParams(url.search);
// . get 을사용하고 키값을 가져온다.
console.log(params.get("category")); // "pokemon"
console.log(params.get("type")); // "fire
생성자 함수는 새로운 객체를 만들고 초기화하는 역할
생성자 함수의 동작 원리
// ✅ 생성자 함수
function Pokemon(name, type) {
this.name = name;
this.type = type;
this.sayHi = function () {
console.log(`안녕! 나는 ${this.name}야!`);
};
}
// new 키워드로 새로운 객체 생성
const pikachu = new Pokemon("피카츄", "전기");
const charmander = new Pokemon("파이리", "불");
console.log(pikachu.name); // "피카츄"
pikachu.sayHi(); // "안녕! 나는 피카츄야!"
console.log(charmander.name); // "파이리"
charmander.sayHi(); // "안녕! 나는 파이리야!"
✅ new 키워드를 사용하면 자동으로 새로운 객체가 생성되고 초기화됨!
✅ this.name, this.type → 각각 새로 생성된 객체(pikachu, charmander)를 가리킴
✅ new 없이 호출하면 this가 undefined가 될 수도 있음!
-완벽이해됌 아래보면-
const bulbasaur = new Pokemon("이상해씨", "풀");
1.새로운 빈 객체 { } 생성됨
2.this가 새로 생성된 객체를 가리킴
3.this.name = "이상해씨" 실행 → { name: "이상해씨" }
4.this.type = "풀" 실행 → { name: "이상해씨", type: "풀" }
5.return this가 자동으로 실행됨!
prototype을 사용한 생성자 함수 최적화
위의 코드에서 sayHi 메서드는 객체가 생성될 때마다 새롭게 생성됨 → 메모리 낭비
이를 방지하려면 prototype을 활용하면 됨!
// ✅ prototype을 사용한 최적화
function Pokemon(name, type) {
this.name = name;
this.type = type;
}
// prototype에 메서드 추가 (모든 객체가 공유)
Pokemon.prototype.sayHi = function () {
console.log(`안녕! 나는 ${this.name}야!`);
};
const squirtle = new Pokemon("꼬부기", "물");
const jigglypuff = new Pokemon("푸린", "노멀");
squirtle.sayHi(); // "안녕! 나는 꼬부기야!"
jigglypuff.sayHi(); // "안녕! 나는 푸린이야!"
class 문법을 사용한 생성자 함수 (ES6)
// ✅ class 문법 사용
// ✅ class 문법 사용
class Pokemon {
constructor(name, type) {
this.name = name;
this.type = type;
}
sayHi() {
console.log(`안녕! 나는 ${this.name}야!`);
}
}
const pikachu = new Pokemon("피카츄", "전기");
pikachu.sayHi(); // "안녕! 나는 피카츄야!"
return을 사용하지 않아도 자동으로 this가 반환됨
function Digimon(name, type) {
this.name = name;
this.type = type;
return { name: "디지몬", type: "디지털" }; // 다른 객체 반환하면 this가 무시됨!
}
const agumon = new Digimon("아구몬", "불꽃");
console.log(agumon.name); // "디지몬" (this가 아닌 객체가 반환됨!)
생성자 함수에서 다른 객체를 return하면 this가 무시됨!
💡 해결법: return을 사용하지 말고 this를 자동 반환하도록 놔두기!
🎯 정리: 생성자 함수란?
특징설명
생성 목적 | 새로운 객체를 만들고 초기화 |
호출 방식 | 반드시 new 키워드와 함께 사용 |
this | 생성된 객체를 가리킴 |
return 필요 여부 | 필요 없음 (자동으로 this가 반환됨) |
prototype 사용 | 여러 객체가 메서드를 공유하도록 최적화 가능 |
ES6 문법 | class를 사용하면 더 간결하게 작성 가능 |
✅ 생성자 함수는 new와 함께 사용해야 하며, 객체 초기화를 쉽게 해주는 역할을 한다!
✅ prototype을 활용하면 메모리를 효율적으로 관리할 수 있다!
✅ class 문법을 사용하면 더 간결하게 작성할 수 있다!
URLSearchParams는 생성자 함수이므로 new를 붙여야 함!
✔ new는 새로운 객체를 생성할 때 사용됨!
📌 정리 (React에서 쿼리 스트링 다루기)
기능코드
쿼리 읽기 | useLocation(), new URLSearchParams(location.search) |
쿼리 추가 | useNavigate(), navigate("/products?category=pokemon") |
쿼리 변경 | params.set("category", "pokemon") + navigate() |
쿼리 삭제 | params.delete("category") + navigate() |
이제 React에서 쿼리 스트링을 자유롭게 다룰 수 있어요! 🎉