본문 바로가기
Front-end/클론코딩

2024 동계 모각코 5회차 활동정리

by 잔디🌿 2024. 1. 28.

     
    함수 이름 바꾸기
    데이터 수정하기
    코드보기
     

    함수 이름 바꾸기

    위와 같이 삭제를 의미하는 onDelete함수의 이름을 onRemove로 바꾸려고 한다.
     

    이 때 함수 이름만 바꾸고, 전달하려는 prop이름은 그대로 두면 에러가 발생한다. diaryList에 전달할 prop인 onDelete가 없어졌기 때문이다. 따라서 밑에 prop부분도 바꾸어야 한다.
     

     

    이에 따라 onDelete를 prop로 받는 컴포넌트들의 코드들도 바꿔주어야한다.
     

    데이터 수정하기

    DiaryItem컴포넌트에서 위와 같이 수정하기 버튼을 만든다.
     

    위와 같이 삭제하기 버튼을 누르면 onclick내의 함수가 수행되는데 이를 가독성이 좋게 하기 위해서 함수를 위에 따로 만들고자 한다.
     

    그래서 위와 같이 handleRemove를 만들고 onClick에 넣어두었다.
     
    DiaryItem에서 state와 레퍼런스를 사용하기 때문에 관련해서 import 한다.

     
     
    그 다음 일기장의 내용을 나타내는 content 부분을 수정한다.
     

     
     isEdit는 현재 사용자가 수정중인지를 의미하는 state이다.
    false이면 수정중이 아니기 때문에 원래 화면을 띄워야 하고, 아니라면 수정화면을 띄워야한다. 기본값은 false이다.
     

    위 함수는 isEdit 상태를 반대로 바꾸는 함수이다.
     

    localcontent state는 수정하는 화면을 위한 state이다. 기본 값은 content로 함으로서 수정버튼을 누르면 기존 내용이 화면에 뜨도록 한다.
    또한 기존 일기 내용을 입력할 때와 같이, 수정한 내용이 5자 이내이면 focus를 하도록 하기 위해 레퍼런스를 하나 만들었다.

    이제 수정버튼을 누르면 content부분이 수정 가능하도록 바뀌게 해야한다.
    이는 삼항연산자로 구현하였다. 만약 false라면 content를 그대로 띄우고, 아니면 수정 가능한 textarea를 띄운다. 이 때 값은 localContent를 띄우고, 레퍼런스를 넣는다. 그 다음 값이 바뀔 때 onchange부분을 통해 localcontent에 해당하는 값을 업데이트한다.
     

    그 다음 버튼 부분을 수정한다. 수정화면에서는 수정취소와 수정완료 버튼이 떠야 한다. 이 부분 역시 삼항연산자로 구현하였다. 또한 각 버튼을 눌렀을 때 실행되어야 할 함수를 넣었다.
     
    <수정 취소> 

    handleQuitEdit는 수정 취소를 눌렀을 때 실행된다. 수정 -> 수정취소 -> 수정 버튼을 차례로 눌렀을 때 수정하는 부분에 수정하던 내용이 아닌, 원래 내용이 뜨도록 한다.
     
    <수정 완료>

    handleEdit는 수정완료 버튼을 누르면 실행된다. 
    수정 완료 버튼을 누른 시점의 localContent state의 길이가 기준을 넘지 않으면 focus하고, 넘는다면 다시 한번 사용자의 의사를 묻는 화면을 띄운 후 동의하면 onEdit를 통해 수정하고, isEdit의 상태를 바꾼다.
     
    이때 onEdit는 데이터가 있는 App.js에 넣어야 한다. 따라서 이 곳에 함수를 선언한 후 , props를 통해 받아야한다.
     

    app.js

    App.js이다. 이 곳에 onEdit함수를 넣었다. 이 함수는 id와 새로운 내용을 매개변수로 받는다 이 후 map를 통해 데이터를 수정한다.
     

    app.js

    그 다음 DiaryList 컴포넌트에 onEdit함수를 보내는 부분을 추가한다.
     

    DiaryList.js

    그리고 DiaryList.js에서 받은 props를 다시 DiaryItem에 보내는 과정을 추가한다.
     

    DiaryItem.js

    마지막으로 DiaryItem에 onEdit를 추가한다.
    이렇게 해서 DiaryItem에서 onEdit를 사용할 수 있게 되었다.
     
     

     

    이렇게 수정하기 기능이 완성되었다.

    코드 

    app.js

    import { useRef,useState } from 'react';
    import './App.css';
    import DiaryEditor from './DiaryEditor';
    import DiaryList from './DiaryList';
    
    // const dummyList = [
    //   {
    //     id : 1,
    //     author : "잔디",
    //     content : "안녕",
    //     emotion : 5,
    //     created_date : new Date().getTime(),
    //   },
    //   {
    //     id : 2,
    //     author : "풀",
    //     content : "안녕하이",
    //     emotion : 2,
    //     created_date : new Date().getTime(),
    //   },
    //   {
    //     id : 3,
    //     author : "리액트",
    //     content : "안녕안녕",
    //     emotion : 1,
    //     created_date : new Date().getTime(),
    //   },
    // ]
    
    
    const App = () =>{
      const [data, setData] = useState([]); //data state를 만든다.
    
      const dataId = useRef(0);
    
      const onCreate = (author,content,emotion) =>{
        const created_date = new Date().getTime();
        const newItem = {
          author,
          content,
          emotion,
          created_date,
          id : dataId.current,
        }; //데이터 추가하는 부분
        dataId.current += 1;
        setData([newItem,...data]);//최근 것이 먼저 오도록 하기 위해 ...data보다 앞에 쓴다.
    
      };//state에 데이터를 계속 추가해나간다.
    
      const onRemove = (targetId) => {
        const newDiaryList = data.filter((it) => it.id !== targetId);
        //target 빼고 출력하기 위해서
        setData(newDiaryList); //이걸 다시 데이터에 넣는다.
      };
      
      const onEdit = (targetId,newContent) =>{
        setData(
          data.map((it) => it.id === targetId ? {...it, content : newContent} : it)
        );
      }; //데이터를 수정하는 함수이다. map함수를 사용하고 it의 아이디가 받은 아이디와 비슷하다면 나머지는 다 원래대로 하고, 
      //content만 newContent로 바꾼다.
    
      return (
        <div className="App">
          <DiaryEditor onCreate = {onCreate}/>
          <DiaryList  onEdit = {onEdit} diaryList = {data} onRemove = {onRemove}/> 
        </div>
      );// diarylist는 일기 리스트. data를 전달한다.
    }
    
    export default App;

     
     
    DiaryItem.is

    import {useState} from "react";
    import { useRef } from "react";
    
    const DiaryItem = ({
        onEdit,
        onRemove,
        id,
        author,
        content,
        emotion,
        created_date
    }) =>{
    
        const [isEdit,setIsEdit] = useState(false); 
        //수정중인지를 확인하기 위해서 state를 만든다. 기본값 false
        const toggleIsEdit = () => setIsEdit(!isEdit);
         //toggleIsEdit를 호출하면 isEdit를 반대인 상태로 바꾼다.
    
        const[localContent, setLocalContent] = useState(content);
         //수정하는 화면을 위한 state, 기본값을 content로 함으로써 수정할 때 원래 값이 화면에 뜨도록 한다.
    
         const localContentInput = useRef();
         //5자를 넘기지 못했을 때 focus를 하기 위한 레퍼런스이다.
    
    
        const handleRemove = () =>{
            if(window.confirm(`${id}번째 일기를 정말 삭제하시겠습니까?`)){
                onRemove(id);
            }
        };
    
        const handleQuitEdit = () =>{
            setIsEdit(false);
            setLocalContent(content);
            //이 함수는 수정 취소를 눌렀다가 다시 수정버튼을 눌렀을 때, 
            //과거 수정 중이던 내용이 뜨는 것이 아니라, 원래 값이 뜨도록 하는 함수이다.
        }
    
        const handleEdit = () =>{
            if(localContent.length<5){
                localContentInput.current.focus(); //레퍼런스 통해서 포커스해준다.
                return;
            }
    
            if(window.confirm(`${id}번 째 일기를 수정하시겠습니까?`)){
                onEdit(id, localContent);//실제 수정과정
                toggleIsEdit(); //원래 화면으로 되돌린다.
    
            } 
        };
    
        return <div className="DiaryItem">
            <div className="info">
                <span> 작성자 : {author} | 감정점수 : {emotion}</span>
                <br></br>
                <span className="date">{new Date(created_date).toLocaleDateString()}</span>
            </div>
            <div className="content">
                {isEdit ? (<>
                <textarea
                  ref = {localContentInput}
                  value = {localContent}
                  onChange = {(e) => setLocalContent(e.target.value)}/>{/*state를 사용하여 수정한다*/}
                </>) : (
                <>{content}</>
                )}</div> {/*삼항연산자로, isEdit의 상태에 따라 content를 띄울지 수정화면을 띄울지 결정한다.*/}
    
                {isEdit ? (
                    <>
                    <button onClick = {handleQuitEdit}>수정취소</button>
                    <button onClick = {handleEdit}> 수정완료 </button>
                    </>
                ) :
                (
                    <>
                     <button onClick = {handleRemove}> 삭제하기 </button>
                    <button onClick = {toggleIsEdit}>수정하기</button>
                    </>
                )}{/*수정을 하는 도중에는 밑 부분에 있는 버튼이 바뀐다.*/}
           
        </div>
    }
    
    export default DiaryItem;

     
     
    DiaryList.js
     

    import DiaryItem from './DiaryItem'
    
    const DiaryList = ({onEdit, onRemove,diaryList}) =>{
        
        return (<div className="DiaryList">
            <h2>일기 리스트</h2>
            <h4>{diaryList.length}개의 일기가 있습니다.</h4>
            <div>
                {diaryList.map((it) => (
                   <DiaryItem key = {it.id} {...it} onEdit = {onEdit} onRemove = {onRemove}/>
                ))} 
            </div>
        </div>
        ); //key는 그냥 써야 하는 거다. DiaryList에서 따로 받을 변수를 지정해두지 않아도 괜찮다.
    }; //다이어리아이템 컴포넌트로 위 내용을 사용한다.
    
    DiaryList.defaultProps = {
        diaryList : [],
    };
    
    export default DiaryList;