Stack/React
[React] booklist
7ingout
2022. 6. 27. 16:40
App.js
import './App.css';
import styled from 'styled-components';
import Header from './components/Header';
import Content from './components/Content';
import { BookProvider } from './context/BookContext';
const ContainerDiv = styled.div`
width: 70%;
margin: 0 auto;
text-align: center;
`;
function App() {
return (
<BookProvider>
<div className="App">
<ContainerDiv>
<Header />
<Content />
</ContainerDiv>
</div>
</BookProvider>
);
}
export default App;
Context/BookContext.js
import React,{createContext, useContext, useReducer} from 'react';
const initialLists = {
total: [
{id:1, writer:"공유",title:"나는 나로 살기로 했다.",year:"2022"},
{id:2, writer:"전지현",title:"경이로운 소문",year:"2022"},
{id:3, writer:"손예진",title:"UI/UX 디자인 이론과 실습",year:"2022"},
{id:4, writer:"현빈",title:"만들면서 배우는 제이쿼리",year:"2022"},
{id:5, writer:"공유",title:"이상한 나라의 엘리스",year:"2021"},
{id:6, writer:"신채경",title:"인어공주",year:"2021"},
{id:7, writer:"유진",title:"일러스트레이터 강의",year:"2021"},
{id:8, writer:"박소담",title:"인터렉티브 웹디자인",year:"2020"},
{id:9, writer:"정우성",title:"코어 자바스크립트",year:"2020"},
{id:10, writer:"이정재",title:"기초부터 배우는 html css",year:"2020"},
{id:11, writer:"한가인",title:"디자이너의 포토샵 스킬북",year:"2019"},
{id:12, writer:"이유리",title:"인디자인 프로",year:"2019"},
{id:13, writer:"김태희",title:"좋은사람에게만 좋은 사람이고 싶다.",year:"2019"},
{id:14, writer:"케이윌",title:"내일죽고 싶지만 떡볶이는 먹고싶어",year:"2019"}
],
filterList: [
{id:1, writer:"공유",title:"나는 나로 살기로 했다.",year:"2022"},
{id:2, writer:"전지현",title:"경이로운 소문",year:"2022"},
{id:3, writer:"손예진",title:"UI/UX 디자인 이론과 실습",year:"2022"},
{id:4, writer:"현빈",title:"만들면서 배우는 제이쿼리",year:"2022"},
{id:5, writer:"공유",title:"이상한 나라의 엘리스",year:"2021"},
{id:6, writer:"신채경",title:"인어공주",year:"2021"},
{id:7, writer:"유진",title:"일러스트레이터 강의",year:"2021"},
{id:8, writer:"박소담",title:"인터렉티브 웹디자인",year:"2020"},
{id:9, writer:"정우성",title:"코어 자바스크립트",year:"2020"},
{id:10, writer:"이정재",title:"기초부터 배우는 html css",year:"2020"},
{id:11, writer:"한가인",title:"디자이너의 포토샵 스킬북",year:"2019"},
{id:12, writer:"이유리",title:"인디자인 프로",year:"2019"},
{id:13, writer:"김태희",title:"좋은사람에게만 좋은 사람이고 싶다.",year:"2019"},
{id:14, writer:"케이윌",title:"내일죽고 싶지만 떡볶이는 먹고싶어",year:"2019"}
]
}
function bookReducer(state, action){
switch(action.type){
case "YEAR_LISTS":
return {
...state,
filterList: state.total.filter(list=>list.year === action.year)
}
// state.filter(list=>list.year === action.year);
case "TOTAL_LISTS":
return {
...state,
filterList:state.total
};
case "DELETE_LIST":
return {
total:state.total.filter(list=>list.id !== action.id),
filterList:state.filterList.filter(list=>list.id !== action.id)
}
default:
return state;
}
}
const BookListContext = createContext();
const BookDispatchContext = createContext();
export function BookProvider({children}){
const [state, dispatch] = useReducer(bookReducer, initialLists);
return (
<BookListContext.Provider value={state}>
<BookDispatchContext.Provider value={dispatch}>
{children}
</BookDispatchContext.Provider>
</BookListContext.Provider>
)
}
export function useBookList(){
return useContext(BookListContext);
}
export function useBookDispatch(){
return useContext(BookDispatchContext);
}
Components/Header.js
import React from 'react';
import { useBookDispatch, useBookList } from '../context/BookContext';
const List = ({year}) => {
const dispatch = useBookDispatch();
const onYearChange=()=>dispatch({
type:'YEAR_LISTS',
year: year
})
return (
<li onClick={onYearChange}>{year}년도</li>
)
}
const Header = () => {
const { total } = useBookList();
const dispatch = useBookDispatch();
//1)map메서드를 활용 ["2022","2022","2021","2021"...]
//2)new Set set을 생성(같은 값을 허용하지않음) { "2022","2021","2020","2019"}
//3)스프레드 구문으로 배열로 변경 [...Set] [ "2022","2021","2020","2019"]
const yearArr = [...new Set(total.map(book => book.year))];
console.log(yearArr);
const onClickTotal=() => {
dispatch({
type:'TOTAL_LISTS'
})
}
return (
<div className='header'>
<h2 onClick={onClickTotal}>
booklist</h2>
<ul>
{yearArr.map((year,index)=><List year={year} key={index}/>)}
</ul>
</div>
);
};
export default Header;
Components/Content.js
import React from 'react';
import ContentList from './ContentList';
import { useBookList,useBookDispatch } from '../context/BookContext';
const Content = () => {
const { filterList } = useBookList();
const dispatch = useBookDispatch();
return (
<div className='content'>
<table>
<tr>
<th>글쓴이</th>
<th>제목</th>
<th>년도</th>
</tr>
{filterList.map(list=><ContentList list={list} key={list.id} dispatch={dispatch}/>)}
</table>
</div>
);
};
export default Content;
Components/ContentList.js
import React from 'react';
const ContentList = ({ list, dispatch}) => {
const onDelete = ()=>dispatch({
type: 'DELETE_LIST',
id: list.id
})
return (
<tr>
<td>{list.writer}</td>
<td>{list.title}</td>
<td>{list.year}<button onClick={onDelete}>삭제</button></td>
</tr>
);
};
export default ContentList;
App.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
.App {
text-align: center;
padding-top: 50px;
}
.header {
padding: 20px;
}
.header ul {
display: flex;
justify-content: space-between;
padding: 30px 0;
}
.header ul li {
width: 22%;
background: #333;
color : #fff;
border-radius: 6px;
padding: 10px;
}
.content table {
border-collapse: collapse;
border-top: 3px solid #333;
width: 100%;
}
.content table td, .content table th {
line-height: 40px;
border-bottom: 1px solid #333;
}