Header부분 기능추가
Home.js
import Button from "../components/Button";
import Header from "../components/Header";
import DiaryList from "../components/DiaryList";
import { useState } from "react";
const Home = () => {
const [pivotDate, setPivotDate] = useState(new Date());
const onIncreaseMonth = () => {
setPivotDate(new Date(pivotDate.getFullYear(), pivotDate.getMonth()+1))
}
const onDecreaseMonth = () => {
setPivotDate(new Date(pivotDate.getFullYear(), pivotDate.getMonth()-1))
}
return (
<div>
<Header
title={`${pivotDate.getFullYear()}년 ${pivotDate.getMonth()+1}월`}
leftChild={ <Button text={'<'} onClick={onDecreaseMonth}/> }
rightChild={<Button text={'>'} onClick={onIncreaseMonth}/>}
/>
<DiaryList/>
</div>
)
};
export default Home;
월별로 게시글 보이기
Home.js
import Button from "../components/Button";
import Header from "../components/Header";
import DiaryList from "../components/DiaryList";
import { useState, useContext } from "react";
import { DiaryStateContext } from "../App"
const getMonthlyData = (pivotDate, data) => {
const beginTime = new Date(
pivotDate.getFullYear(),
pivotDate.getMonth(),
1,
0,
0,
0
).getTime();
const endTime = new Date(
pivotDate.getFullYear(),
pivotDate.getMonth()+1,
0,
23,
59,
59
).getTime();
return data.filter(
(item) => beginTime <= item.createdDate && item.createdDate <= endTime
);
}
const Home = () => {
const data = useContext(DiaryStateContext);
const [pivotDate, setPivotDate] = useState(new Date());
const monthlyData = getMonthlyData(pivotDate, data);
console.log(monthlyData);
const onIncreaseMonth = () => {
setPivotDate(new Date(pivotDate.getFullYear(), pivotDate.getMonth()+1))
}
const onDecreaseMonth = () => {
setPivotDate(new Date(pivotDate.getFullYear(), pivotDate.getMonth()-1))
}
return (
<div>
<Header
title={`${pivotDate.getFullYear()}년 ${pivotDate.getMonth()+1}월`}
leftChild={ <Button text={'<'} onClick={onDecreaseMonth}/> }
rightChild={<Button text={'>'} onClick={onIncreaseMonth}/>}
/>
<DiaryList data={monthlyData}/>
</div>
)
};
export default Home;
DiaryList.js
import './DiaryList.css'
import DiaryItem from './DiaryItem'
import Button from './Button'
const DiaryList = ({data}) => {
return (
<div className='DiaryList'>
<div className='menu_bar'>
<select>
<option value={'latest'}>최신순</option>
<option value={'oldest'}>오래된순</option>
</select>
<Button text={'새 일기 쓰기'} type={'POSITIVE'}/>
</div>
<div className='list_warapper'>
{ data.map((item) => (
<DiaryItem key={item.id} {...item}/>
))}
</div>
</div>
)
}
export default DiaryList;
DiaryItem.js
import './DiaryItem.css'
import { getEmotionImage } from '../util/get-emotion-image';
import Button from './Button';
const DiaryItem = ({id, emotionId, createdDate, content}) => {
return (
<div className='DiaryItem'>
<div className={`img_section img_section_${emotionId}`}>
<img src={getEmotionImage(emotionId)}/>
</div>
<div className='info_section'>
<div className='created_date'>
{ new Date(createdDate).toLocaleDateString()}
</div>
<div className='content'>
{content}
</div>
</div>
<div className='button_section'>
<Button text={'수정하기'}/>
</div>
</div>
)
};
export default DiaryItem;
App.js
import './App.css';
import Dairy from './pages/Diary';
import New from './pages/New';
import Home from './pages/Home';
import Notfound from './pages/Notfound';
import { Route, Routes } from 'react-router-dom';
import { useReducer, useRef, createContext } from 'react';
import Header from './components/Header';
import Button from './components/Button';
const mockData = [
{
id: 1,
createdDate: new Date('2025-09-09').getTime(),
emotionId: 1,
content:'1번 일기 내용'
},
{
id: 2,
createdDate: new Date('2025-09-03').getTime(),
emotionId: 2,
content: '2번 일기 내용'
},
{
id: 3,
createdDate: new Date('2025-08-22').getTime(),
emotionId: 4,
content: '3번 일기 내용'
}
]
function reducer(state, action){
console.log(action)
switch(action.type){
case 'CREATE':
return [action.data, ...state]
case 'UPDATE':
return state.map((item) =>
String(item.id) === String(action.data.id) ? action.data : item
)
case 'DELETE':
return state.filter(
(item) => String(item.id) !== String(action.id)
);
default:
return state;
}
}
export const DiaryStateContext = createContext();
export const DiaryDispatchContext = createContext();
function App() {
const [data, dispatch] = useReducer(reducer, mockData);
const idRef = useRef(4);
const onCreate = (createdDate, emotionId, content) => {
dispatch({
type: 'CREATE',
data: {
id: idRef.current++,
createdDate,
emotionId,
content
}
})
}
const onUpdate = (id, createdDate, emotionId, content) => {
dispatch({
type:'UPDATE',
data: {
id,
createdDate,
emotionId,
content
}
})
}
const onDelete = (id) => {
dispatch({
type:'DELETE',
id
})
}
return (
<>
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider value={{ onCreate, onUpdate, onDelete}}>
<Routes>
<Route path='/' element={ <Home/> }/>
<Route path='/new' element={ <New/> }/>
<Route path='/diary/:id' element={ <Dairy/> }/>
<Route path='*' element={ <Notfound/> }/>
</Routes>
</DiaryDispatchContext.Provider>
</DiaryStateContext.Provider>
</>
);
}
export default App;
현재 결과

