본문 바로가기
Front/React

Day11_react(6)_Am

by roaring90s 2025. 9. 10.

수정페이지 삭제버튼 활성화

Eidit.js

import { useParams, useNavigate } from "react-router-dom";

import Header from "../components/Header";
import Editor from "../components/Editor";
import Button from "../components/Button";
import { DiaryStateContext, DiaryDispatchContext } from "../App";
import { useContext, useEffect, useState } from "react";


const Edit = () => {
    const params = useParams();
    const nav = useNavigate();

    const data = useContext(DiaryStateContext);
    const { onUpdate, onDelete } = useContext(DiaryDispatchContext);

    const [curDiaryItem, setCurDiaryItem] = useState();

    useEffect(() => {

        const currentDiaryItem = data.find(
            (item) => String(item.id) === String(params.id)
        );

        if(!currentDiaryItem) {
            window.alert('존재하지 않은 일기입니다.');
            nav('/', {replace: true})
        }

        setCurDiaryItem(currentDiaryItem);
        console.log(currentDiaryItem);

    }, [params.id])

    const onClickDelete = () => {
        if(window.confirm('일기를 정말로 삭제하시겠습니가? 다시 복구되지 않습니다.')){
        onDelete(params.id)
        nav('/', {replace: true})
        }
    }


    const onSubmit = (input) => {
        if (window.confirm('일기를 정말로 수정하시겠습니까?')){
         onUpdate(
            params.id,
            input.createdDate.getTime(),
            input.emotionId,
            input.content
        )
        nav('/', {replac : true});
    }

        }

   

    return (
        <div>
            <Header
            title={'일기 수정하기'}
            leftChild={
                <Button onClick = {() => nav(-1)} text={'< 뒤로가기'} />
            }

            rightChild={
                <Button
                    text={'삭제하기'}
                    type={'NEGATIVE'}
                    onClick={onClickDelete}
                />
            }
           
            />
            <Editor initData={curDiaryItem} onSubmit={onSubmit}/>
        </div>
    )
}

export default Edit;

 

현재 결과


 

Diary 페이지 구성

 

다이어리 헤더 버튼 활성화

 

Diary.js

import { useParams, useNavigate} from "react-router-dom"
import Header from "../components/Header";
import Button from "../components/Button";
import Viewer from "../components/Viewer";


const Diary = () => {
    const params = useParams();
    const nav = useNavigate();
   
    return (
        <div>
            <Header
                leftChild={
                    <Button
                        text={"< 뒤로가기"}
                        onClick={() => nav(-1)}
                    />
                }
                title={'yyyy년 mm월 ss일 작성'}

                rightChild={
                    <Button
                        text = "수정하기"
                        onClick={() => { nav(`/edit/${params.id}`)}}
                   
                    />
                }
            />
        </div>
    )
};
export default Diary;

 


 

useDiary.js

import { useContext, useState, useEffect } from "react";
import { DiaryStateContext } from "../App";
import { useNavigate } from "react-router-dom";

const useDiary = (id) => {

    const nav = useNavigate();
    const data = useContext(DiaryStateContext);
    const [curDiaryItem, setCurDiaryItem] = useState();

    useEffect(() => {

        const currentDiaryItem = data.find(
            (item) => String(item.id) === String(id)
        );

        if(!currentDiaryItem) {
            window.alert('존재하지 않은 일기입니다.');
            nav('/', {replace: true})
        }

        setCurDiaryItem(currentDiaryItem);
        console.log(currentDiaryItem);

           
    }, [id])

    return curDiaryItem;
}
export default useDiary;

 

Edit.js

import { useParams, useNavigate } from "react-router-dom";

import Header from "../components/Header";
import Editor from "../components/Editor";
import Button from "../components/Button";
import { DiaryDispatchContext } from "../App";
import { useContext} from "react";
import useDiary from "../hook/useDiary";

const Edit = () => {
    const params = useParams();
    const nav = useNavigate();

    const { onUpdate, onDelete } = useContext(DiaryDispatchContext);

    const curDiaryItem = useDiary(params.id)

    const onClickDelete = () => {
        if(window.confirm('일기를 정말로 삭제하시겠습니가? 다시 복구되지 않습니다.')){
        onDelete(params.id)
        nav('/', {replace: true})
        }
    }


    const onSubmit = (input) => {
        if (window.confirm('일기를 정말로 수정하시겠습니까?')){
         onUpdate(
            params.id,
            input.createdDate.getTime(),
            input.emotionId,
            input.content
        )
        nav('/', {replac : true});
    }

        }

   

    return (
        <div>
            <Header
            title={'일기 수정하기'}
            leftChild={
                <Button onClick = {() => nav(-1)} text={'< 뒤로가기'} />
            }

            rightChild={
                <Button
                    text={'삭제하기'}
                    type={'NEGATIVE'}
                    onClick={onClickDelete}
                />
            }
           
            />
            <Editor initData={curDiaryItem} onSubmit={onSubmit}/>
        </div>
    )
}

