
/pokemons api 구성PokemonList 컴포넌트 작성/pokemons/[id] api 구성PokemonDetail 컴포넌트 작성NextJS 를 이용해 나만의 포켓몬 도감을 만드는 과제였다. 일단 필수 구현 사항들은 거진 다 완료된 상태이지만, 아직 UI 부분을 신경쓰지 않았고 디테일하게 손 볼 부분이 많아 해당 부분을 진행해야할 것 같다.
과제의 필수 구현 사항으로, Next.js 내의 Image 태그를 사용해 이미지를 넣으려는데 계속 오류가 뜨는 문제가 있었다.
공식 문서 및 구글링을 통해, 외부에서 가져온 이미지 경로에 대해서는 next.config.js 파일에 이미지의 경로에 대한 정보를 작성해주어야한다는 점을 알게 되었다. 때문에 next.config.js 파일을 제작하고 내가 사용하는 이미지 경로에 대한 정보를 작성해주었다.
// next.config.js
module.exports = {
images: {
remotePatterns: [
{
protocol: "https",
hostname: "raw.githubusercontent.com",
port: "",
pathname: "/PokeAPI/sprites/master/sprites/pokemon/**",
},
],
},
};
문제가 해결되었다.
필수 조건 중 디테일 페이지에서는 무조건 서버 컴포넌트로 구현을 해야하는 조건이 있어, 여러가지 방법을 통해 파라미터를 가져오는 방법을 찾아보았다.
그러던 중 getServerSideProps같은 방법도 찾아 적용시켜보려 했으나 난이도가 높아 이게 맞는지 의구심이 들어 튜터님을 찾아뵀고, getServerSideProps가 아닌 더 쉬운 방법을 힌트로 알려주셨다. 아래는 그렇게 알게된 방법으로 작성한 코드이다.
const PokemonDetailPage = ({ params }: { params: { id: string } }) => {
const { id } = params;
return (
<div>
<PokemonDetail id={id} />
</div>
);
};
매개변수에 {params}만으로도 가져올 수 있다. next 14 버전부터 적용된 기능이라고 하시는데, 나는 이걸 알고나서 다시 찾아보아도 찾아지지가 않는(심지어 공식 문서에서도 못 찾겠는...) 문제가 있어서 공식 문서 보는 능력 및 구글링하는 능력을 더 길러야겠다는 생각이 들었다.
'위로', '아래로' 버튼 클릭 시, 즉각적으로 리스트의 순서가 바뀔 수 있게 해주세요.
맨 위 아이템, 맨 아래 아이템은 더 이상 위로, 아래로 가지 못하게 해주셔야 합니다!
풀이는 코드 속에 작성했다.
import { useState } from "react";
import { MOCK_DATA } from "./MOCK_DATA.js";
const ChangeListOrder = () => {
const [pokemonData, setPokemonData] = useState(MOCK_DATA);
// TODO '위로' 버튼을 눌렀을 때, 실행되는 로직을 작성합니다. 첫 번째 아이템은 위로 이동 할 수 없음을 기억해주세요!
const moveItemUp = (selectedIndex) => {
// 첫 번째 아이템일 경우 return을 통해 아무 코드도 실행할 수 없게 한다.
if (selectedIndex === 0) {
return;
}
// 선택된 아이템과 바로 전 아이템을 찾아서 새로운 배열로 만들고, 해당 배열을 reverse한다.
const filteredPokemons = pokemonData
.filter((pokemon, index) => {
return selectedIndex === index || selectedIndex - 1 === index;
})
.reverse();
// 전체 배열을 map 하여, 직전 인덱스에는 필터링한 배열의 첫번째 요소(선택된 아이템)를, 선택된 인덱스에는 두번째 요소(직전 아이템)을 넣는다.
// 해당 두 경우가 아닐 경우에는 그대로 return 한다.
// 해당 배열을 pokemonData에 적용한다.
setPokemonData(
pokemonData.map((pokemon, index) => {
if (index === selectedIndex - 1) {
return filteredPokemons[0];
} else if (index === selectedIndex) {
return filteredPokemons[1];
}
return pokemon;
})
);
};
// TODO '아래' 버튼을 눌렀을 때, 실행되는 로직을 작성합니다. 마지막 아이템은 아래로 이동 할 수 없음을 기억해주세요!
const moveItemDown = (selectedIndex) => {
// 마지막 아이템일 경우 return을 통해 아무 코드도 실행할 수 없게 한다.
if (selectedIndex === pokemonData.length - 1) {
return;
}
// 선택된 아이템과 바로 후 아이템을 찾아서 새로운 배열로 만들고, 해당 배열을 reverse한다.
const filteredPokemons = pokemonData
.filter((pokemon, index) => {
return selectedIndex === index || selectedIndex + 1 === index;
})
.reverse();
// 전체 배열을 map 하여, 선택된 인덱스에는 필터링한 배열의 첫번째 요소(직후 아이템)를, 직후 인덱스에는 두번째 요소(선택된 아이템)을 넣는다.
// 해당 두 경우가 아닐 경우에는 그대로 return 한다.
// 해당 배열을 pokemonData에 적용한다.
setPokemonData(
pokemonData.map((pokemon, index) => {
if (index === selectedIndex) {
return filteredPokemons[0];
} else if (index === selectedIndex + 1) {
return filteredPokemons[1];
}
return pokemon;
})
);
};
return (
<div className="container mx-auto">
<h2 className="w-full text-center py-10">리스트 순서 바꾸기</h2>
<div className="flex flex-col gap-2">
{/* TODO Index 도 필요하다면, 수정해주세요 */}
{pokemonData.map((pokemon, index) => (
<div
key={pokemon.id}
className="pokemon p-4 border rounded-lg flex justify-between"
>
<div>
<img
src={pokemon.sprites.front_default}
alt={pokemon.korean_name}
/>
<p>{pokemon.korean_name}</p>
<p>도감번호: {pokemon.id}</p>
</div>
<div className="flex gap-5 items-center">
{/* TODO moveItemUp 함수에 매개변수로 넣어주고 싶은게 있으시면 추가 시키셔도 됩니다. */}
<button
className="bg-brand h-10 p-2 rounded text-[#ffffff] font-bold"
onClick={() => moveItemUp(index)}
>
위로
</button>
{/* TODO moveItemDown 함수에 매개변수로 넣어주고 싶은게 있으시면 추가 시키셔도 됩니다. */}
<button
className="bg-state-warning h-10 p-2 rounded text-[#ffffff] font-bold"
onClick={() => moveItemDown(index)}
>
아래로
</button>
</div>
</div>
))}
</div>
</div>
);
};
export default ChangeListOrder;
주말 간 강의를 모두 수강했기 때문에 좀 더 빠르게 과제를 진행할 수 있었던 것 같다. 때문인지 탄력을 받아 필수 구현 사항은 거의 완성되었다. 역시 무리하지 않는 선에서는 미리미리 해둬서 나쁠 게 없다! 이 기세로 쭉쭉 진행해야겠다.
챡챡챡 잘 해내고 계시군여 솔님 ! 앞으로의 행보도 응원할게요 (˶• ﻌ •˶)