최신순, 오래된순 버튼활성화
DiaryList.js
import './DiaryList.css'
import DiaryItem from './DiaryItem'
import Button from './Button'
import {useState} from 'react'
const DiaryList = ({data}) => {
const [sortType, setSortType] = useState('latest');
const onChangeSortType = (e) => {
setSortType(e.target.value)
}
return (
<div className='DiaryList'>
<div className='menu_bar'>
<select value={sortType} onChange={onChangeSortType}>
<option value={'latest'}>최신순</option>
<option value={'oldest'}>오래된순</option>
</select>
<Button text={'새 일기 쓰기'} type={'POSITIVE'}/>
</div>
<div className='list_warapper'>
{ data.map((item) => (
<DiaryItem key={item.id} {...item}/>
))}
</div>
</div>
)
}
export default DiaryList;
현재결과

최신순, 오래된순 정렬
DiaryList.js
import './DiaryList.css'
import DiaryItem from './DiaryItem'
import Button from './Button'
import {useState} from 'react'
const DiaryList = ({data}) => {
const [sortType, setSortType] = useState('latest');
const onChangeSortType = (e) => {
setSortType(e.target.value)
}
const getSortedData = () => {
return data.toSorted((a,b) => {
if(sortType === 'oldest'){
return a.createdDate - b.createdDate;
}
else{
return b.createdDate - a.createdDate;
}
})
}
const sortedData = getSortedData();
return (
<div className='DiaryList'>
<div className='menu_bar'>
<select value={sortType} onChange={onChangeSortType}>
<option value={'latest'}>최신순</option>
<option value={'oldest'}>오래된순</option>
</select>
<Button text={'새 일기 쓰기'} type={'POSITIVE'}/>
</div>
<div className='list_warapper'>
{ sortedData.map((item) => (
<DiaryItem key={item.id} {...item}/>
))}
</div>
</div>
)
}
export default DiaryList;
tosort 정보를 그대로 가져옴
sortType
오름차순을 할때 a-b 양수
내림차순 b-a 양수
새일기쓰기 버튼 활성화
DiaryList.js
import './DiaryList.css'
import DiaryItem from './DiaryItem'
import Button from './Button'
import {useState} from 'react'
import { useNavigate } from 'react-router-dom'
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 a.createDate - b.createDate;
}
else{
return b.createDate - a.createDate;
}
})
}
const sortedData = getSortedData();
return (
<div className='DiaryList'>
<div className='menu_bar'>
<select value={sortType} onChange={onChangeSortType}>
<option value={'latest'}>최신순</option>
<option value={'oldest'}>오래된순</option>
</select>
<Button
text={'새 일기 쓰기'}
type={'POSITIVE'}
onClick={()=> nav('/new')}
/>
</div>
<div className='list_warapper'>
{ sortedData.map((item) => (
<DiaryItem key={item.id} {...item}/>
))}
</div>
</div>
)
}
export default DiaryList;
수정하기 만들기
Edit.js 만들기
const Edit = () => {
return (
<div>일기 수정페이지 입니다.</div>
)
}
export default Edit;
App.js
import './App.css';
import Dairy from './pages/Diary';
import New from './pages/New';
import Home from './pages/Home';
import Notfound from './pages/Notfound';
import { Route, Routes } from 'react-router-dom';
import { useReducer, useRef, createContext } from 'react';
import Header from './components/Header';
import Button from './components/Button';
import Edit from './pages/Edit';
const mockData = [
{
id: 1,
createdDate: new Date('2025-09-09').getTime(),
emotionId: 1,
content:'1번 일기 내용'
},
{
id: 2,
createdDate: new Date('2025-09-03').getTime(),
emotionId: 2,
content: '2번 일기 내용'
},
{
id: 3,
createdDate: new Date('2025-08-22').getTime(),
emotionId: 4,
content: '3번 일기 내용'
}
]
function reducer(state, action){
console.log(action)
switch(action.type){
case 'CREATE':
return [action.data, ...state]
case 'UPDATE':
return state.map((item) =>
String(item.id) === String(action.data.id) ? action.data : item
)
case 'DELETE':
return state.filter(
(item) => String(item.id) !== String(action.id)
);
default:
return state;
}
}
export const DiaryStateContext = createContext();
export const DiaryDispatchContext = createContext();
function App() {
const [data, dispatch] = useReducer(reducer, mockData);
const idRef = useRef(4);
const onCreate = (createdDate, emotionId, content) => {
dispatch({
type: 'CREATE',
data: {
id: idRef.current++,
createdDate,
emotionId,
content
}
})
}
const onUpdate = (id, createdDate, emotionId, content) => {
dispatch({
type:'UPDATE',
data: {
id,
createdDate,
emotionId,
content
}
})
}
const onDelete = (id) => {
dispatch({
type:'DELETE',
id
})
}
return (
<>
<DiaryStateContext.Provider value={data}>
<DiaryDispatchContext.Provider value={{ onCreate, onUpdate, onDelete}}>
<Routes>
<Route path='/' element={ <Home/> }/>
<Route path='/new' element={ <New/> }/>
<Route path='/diary/:id' element={ <Dairy/> }/>
<Route path='/edit/:id' element={ <Edit/> }/>
<Route path='*' element={ <Notfound/> }/>
</Routes>
</DiaryDispatchContext.Provider>
</DiaryStateContext.Provider>
</>
);
}
export default App;
DiaryItem.js
import './DiaryItem.css'
import { getEmotionImage } from '../util/get-emotion-image';
import Button from './Button';
import { useNavigate } from 'react-router-dom';
const DiaryItem = ({id, emotionId, createdDate, content}) => {
const nav = useNavigate();
const goEditPage = () => {
nav(`/edit/${id}`);
}
return (
<div className='DiaryItem'>
<div className={`img_section img_section_${emotionId}`}>
<img src={getEmotionImage(emotionId)}/>
</div>
<div className='info_section'>
<div className='created_date'>
{ new Date(createdDate).toLocaleDateString()}
</div>
<div className='content'>
{content}
</div>
</div>
<div className='button_section'>
<Button text={'수정하기'} onClick={goEditPage}/>
</div>
</div>
)
};
export default DiaryItem;
Edit.js 추가작성
import { useParams } from "react-router-dom";
const Edit = () => {
const params = useParams();
return (
<div>{params.id}번 일기 수정페이지 입니다.</div>
)
}
export default Edit;
다이어리 페이지로 넘어가기
Diary.js
import { useParams } from "react-router-dom"
const Diary = () => {
const params = useParams();
console.log(params)
return (
<div>
<h1>{params.id}번째 다이어리</h1>
</div>
)
};
export default Diary;
DiaryItem.js
import './DiaryItem.css'
import { getEmotionImage } from '../util/get-emotion-image';
import Button from './Button';
import { useNavigate } from 'react-router-dom';
const DiaryItem = ({id, emotionId, createdDate, content}) => {
const nav = useNavigate();
const goEditPage = () => {
nav(`/edit/${id}`);
}
const goDiaryPage = () => {
nav(`/diary/${id}`)
}
return (
<div className='DiaryItem'>
<div onClick={goDiaryPage} className={`img_section img_section_${emotionId}`}>
<img src={getEmotionImage(emotionId)}/>
</div>
<div onClick={goDiaryPage} className='info_section'>
<div className='created_date'>
{ new Date(createdDate).toLocaleDateString()}
</div>
<div className='content'>
{content}
</div>
</div>
<div className='button_section'>
<Button text={'수정하기'} onClick={goEditPage}/>
</div>
</div>
)
};
export default DiaryItem;
New 페이지 만들기
New.js
import Header from "../components/Header";
import Button from "../components/Button";
import Editor from "../components/Editor";
const New = () => {
return (
<div>
<Header
title='새 일기 쓰기'
leftChild={ <Button text={'< 뒤로 가기'}/>}
/>
<Editor/>
</div>
)
}
export default New;
Editor.js
import './Editor.css'
const Editor = () => {
return (
<div className='Editor'>
<section className='date_section'>
<h4>오늘의 날짜</h4>
<input type='date'/>
</section>
<section>
<h4>오늘의 감정</h4>
</section>
</div>
)
}
export default Editor;
Editor.js
.Editor > section {
margin-bottom: 40px;
}
.Editor > section > h4 {
font-size: 22px;
font-weight: bold;
}
.Editor > section > input{
background-color: rgb(236, 236, 236);
border : none;
border-radius: 5px;
font-size: 20px;
padding: 10px 20px ;
}
현재 결과

