import { useState,useReducer,useRef } from 'react'
import './App.css'
import { Routes,Route,Link ,useNavigate} from 'react-router-dom'
import Home from './page/Home'
const mockData=[
{
id:1,
createdDate:new Date('2025-01-08'),
emotionId:1,
content:'일번 일기내용'
},
{
id:2,
createdDate:new Date('2025-01-18'),
emotionId:2,
content:'2번 일기내용'
},
{
id:3,
createdDate:new Date('2025-01-28'),
emotionId:3,
content:'3번 일기내용'
},
]
function reducer(state,action){
switch(action.type){
case "CREATE" : return [...state,action.data] ;
case "UPDATE" : return state.map((item)=>String(item.id)===String(action.data.if)? action.data: item);
case "DELETE" : return state.filter((item)=> String(item.id)!==String(action.data.id));
default : return state;
}
}
function App() {
const idRef=useRef(3);
const [count, setCount] = useState(0)
const [data,dispatch] = useReducer(reducer,mockData);
const onCreate=(createdDate,emotionId,content)=>{
dispatch({
type:"CREATE",
data:{
id:idRef.current++,
createdDate,
emotionId,
content
}
})
}
const onDelete=(id)=>{
dispatch({
type:"DELETE",
data:{
id
}
})
}
const onUpdate=(id,createdDate,content,emotionId)=>{
dispatch({
type:"UPDATE",
data:{
id,
createdDate,
emotionId,
content
}
})
}
return (
<>
<Home></Home>
</>
)
}
export default App
return (
<>
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider value={{onCreate,onDelete,onUpdate}}>
<Routes>
<Route path='/' element={<Home></Home>}></Route>
<Route path='/new' element={<New></New>}></Route>
<Route path='/diary/:id' element={<Diary></Diary>}></Route>
<Route path='*' element={<NotFound></NotFound>}></Route>
<Route path='/edit/:id' element={<Edit></Edit>}></Route>
</Routes>
</DiaryDispatchContext.Provider>
</DiaryStateContext.Provider>
</>
)
}
* : 지정되지 않은 루트로 이동하면 정상적이지 않은 페이지라고 알려주는 페이지로 이동시킴createContext로 props를 이용하여 부모에서 자식으로 전달이 아닌 어디에서나 접근이 가능하게 만듦/edit:id : /edit/3과 같은 url로 접근하면 해당 아이디가 가지고 있는 정보를 나타내는 페이지로 이동주의
<BrowserRouter>
<App />
</BrowserRouter>
Routes를 쓸때는 App이 BrowserRouter로 감싸져 있어야 함HomePage 이미지

components 폴더를 만든 후 Header,Button,DiaryList,DiaryItem 컴포넌트를 구현함Header
const Header=({title,leftChild,rightChild})=>{
return <header className='Header'>
<div className='header_left'>{leftChild}</div>
<div className='header_center'>{title}</div>
<div className='header_right'>{rightChild}</div>
</header>
}
export default Header
title에는 텍스트 구문 leftChild,rightChild의 경우는 Button 컴포넌트를 상속받음Button
const Button=({text,type,onClick})=>{
return <button className={`Button Button_${type}`} onClick={onClick} > {text}</button>
}
export default Button
css를 적용하기 위해 동적으로 클래스 생성onClick 함수 적용DiaryList
const DiaryList=({data})=>{
const nav=useNavigate();
const [sortType,setSortType]=useState("latest");
const onChangeSortType=(e)=>{
setSortType(e.target.value);
}
// 원본배열을 수정하면 문제가 생길수있어 새로운 배열로 반환받음
const getSortedData=()=>{
return data.toSorted((a,b)=>{
if(sortType=="oldest"){
return Number(a.createdDate) -Number(b.createdDate);
}else{
return Number(b.createdDate)-Number(a.createdDate);
}
})
}
const sortedData =getSortedData();
return <>
<div className="DiaryList">
<div className="menu_bar">
<select name="" id="" onChange={onChangeSortType}>
<option value="latest">최신순</option>
<option value="oldest"> 오래된순</option>
</select>
<Button text={'새로운 일기 쓰기'} type={'POSITIVE'} onClick={()=>{
nav("/new")
}}></Button>
</div>
<div className="list_wrapper">
{sortedData.map((item)=>{
return <DiaryItem key={item.id}{...item}></DiaryItem>
})}
</div>
</div>
</>
}
export default DiaryList
onChangeSortType에서 setSortType으로 타입 조작과 동시에 getSortedData()를 새로 반환map을 써서 배열을 순환하며 각 데이터를 DiaryItem으로 props형태로 전달DiaryItem
const DiaryItem=({id,emotionId,createdDate,content})=>{
const nav=useNavigate();
return (
<div className="DiaryItem">
<div className={`img_section img_section_${emotionId}`} onClick={()=>nav(`/diary/${id}`)}>
<img src={getEmotionImage(emotionId)} alt="" />
</div>
<div className="info_section" onClick={()=>nav(`/diary/${id}`)}>
<div className="created_date">{new Date(createdDate).toLocaleDateString()}</div>
<div className="content">
{content}
</div>
</div>
<div className="button_section">
<Button text={'수정하기'} onClick={()=>nav(`/edit/${id}`)}></Button>
</div>
</div>
)
}
export default DiaryItem
getEmtionImage(): 별도의 자바 스크립트 파일로 만들어 emotionId에 따라 다른 이미지 전달