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;
}