EmotionItem.js / .css 추가
EmotionItem.js
import './EmotionItem.css'
const EmotionItem = () => {
return(
<div>e</div>
)
};
export default EmotionItem;
Editor.js
import './Editor.css'
import EmotionItem from './EmotionItem';
import Button from './Button';
const emotionList = [{
emotionId: 1,
emotionName: '매우 좋음'
},
{
emotionId:2,
emotionName: '좋음'
},
{
emotionId:3,
emotionName: '보통'
},
{
emotionId:4,
emotionName: '나쁨'
},
{
emotionId:5,
emotionName: '매우나쁨'
},
]
const Editor = () => {
return (
<div className='Editor'>
<section className='date_section'>
<h4>오늘의 날짜</h4>
<input type='date'/>
</section>
<section className='emotion_section'>
<h4>오늘의 감정</h4>
<div className='emotion_list_wrapper'>
{emotionList.map((item) => (
<EmotionItem
key={item.emotionId}
{...item}
/>
))}
</div>
</section>
</div>
)
}
export default Editor;
EmotionItem.js
import './EmotionItem.css'
import { getEmotionImage } from '../util/get-emotion-image';
const EmotionItem = ({ emotionId, emotionName}) => {
return(
<div className='EmotionItem'>
<img className='emotion_img' src={getEmotionImage(emotionId)}/>
<div className='emotion_name'>{emotionName}</div>
</div>
)
};
export default EmotionItem;
Editor.css
.Editor > section {
margin-bottom: 40px;
}
.Editor > section > h4 {
font-size: 22px;
font-weight: bold;
}
.Editor > section > input{
background-color: rgb(236, 236, 236);
border : none;
border-radius: 5px;
font-size: 20px;
padding: 10px 20px ;
}
.Editor .emotion_section .emotion_list_wrapper{
display: flex;
justify-content: space-around;
gap: 2%;
}
EmotionItem.css
.EmotionItem {
background-color: rgb(236,236,236);
padding: 20px;
border-radius: 5px;
cursor: pointer;
text-align: center;
}
.EmotionItem .emotion_img {
width: 50%;
margin-bottom: 10px;
}
현재 결과

