인프런 커뮤니티 질문&답변

대조동이강인님의 프로필 이미지
대조동이강인

작성한 질문수

[2024] 한입 크기로 잘라 먹는 리액트(React.js) : 기초부터 실전까지

새일기를 쓰면 한개가 아닌 두개가 등록이 됩니다ㅠ

해결된 질문

작성

·

554

0

윈터로드님 알려주신 덕분에 완강할수잇었습니다ㅠㅠ 인프런 강의 첫 수강완료증을 받앗네요

제 프로젝트에 큰오류를 발견했습니다,,,, 새일기쓰면 똑같은게 2개가 만들어지는데 이거 어디서 오류를 수정해야 하는지알수잇을까요?

답변 1

0

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

안녕하세요 이정환입니다.

완강하셨다니 감사합니다 그리고 축하드립니다!

코드를 보지 않고는 오류를 찾기 어렵습니다 🥲

오류가 발생한 코드를 코드샌드박스 또는 깃허브에 업로드 하신 다음 링크로 공유 부탁드립니다.

제가 깃허브랑 코드샌드박스 사용법을 잘몰라서 소스만 공유하겠습니다ㅠ 깃허브도 공부를 해야겟네요

//App.js

import React, { useReducer, useRef, useEffect } from 'react';

import './App.css';
import { BrowserRouter, Routes, Route } from "react-router-dom";

import Home from './pages/Home';
import New from './pages/New';
import Edit from './pages/Edit';
import Diary from './pages/Diary';

const reducer = (state,action)=>{
  let newState = [];
  switch(action.type){
    case 'INIT':{
      return action.data;
    }
    case 'CREATE':{
      newState = [action.data, ...state];
      break;
    }
    case 'REMOVE':{
      newState = state.filter((it)=>it.id !== action.targetId);
      break;
    }
    case 'EDIT':{
      newState = state.map((it)=>it.id === action.data.id? [...action.data]: it)
      break;
    }
    default:
    return state;
  }

  localStorage.setItem("diary", JSON.stringify(newState))
  return newState;
};

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


function App() {
  useEffect(() => {
    const item1 = localStorage.getItem("item1");
    const item2 = localStorage.getItem("item2");
    const item3 = JSON.parse(localStorage.getItem("item3"));
    console.log(item1, item2, item3)
  }, []);
  
  const [data, dispatch] = useReducer(reducer,[]);

  useEffect(() =>{
    const localData = localStorage.getItem('diary');
    if(localData) {
      const diaryList = JSON.parse(localData).sort(
        (a,b)=> parseInt(b.id) - parseInt(a.id)
        );

        if(diaryList.length >= 1) {
          dataId.current = parseInt(diaryList[0].id) + 1;
          dispatch({ type: "INIT", data: diaryList });
        }
    }
  }, []);

  const dataId = useRef(0);
  // CREATE
  const onCreate = (date, content, emotion)=>{
    dispatch({
      type :"CREATE",
      data:{
      id: dataId.current,
      date: new Date(date).getTime(),
      content,
      emotion,
    },
  });
  dataId.current += 1;
};
  // REMOVE
  const onRemove = (targetId) => {
    dispatch({type: "REMOVE",targetId});
  }
  // EDIT
  const onEdit = (targetId, date, content, emotion)=> {
    dispatch({
      type:'EDIT',
      data:{
        id : targetId,
        date: new Date(date).getTime(),
        content,
        emotion,
      }
    })
  }


  return (
    <DiaryStateContext.Provider value={data}>
      <DiaryDispatchContext.Provider 
      value={{
        onCreate, 
        onEdit, 
        onRemove,
      }}
    >
    <BrowserRouter>
      <div className="App">
        <Routes>
          <Route path="/" element={<Home />} />
          <Route path="/new" element={<New />} />
          <Route path="/edit/:id" element={<Edit />} />
          <Route path="/diary/:id" element={<Diary />} />
        </Routes>
      </div>
     </BrowserRouter>
    </DiaryDispatchContext.Provider>
  </DiaryStateContext.Provider>
  );
};

export default App;



//DiaryEditor.js

import { useState, useRef, useContext, useEffect, useCallback } from 'react';
import { useNavigate } from 'react-router-dom';
import { DiaryDispatchContext } from './../App.js';