export default Edit;

get-stringed-date.js

export const getStringDate = (targetDate) => {
    // yyyy-mm-dd

    let year = targetDate.getFullYear();
    let month = targetDate.getMonth() +1
    let date = targetDate.getDate();

    if (month < 10){
        month = `0${month}`;
    }
    if (date < 10){
        date = `0${date}`;
    }


    return `${year}-${month}-${date}`;
};

Editor.js 에서 잘라오기

 

Editor.js

import './Editor.css'
import EmotionItem from './EmotionItem';
import Button from './Button';
import { useState, useEffect } from 'react';
import { useNavigate } from 'react-router-dom';
import { emotionList } from '../util/constants';
import { getStringDate } from '../util/get-stringed-date';



const Editor = ({initData, onSubmit}) => {

    const nav = useNavigate();

    const [input, setInput] = useState({
        createdDate: new Date(),
        emotionId: 3,
        content: ""
    })
   
    useEffect(()=> {
        if(initData){
            setInput({
                ...initData,
                createdDate: new Date(Number(initData.createdDate))
            })
        }
    }, [initData])

    const onChangeInput = (e) => {
        let name= e.target.name;
        let value= e.target.value;

        if(name ==='createdDate'){
            value = new Date(value);
        }
       
        setInput({
            ...input,
            [name]: value
        })
    }


    //const emotionId = 5;

    const onSubmitButtonClick = () => {
        onSubmit(input);
    }

    return (
        <div className='Editor'>
           <section className='date_section'>
            <h4>오늘의 날짜</h4>
            <input
                type='date'
                name='createdDate'
                onChange={onChangeInput}
                value={getStringDate(input.createdDate)}
            />
           </section>
           <section className='emotion_section'>
            <h4>오늘의 감정</h4>
            <div className='emotion_list_wrapper'>
                {emotionList.map((item) => (
                    <EmotionItem
                        onClick={() =>
                            onChangeInput({
                                target: {
                                    name: 'emotionId',
                                    value: item.emotionId
                                }}
                            )
                        }


                        key={item.emotionId}
                        {...item}
                        isSelected={item.emotionId === input.emotionId}
                        />
                    ))}
            </div>
           </section>
           <section className='content_section'>
                    <h4>오늘의 일기</h4>
                    <textarea
                        placeholder='오늘은 어땠나요?'
                        name='content'
                        onChange={onChangeInput}
                        value={input.content}
                    />
           </section>
           <section className='button_section'>
                    <Button text={'취소하기'} onClick={() => nav(-1)}/>
                    <Button
                        text={'작성완료'}
                        type='POSITIVE'
                        onClick={onSubmitButtonClick}
                        />
           </section>
        </div>
    )
}
export default Editor;

 

 

Diary.js

import { useParams, useNavigate} from "react-router-dom"
import Header from "../components/Header";
import Button from "../components/Button";
import Viewer from "../components/Viewer";
import useDiary from "../hook/useDiary";
import { getStringDate } from "../util/get-stringed-date";


const Diary = () => {
    const params = useParams();
    const nav = useNavigate();

    const curDiaryItem = useDiary(params.id);

    if(!curDiaryItem){
        return <div>데이터 로딩중...</div>
    }

    const { createdDate, emotionId, content } = curDiaryItem;
    const title = getStringDate(new Date(createdDate))
   
    return (
        <div>
            <Header
                leftChild={
                    <Button
                        text={"< 뒤로가기"}
                        onClick={() => nav(-1)}
                    />
                }

                title={`${title} 기록`}

                rightChild={
                    <Button
                        text = "수정하기"
                        onClick={() => { nav(`/edit/${params.id}`)}}
                   
                    />
                }
            />
            <Viewer emotionId={emotionId} content={content} />
        </div>
    )
};
export default Diary;

 

현재 결과

 


 

Viewer.js

import './Viewer.css'
import { getEmotionImage } from '../util/get-emotion-image';

const Viewer = ({ emotionId, content}) => {
    return (
        <div className='Viewer'>
            <section className='img_section'>
                <h4>오늘의 감정</h4>
                <div>
                    <img src={getEmotionImage(emotionId)}/>
                    <div>이모션 텍스트</div>
                </div>
            </section>
            <section className='content_section'>
                <h4>오늘의 일기</h4>
                <div className='content_wrapper'>
                    <p>{content}</p>
                </div>
            </section>
        </div>
    )
};
export default Viewer;

 

현재 결과


 

이모션 가져오기

Viewer.js

import './Viewer.css'
import { getEmotionImage } from '../util/get-emotion-image';
import { emotionList } from '../util/constants';

