1. Player.css
*{
padding: 0;
margin: 0;
}
h1{
font-size: 5rem;
margin: 5% 0;
}
.main-container{
display: flex;
flex-direction: column;
align-items: center;
}
.main-container>a{
font-size: 1.5em;
font-weight: bold;
text-decoration: none;
color: black;
background-color: lightgray;
padding: 20px 30px;
border-radius: 20px;
}
.list-container{
display: flex;
flex-direction: column;
align-items: center;
}
.list-item{
display: flex;
flex-wrap: wrap;
justify-content: space-evenly;
cursor: pointer;
}
.item-container{
display: flex;
flex-direction: column;
align-items: center;
background: linear-gradient(320deg, blue , red);
color: white;
font-size: 1.2rem;
font-weight: bold;
width: 27.5%;
padding: 2%;
margin: 0.5%;
}
img{
width: 100%;
margin-bottom: 5%;
/* border-radius: 50%; */
}
table{
text-align: center;
width: 100%;
}
td{
background-color: rgba(255, 255, 255, 0.5);
color: black;
padding: 2.5% 0;
}
tr>td:nth-child(1){
width: 30%;
}
tr>td:nth-child(2){
width: 70%;
}
2. Player.jsx
import React from 'react'
import { useState } from 'react';
import { Routes, Route } from 'react-router-dom';
import Main from './components/Main';
import List from './components/List';
import Detail from './components/Detail';
import './player.css'
const Player = () => {
/**
* componet 생성 및 리우팅 설정
* - 메인페이지:Main.jsx => /
* 리수트페이지: List.jsx -> /list
* 상세페이지: Detail.jsx -> /detail
*
*/
const [list, setList]= useState([]);
return (
<div className='container'>
<Routes>
<Route path='/' element={<Main/>}></Route>
<Route path ='/list' element = {<List list ={list} setList={setList}/>}/>
<Route path ='/detail/:num' element = {<Detail list ={list}/>}/>
</Routes>
</div>
);
}
export default Player
3. index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
//import App from './App';
import App from './Player.jsx'
import reportWebVitals from '../../project06/src/reportWebVitals';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<BrowserRouter>
<App />
</BrowserRouter>
);
reportWebVitals();
// If you want to start measuring performance in your app, pass a function
// to log results (for example: reportWebVitals(console.log))
// or send to an analytics endpoint. Learn more: https://bit.ly/CRA-vitals
4. Folder public → Player.json
{
"list" : [
{
"name" : "조규성",
"position" : "FW",
"age" : 1998,
"height" : 189,
"weight" : 82,
"team" : "FC 미트윌란",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207345228338.jpg"
}, {
"name" : "나상호",
"position" : "MF",
"age" : 1996,
"height" : 173,
"weight" : 70,
"team" : "FC서울",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207313338443.jpg"
} , {
"name" : "손흥민",
"position" : "MF",
"age" : 1992,
"height" : 183,
"weight" : 78,
"team" : "토트넘",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207324860557.jpg"
} , {
"name" : "황인범",
"position" : "MF",
"age" : 1996,
"height" : 177,
"weight" : 70,
"team" : "올림피아코스",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207341162100.jpg"
} , {
"name" : "설영우",
"position" : "DF",
"age" : 1998,
"height" : 180,
"weight" : 72,
"team" : "울산현대",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2023&name=%25EC%2582%25AC%25EC%25A7%2584_2023032713492058375.jpg"
} , {
"name" : "이기제",
"position" : "DF",
"age" : 1991,
"height" : 176,
"weight" : 68,
"team" : "수원삼성",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2023&name=%25EC%2582%25AC%25EC%25A7%2584_202303211104076484.jpg"
} , {
"name" : "안현범",
"position" : "MF",
"age" : 1994,
"height" : 178,
"weight" : 72,
"team" : "제주유나이티드",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2023&name=%25EC%2582%25AC%25EC%25A7%2584_2023061611424516588.jpg"
} , {
"name" : "이강인",
"position" : "MF",
"age" : 2001,
"height" : 174,
"weight" : 72,
"team" : "파리 생제르맹 FC",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207332743807.jpg"
} , {
"name" : "이재성",
"position" : "MF",
"age" : 1992,
"height" : 180,
"weight" : 70,
"team" : "FSV 마인츠05",
"imgSrc" : "https://www.joinkfa.com/generate/CommonFile/ImageView.do?path=NAT/2022&name=%25EC%2582%25AC%25EC%25A7%2584_2022092207333993248.jpg"
}
]
}
5. Src → Folder components
Main.jsx
import React from 'react'
import {Link} from 'react-router-dom'
const Main = () => {
return (
<div className='main-container'>
<img src = "https://img.kfa.or.kr/main_banner/169743771453908.jpg" alt = "" width = '100%'/>
<Link to = '/list'>Player List</Link>
</div>
)
}
export default Main
List.jsx
import React, { useEffect } from 'react'
import Item from './Item'
import axios from 'axios'
const List = ({list,setList}) => {
useEffect(()=>{
axios
.get('http://localhost:3000/player.json')
.then((res)=>{setList(res.data.list)})
},[])
console.log(list);
return (
<div className='list-container'>
<h1></h1>
<div className='list-item'>
{list.map((item,index)=>
<Item key = {index} item ={item} index = {index}/>
)}
</div>
</div>
)
}
export default List
Item.jsx
import React from 'react'
import { useNavigate } from 'react-router-dom';
const Item = ({item,index}) => {
const nav = useNavigate();
return (
<div className='item-container' onClick={()=>{nav(`/detail/${index}`)}}>
<img src = {item.imgSrc} alt = "" width = "100px"/>
<table>
<tbody>
<tr>
<td>Name</td>
<td>{item.name}</td>
</tr>
<tr>
<td>position</td>
<td>{item.position}</td>
</tr>
<tr>
<td>age</td>
<td>{item.age}년생 ({2023-item.age} years old)</td>
</tr>
<tr>
<td>height, weight</td>
<td>{item.height}cm, {item.weight}kg </td>
</tr>
<tr>
<td>team</td>
<td>{item.team}</td>
</tr>
</tbody>
</table>
</div>
)
}
export default Item
Detail.jsx
import React from 'react'
import { useParams, Link } from 'react-router-dom'
const Detail = ({list}) => {
let {num} = useParams();
return (
<div className='item-container'>
<div className='img'>
<img src = {list[num].imgSrc} alt = "" width ="100px"></img>
</div>
<div className='detail-text'></div>
<table>
<tbody>
<tr>
<td>Name</td>
<td>{list[num].name}</td>
</tr>
<tr>
<td>position</td>
<td>{list[num].position}</td>
</tr>
<tr>
<td>age</td>
<td>{list[num].age}년생 ({2023-list[num].age} years old)</td>
</tr>
<tr>
<td>height, weight</td>
<td>{list[num].height}cm, {list[num].weight}kg </td>
</tr>
<tr>
<td>team</td>
<td>{list[num].team}</td>
</tr>
</tbody>
</table>
<p>
<Link to ='/list'>목록으로 돌아가기</Link>
</p>
</div>
)
}
export default Detail