import MyHeader from './MyHeader';
import MyButton from './MyButton';
import EmotionItem from './EmotionItem';

import { getStringDate } from '../util/date.js';
import { emotionList } from '../util/emotion.js';

const env = process.env;
env.PUBLIC_URL = env.PUBLIC_URL || "";

const DiaryEditor = ({isEdit,originData}) => {
    const contentRef = useRef();
    const [content, setContent] = useState("");
    const [emotion, setEmotion] = useState(3);
    const [date, setDate] = useState(getStringDate(new Date()));

    const { onCreate, onEdit, onRemove } = useContext(DiaryDispatchContext)

    const handleClickEmote = useCallback((emotion) => {
        setEmotion(emotion);
    }, []);

    const navigate = useNavigate();

    const handleSubmit = ()=> {
        if(content.length < 1){
            contentRef.current.focus();
            return;
        }

        if(window.confirm(isEdit ? "일기를 수정하시겠습니까?" : "새로운 일기를 작성하시겠습니까?")){
            if(!isEdit){
                onCreate(date, content, emotion);

            } else{
                onEdit(originData.id, date, content, emotion);
            }
        }

        onCreate(date,content,emotion);
        navigate('/', { replace: true });
    };

    const handleRemove = () => {
        if(window.confirm('정말 삭제하시겠습니까?')){
            onRemove(originData.id);
            navigate('/',{replace:true})
        }
    }

    useEffect(()=>{
        if(isEdit) {
            setDate(getStringDate(new Date(parseInt(originData.date))));
            setEmotion(originData.emotion);
            setContent(originData.content);
        }
    }, [isEdit,originData]);

    return (
         <div className='DiaryEditor'>
         <MyHeader 
         headText={isEdit ? "일기 쓰기" : "새 일기쓰기"} 
         leftChild={
            <MyButton text={"< 뒤로가기"} onClick={() => navigate(-1)} />
         }
         rightChild={isEdit && <MyButton text={"삭제하기"} type={"negative"} onClick={handleRemove}/>
        }
         />
            <div>
             <section>
                 <h4>오늘은 언제인가요?</h4>
                 <div className='input_box'>
                    <input 
                    className='input_date'
                    value={date} 
                    onChange={(e)=>setDate(e.target.value)} 
                    type="date"
                     />
                 </div>
             </section>
             <section>
                <h4>오늘의 감정</h4>
                <div className='input_box emotion_list_wrapper'>
                    {emotionList.map((it) => (
                        <EmotionItem 
                        key={it.emotion_id} 
                        {...it} 
                        onClick={handleClickEmote}
                        isSelected={it.emotion_id === emotion}
                        />
                    ))}
                </div>
             </section>
             <section>
                <h4>오늘의 일기</h4>
                <div className='input_box text_wrapper'>
                    <textarea 
                    placeholder="오늘은 어땟나요"
                    ref={contentRef} value={content} 
                    onChange={(e) => setContent(e.target.value)}/>
                </div>
             </section>
             <section>
                <div className='control_box'>
                    <MyButton text={'취소하기'} onClick={()=> navigate(-1)} />
                    <MyButton text={'작성완료'} type={"positive"} onClick={handleSubmit} />
                </div>
             </section>
            </div>
         </div>
    );
}

export default DiaryEditor;

이정환 Winterlood님의 프로필 이미지
이정환 Winterlood
지식공유자

hwji님 안녕하세요 이정환입니다.
아무래도 모든 파일의 내용을 확인해야 정확한 오류를 찾을 수 있기 때문에 지금 올려주신 코드만으로는 정확한 파악이 어렵습니다
오류의 원인이 올려주신 두 파일(App, Editor)에 존재할 수도 있겠지만 혹여나 아닐 수도 있거든요

코드샌드박스 활용법이 어렵다면 제 메일로 전체 프로젝트 폴더(node_modules는 제거해주세요)를 압축해 보내주세요 그럼 제가 다운로드하고 환경을 설정한 다음 확인해 어떤 부분에 오류가 있는지 정확히 찾아서 알려드릴 수 있을 것 같습니다.

아래 메일 주소로 보내주시면 확인해보겠습니다.

king199777@gmail.com

구글이랑 카카오메일로 보냈습니다

확인해주시면 감사하겠습니다!

대조동이강인님의 프로필 이미지
대조동이강인

작성한 질문수

질문하기