const Viewer = ({ emotionId, content}) => {

    const emotionItem = emotionList.find(
        (item) => String(item.emotionId) === String(emotionId)
    )

    return (
        <div className='Viewer'>
            <section className='img_section'>
                <h4>오늘의 감정</h4>
                <div className={`emotion_img_wrapper emotion_img_wrapper_${emotionId}`}>
                    <img src={getEmotionImage(emotionId)}/>
                    <div>{emotionItem.emotionName}</div>
                </div>
            </section>
            <section className='content_section'>
                <h4>오늘의 일기</h4>
                <div className='content_wrapper'>
                    <p>{content}</p>
                </div>
            </section>
        </div>
    )
};
export default Viewer;

 

Viewer.css

.Viewer > section {
    width: 100%;
    margin-bottom: 100px;

    display: flex;
    flex-direction: column;
    align-items: center;
    text-align: center;
}

.Viewer > section > h4 {
    font-size: 22px;
    font-weight: bold;
}

.Viewer .emotion_img_wrapper {
    width: 250px;
    height: 250px;
    border-radius: 5px;

    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: space-around;

    color: white;
    font-size: 25px;
   
}

.Viewer .emotion_img_wrapper_1 {
    background-color: rgb(100,201,100);
}
.Viewer .emotion_img_wrapper_2 {
    background-color: rgb(157,215,114);
}
.Viewer .emotion_img_wrapper_3 {
    background-color: rgb(253,206,23);
}
.Viewer .emotion_img_wrapper_4 {
    background-color: rgb(253,132,70);
}
.Viewer .emotion_img_wrapper_5 {
    background-color: rgb(253,86,95);
}

.Viewer .content_wrapper {
    width: 100%;
    background-color: rgb(236,236,236);
    border-radius: 5px;

    word-break: keep-all;
    overflow-wrap: break-word;
}

.Viewer .content_wrapper > p {
    padding: 20px;
    text-align: left;
    font-size: 20px;
    font-weight: 400;
    line-height: 2.5;
}

 

현재 결과

 


 

아이피에 데이터 저장하기

App.js

import './App.css';
import Diary 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);


  localStorage.setItem('test', 'hello local storage!!!')
  // localStorage.setItem('person', {name:'lims'})
  localStorage.setItem('person', JSON.stringify({name:'lims'}))

  console.log(localStorage.getItem('test'));
  console.log(localStorage.getItem('person'));
  console.log(JSON.parse(localStorage.getItem('person')));


  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={ <Diary/> }/>
            <Route path='/edit/:id' element={ <Edit/> }/>
            <Route path='*' element={ <Notfound/> }/>
          </Routes>
        </DiaryDispatchContext.Provider>
      </DiaryStateContext.Provider>
    </>
  );
}

export default App;


 

App.js

import './App.css';
import Diary 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, useState, useEffect } 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)

  let nextState;
 
  switch(action.type){
    case 'INIT':
      return action.data
    case 'CREATE':
      nextState = [action.data, ...state]
      break;
    case 'UPDATE':
      nextState = state.map((item) =>
        String(item.id) === String(action.data.id) ? action.data : item
      )
      break;
    case 'DELETE':
      nextState = state.filter(
        (item) => String(item.id) !== String(action.id)
      );
      break;
    default:
      return state;
  }


  localStorage.setItem('diary', JSON.stringify(nextState));
  return nextState;
}


export const DiaryStateContext = createContext();
export const DiaryDispatchContext = createContext();


function App() {

  const [isLoading, setIsLoading] = useState(true);
 
  const [data, dispatch] = useReducer(reducer, []);
  const idRef = useRef(0);

  useEffect(() => {
    const storagedData = localStorage.getItem('diary');
    if(!storagedData){
      setIsLoading(false);
      return;
    }

    const parsedData = JSON.parse(storagedData)
    if(!Array.isArray(parsedData)){
      setIsLoading(false);
      return;
    }
   
    let maxId = 0;
   
    parsedData.forEach((item) => {
      if(Number(item.id) > maxId){
        maxId = item.id
      }
    })

    idRef.current = maxId +1;

    dispatch({
      type: 'INIT',
      data: parsedData
    });
   
    setIsLoading(false);
   
  }, [])


  // localStorage.setItem('test', 'hello local storage!!!')
  // // localStorage.setItem('person', {name:'lims'})
  // localStorage.setItem('person', JSON.stringify({name:'lims'}))

  // console.log(localStorage.getItem('test'));
  // console.log(localStorage.getItem('person'));
  // console.log(JSON.parse(localStorage.getItem('person')));




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

  if(isLoading){
    return <div>데이터 로딩중 입니다...</div>
  };
 
  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={ <Diary/> }/>
            <Route path='/edit/:id' element={ <Edit/> }/>
            <Route path='*' element={ <Notfound/> }/>
          </Routes>
        </DiaryDispatchContext.Provider>
      </DiaryStateContext.Provider>
    </>
  );
}

export default App;

'Front > React' 카테고리의 다른 글

Day13_react(7)_Pm  (0) 2025.09.12
Day11_react(6)_Pm  (0) 2025.09.09
Day11_react(6)_Am  (0) 2025.09.09
Day10_react(5)_Pm  (0) 2025.09.08
Day10_react(5)_Am  (0) 2025.09.08