Editor.js
import './Editor.css'
import EmotionItem from './EmotionItem';
import Button from './Button';
const emotionList = [{
emotionId: 1,
emotionName: '매우 좋음'
},
{
emotionId:2,
emotionName: '좋음'
},
{
emotionId:3,
emotionName: '보통'
},
{
emotionId:4,
emotionName: '나쁨'
},
{
emotionId:5,
emotionName: '매우나쁨'
},
]
const Editor = () => {
const emotionId = 5;
return (
<div className='Editor'>
<section className='date_section'>
<h4>오늘의 날짜</h4>
<input type='date'/>
</section>
<section className='emotion_section'>
<h4>오늘의 감정</h4>
<div className='emotion_list_wrapper'>
{emotionList.map((item) => (
<EmotionItem
key={item.emotionId}
{...item}
isSelected={item.emotionId === emotionId}
/>
))}
</div>
</section>
</div>
)
}
export default Editor;
EmotionItem.js
import './EmotionItem.css'
import { getEmotionImage } from '../util/get-emotion-image';
const EmotionItem = ({ emotionId, emotionName, isSelected}) => {
return(
<div className={`EmotionItem ${isSelected ? `EmotionItem_on_${emotionId}` : ""}`}>
<img className='emotion_img' src={getEmotionImage(emotionId)}/>
<div className='emotion_name'>{emotionName}</div>
</div>
)
};
export default EmotionItem;
EmotionItem.css
.EmotionItem {
background-color: rgb(236,236,236);
padding: 20px;
border-radius: 5px;
cursor: pointer;
text-align: center;
}
.EmotionItem .emotion_img {
width: 50%;
margin-bottom: 10px;
}
.EmotionItem_on_1 {
color: white;
background-color: rgb(100,201,100);
}
.EmotionItem_on_2 {
color: white;
background-color: rgb(157,215,114);
}
.EmotionItem_on_3 {
color: white;
background-color: rgb(253,206,23);
}
.EmotionItem_on_4 {
color: white;
background-color: rgb(253,132,70);
}
.EmotionItem_on_5 {
color: white;
background-color: rgb(253,86,95);
}
현재 결과

