개발환경설치
- node.js
npx create-react-app <프로젝트명> [--template typescript]
cd <프로젝트명>
npm install axios --save
npm install react-router-dom --save
npm run start // 3000 포트로 실행
npm run build // build 폴더 내 생성된 파일들을 웹서버가 바라보는 폴더에 복사 붙여넣기
App.js
import './App.css';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import ItemList from './ItemList';
import ItemDetail from './ItemDetail';
function App() {
return (
<div align='center'>
<BrowserRouter>
<Routes>
<Route path='/' element={<ItemList/>} />
{
/* exact의 경우, 해당 경로와 확실하게 일치하여야 렌더링 수행 */
}
<Route path='/detail/:index' element={<ItemDetail/>} />
{
/*
<Route path="/error" element={<ErrorPage />} />
<Route path="/*" element={<Navigate to="/error" />} />
*/
}
</Routes>
</BrowserRouter>
</div>
);
}
export default App;
- react-router-dom v6 이전
더보기
import './App.css';
import { BrowserRouter as Router, Route, Switch } from 'react-router-dom';
import ItemList from './ItemList';
import ItemDetail from './ItemDetail';
function App() {
return (
<div align='center'>
<Router>
<Switch>
<Route path='/' component={ItemList} />
{/* exact의 경우, 해당 경로와 확실하게 일치하여야 렌더링 수행 */}
<Route path='/detail/:index' component={ItemDetail} exact />
</Switch>
</Router>
</div>
);
}
export default App;
ItemList.js
import axios from 'axios';
import React, { useState, useEffect, useCallback } from 'react';
import ItemListItem from './ItemListItem';
import { useNavigate } from 'react-router-dom';
const ItemList = () => {
// 상단 상태값
const [currentTime, setCurrentTime] = useState('');
// 상단 Select 상태값
const [chartType, setChartType] = useState('domestic');
// 메인 리스트 상태값
const [chartList, setChartList] = useState([]);
// const [loading, setLoading] = useState(false);
const navigate = useNavigate();
// API 목록 조회 (쿼리에 따른)
const loadItemList = (chartTypeStr) => {
// setLoading(true)
axios.get('http://localhost:3300/v1/chart/' + chartTypeStr)
.then((response) => {
setChartList(response.data.chartList);
// setLoading(false)
})
.catch((error) => {
console.log(error);
// setLoading(false)
});
};
// 이벤트 처리 함수
const onSelectItem = (chartTypeStr) => {
setChartType(chartTypeStr);
loadItemList(chartTypeStr);
};
// 이벤트 처리 함수
const onClickTitle = (id) => {
// window.location.assign('/detail/' + id);
navigate('/detail/' + id)
};
// renderList
const drawList = useCallback(() => {
const ItemList = chartList.map((item) => {
return (<ItemListItem key={item.id} item={item} onClickCallback={onClickTitle}></ItemListItem>);
});
return ItemList;
}, [chartList]);
// onCreate() : 초기화 작업
useEffect(() => {
let now = new Date();
let hour = now.getHours() < 10 ? '0' + now.getHours() : now.getHours();
let min = now.getMinutes() < 10 ? '0' + now.getMinutes() : now.getMinutes();
let curremtTimeStr = now.getFullYear() + '년 ' + (now.getMonth() + 1) + '월 ' + now.getDate() + '일 ' + hour + ':' + min;
setCurrentTime(curremtTimeStr);
setChartType('domestic');
// 초기 데이터 로드
loadItemList('domestic');
}, []);
return (
<>
{/* {loading && <div> loading... </div>} */}
<table width='600px' border='0px'>
<tr><td align='center' colspan='4'><h1>음악 차트</h1></td></tr>
<tr><td align='center' colspan='4'>{currentTime}</td></tr>
<tr>
<td colspan='4'>
<button style={chartType === 'domestic' ? { fontWeight: 'bold', color: 'red', cursor: 'pointer' } : { cursor: 'pointer' }} onClick={() => onSelectItem('domestic')}> 국내 </button>
<button style={chartType === 'overseas' ? { fontWeight: 'bold', color: 'red', cursor: 'pointer' } : { cursor: 'pointer' }} onClick={() => onSelectItem('overseas')}> 해외 </button><br /><br />
</td>
</tr>
{drawList()}
</table>
</>
);
}
export default ItemList;
ItemListItem.js
import React, { useState, useEffect } from 'react';
import { Link } from 'react-router-dom';
import {useNavigate} from 'react-router-dom'
// props
// - item
const ItemListItem = (props) => {
const [title, setTitle] = useState(props.item.title);
const [singer, setSinger] = useState(props.item.singer);
const [url, setUrl] = useState('/detail/' + props.item.id);
const navigate = useNavigate();
const onClickTitle = () => {
props.onClickCallback(props.item.id);
}
// useEffect(() => {
// if (props.item.title.length > 18) {
// setTitle(props.item.title.substring(0, 18) + '...');
// }
// if (props.item.singer.length > 15) {
// setSinger(props.item.singer.substring(0, 15) + '...');
// }
// }, [title, singer]);
return (
<tr>
<td width='20px'>{props.item.rank}</td>
<td width='50px'>
<img src={props.item.imageUrl} />
</td>
<td width='250px'>
<Link to={url}>
<div style={{width: '70px',
padding:'0 5px',
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap'}}>
{title}
</div>
</Link>
</td>
<td width='180px' align='right'>{singer}</td>
</tr>
);
}
export default ItemListItem;
ItemDetail.js
import React, { useState, useEffect } from 'react';
import axios from 'axios';
import { useParams } from 'react-router-dom';
import { useNavigate } from 'react-router-dom';
const ItemDetail = ({ match }) => {
// const index = match.params.index
const { index } = useParams();
const [id, setId] = useState(index);
const [detail, setDetail] = useState(null);
const navigate = useNavigate();
// onCreate(): 초기화
useEffect(() => {
if (id > 0) {
axios.get('http://localhost:3300/v1/chart/detail/' + id)
.then((response) => {
if (response.data.chart.title === undefined) {
alert('곡 정보가 존재하지 않습니다.');
// window.location.assign('/');
navigate('/');
}
else {
setDetail(response.data.chart);
}
}).catch((error) => {
console.log(error);
});
}
}, [id]);
return (
<div>
<div align='center'>
{
detail &&
<div>
<div><h2></h2></div>
<table border='0'>
<tr>
<td colSpan='2'>
{/* 뒤로가기 구현 */}
<button style={{ cursor: 'pointer' }} onClick={() =>
// window.location.assign('/')
navigate('/')
}>←</button>
</td>
</tr>
<tr>
<td colSpan='2' align='center'>
<h1>{detail.title}</h1>
<h3>{detail.singer}</h3>
<br></br>
</td>
</tr>
<tr>
<td width='100px' align='left'><h4>작사</h4></td>
<td width='300px' align='left'>{detail.lyricist}</td>
</tr>
<tr>
<td width='100px' align='left'><h4>작곡</h4></td>
<td width='300px' align='left'>{detail.melodizer}</td>
</tr>
<tr>
<td width='100px' align='left'><h4>장르</h4></td>
<td width='300px' align='left'>{detail.genre}</td>
</tr>
</table>
</div>
}
</div>
</div >
);
}
export default ItemDetail;
# 참고
- 간단 스크롤링 구현하기 : [React] Infinite Scroll 구현하기. React로 infinite scroll을 구현해보자 | by Diana Lee | Medium
- 간단 페이징 구현하기 : [React] 리액트 페이지네이션(pagination) 구현하기 (2) | ChanBLOG (chanhuiseok.github.io)
'[DEV] App Dev ∕ Web Front > Framework ∕ React' 카테고리의 다른 글
[React] rc-tree 라이브러리를 통한 treeview 공통 컴포넌트 만들기 (0) | 2023.05.09 |
---|---|
[React] 개발 참고자료 목록 (0) | 2022.10.23 |
[React] 개발 참고자료 목록 (0) | 2022.06.08 |
[React] JS ES6 문법 / 함수형 프로그래밍 for React (0) | 2022.05.11 |
[React] Cordova로 안드로이드, IOS 버전 만들기 (0) | 2021.07.02 |
최근댓글