텍스트창 만들기
Editor.js
import './Editor.css'
import EmotionItem from './EmotionItem';
import Button from './Button';
const emotionList = [{
emotionId: 1,
emotionName: '매우 좋음'
},
{
emotionId:2,
emotionName: '좋음'
},
{
emotionId:3,
emotionName: '보통'
},
{
emotionId:4,
emotionName: '나쁨'
},
{
emotionId:5,
emotionName: '매우나쁨'
},
]
const Editor = () => {
const emotionId = 5;
return (
<div className='Editor'>
<section className='date_section'>
<h4>오늘의 날짜</h4>
<input type='date'/>
</section>
<section className='emotion_section'>
<h4>오늘의 감정</h4>
<div className='emotion_list_wrapper'>
{emotionList.map((item) => (
<EmotionItem
key={item.emotionId}
{...item}
isSelected={item.emotionId === emotionId}
/>
))}
</div>
</section>
<section className='content_section'>
<h4>오늘의 일기</h4>
<textarea placeholder='오늘은 어땠나요?'/>
</section>
</div>
)
}
export default Editor;
Editor.css
.Editor > section {
margin-bottom: 40px;
}
.Editor > section > h4 {
font-size: 22px;
font-weight: bold;
}
.Editor > section > input, textarea{
background-color: rgb(236, 236, 236);
border : none;
border-radius: 5px;
font-size: 20px;
padding: 10px 20px ;
}
.Editor > section > textarea{
padding: 20px;
width: 100%;
min-height: 200px;
resize: vertical;
box-sizing: border-box;
}
.Editor .emotion_section .emotion_list_wrapper{
display: flex;
justify-content: space-around;
gap: 2%;
}
아래 버튼만들기
Editor.js
import './Editor.css'
import EmotionItem from './EmotionItem';
import Button from './Button';
const emotionList = [{
emotionId: 1,
emotionName: '매우 좋음'
},
{
emotionId:2,
emotionName: '좋음'
},
{
emotionId:3,
emotionName: '보통'
},
{
emotionId:4,
emotionName: '나쁨'
},
{
emotionId:5,
emotionName: '매우나쁨'
},
]
const Editor = () => {
const emotionId = 5;
return (
<div className='Editor'>
<section className='date_section'>
<h4>오늘의 날짜</h4>
<input type='date'/>
</section>
<section className='emotion_section'>
<h4>오늘의 감정</h4>
<div className='emotion_list_wrapper'>
{emotionList.map((item) => (
<EmotionItem
key={item.emotionId}
{...item}
isSelected={item.emotionId === emotionId}
/>
))}
</div>
</section>
<section className='content_section'>
<h4>오늘의 일기</h4>
<textarea placeholder='오늘은 어땠나요?'/>
</section>
<section className='button_section'>
<Button text={'취소하기'}/>
<Button text={'작성완료'} type='POSITIVE'/>
</section>
</div>
)
}
export default Editor;
Editor.css
.Editor > section {
margin-bottom: 40px;
}
.Editor > section > h4 {
font-size: 22px;
font-weight: bold;
}
.Editor > section > input, textarea{
background-color: rgb(236, 236, 236);
border : none;
border-radius: 5px;
font-size: 20px;
padding: 10px 20px ;
}
.Editor > section > textarea{
padding: 20px;
width: 100%;
min-height: 200px;
resize: vertical;
box-sizing: border-box;
}
.Editor .emotion_section .emotion_list_wrapper{
display: flex;
justify-content: space-around;
gap: 2%;
}
.Editor .button_section{
display: flex;
justify-content: space-between;
}
현재 결과

'Front > React' 카테고리의 다른 글
| Day11_react(6)_Am (0) | 2025.09.10 |
|---|---|
| Day11_react(6)_Pm (0) | 2025.09.09 |
| Day10_react(5)_Pm (0) | 2025.09.08 |
| Day10_react(5)_Am (0) | 2025.09.08 |
| Day9_react(4)_Pm (0) | 2025.09.05 |