[Front-end] 개발자 공부

[개발 공부 32일차] 앞으로의 공부 방향성 | 개인과제 완료!

MOLLY_ 2024. 2. 5. 20:41
728x90

 

개인과제는 어제 다 끝내서 제출했다.

딱 시작한 날로부터 5일 정도 걸린 것 같다. 하지만 많은 부분을 다른 동기들과 튜터님들께 여쭤보았기 때문에 다시 해보는 필요성이 있겠다 싶었다. 그래서 다시 공부하고 만들어볼 생각이다.

 

 

< 목차 >

1. 수정 기능 및 props drilling 작업 완료

2. 앞으로의 공부 방향성

   - 개발 기획 과정 및 코딩 방법

3. 금일 소감

 

 

 

우선 과제를 하면서 있었던 에러와 해결 과정을 먼저 살펴보자

 

1. 수정 기능 및 props drilling 작업 완료

작성된 팬레터가 없을 때 나올 문구 자리 헤매는 중

 

 

자리를 고민하다가 return 안으로 넣고 letters.map을 감싸는 { }를 풀어줬더니 정상으로 작동함!

 

 

하핫 하하핫

 

 

자리 안착 완료,,

헤맬 때는 '우짜지 우짜지' 싶지만 해결되면 세상 행복한 게 프로그래밍 아닐까요 하핫

 

그럼 이제 다음 해결할 거 가져오세요

 

 

수정 기능 코드 구상편

 

 

 

내가 생각한 수정 로직 및 구상한 코드... 약간 얼토당토 없지만 이런 식으로 하면 되지 않을까? 하며 토도독 짜봤다. 결론적으로는 위 코드 별로 안 쓰고, 새로 다시 코드 짜서 했다.

 

 

"Cannot read properties of undefined (reading 'length')" 에러가 뜸

 

 

위 화면에서 뜨는 에러 때문에 아예 화면에 그려지는 것조차 안 되고 있다.

 

 

"Cannot read properties of undefined(reading 'length')" 에러가 나오는 부분은 letter.content를 처리하는 부분으로 보인다. 에러 메시지에서 'undefined'에 접근하려고 한다고 나와있기 때문에, letter 객체 자체가 undefined 또는 null일 수 있다. 이러한 경우에 해당 객체의 속성에 접근하려고 하면 에러가 발생한다.

에러를 방지하려면 letter 객체가 정의되었는지 확인하고, 그 후에 content 속성에 접근해야 한다. 조건부 렌더링을 사용해 letter가 존재할 때만 해당 내용을 보여주도록 코드를 수정할 수 있다. 그러려면

 

( ) 소괄호로 묶어주었다.

 

해결책!

삼항연산자 : 다음에 나오는 코드 전체를 소괄호로 묶어줘야 한다. 수정한 코드 및 해당 부분 코드 전체는 다음과 같다.

 

 

▼  수정한 코드 및 전체 코드

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

function DetailedPage({ letters, setLetters }) {
    const { id } = useParams()

    const navigate = useNavigate();

    const letter = letters.find(letters => (
        letters.id === id
    ))

    // 삭제 버튼 클릭 (setTodo(deleteTodo); 확실히 이해 필요)
    // 클릭한 id 값에 해당하지 않는 것만 보이게

    // 해야할 것 써보자
    // (1) 인풋 : 삭제 대상 letter의 id
    // (2) 아웃풋 : 필요 없음
    // (3) 프로세스
    //   - window.confirm으로 정말 삭제할건지 물어봄
    //   - false : 취소 처리(아무것도 안함)
    //   - true
    //     - setLetters를 위해서 새로운 배열을 만들어 내야 함
    //     - 새로운 배열 : input에서 준 id에 해당되는 letter가 제외된 리스트 => newLetters
    //     - setLetters(newLetters)

    const goToMainPage = () => {
        navigate("/");
    }

    // 삭제 기능
    const onClickDeleteBtn = (idToDelete) => {
        const wantToDelete = window.confirm("삭제 원하세요?");
        if (wantToDelete) {
            // 삭제 원해요?
            const notWantToDelete = letters.filter(function (letters) {
                if (letters.id !== idToDelete) {
                    // true가 삭제대상아이디가포함안된리스트에 포함되지 않아야 하기 때문에 true?
                    // Main Page로 이동
                    navigate("/")
                    return true;
                } else {
                    // 아무것도 안 해줘야 해서 false
                    return false;
                }
            });
            setLetters(notWantToDelete)
        } else {
            // 삭제 원하지 않음? => 아무것도 할 필요없음
            alert("취소하셨습니다.");
            return;
        }
    }


    //  수정 기능
    const [toggleBtn, setToggleBtn] = useState(false);
    const [editValue, setEditValue] = useState();
    const onClickEditBtn = () => {
        setToggleBtn(true)
    }

    const onClickEditCancleBtn = () => {
        setToggleBtn(false)
    }

    const onchangeEditValue = (e) => {
        setEditValue(e.target.value)
    }

    const onClickEditCompleteBtn = () => {
        setLetters((prevData) => {
            return prevData.map((item) => {
                if (item.id === id) {
                    return { ...item, content: editValue };
                }
                return item;
            });
        })
        setToggleBtn(false);
    };

    // 팬레터 클릭하면 이동되게 해야 함
    return letter ? (
        <div>
            <button onClick={goToMainPage}>Main Page</button>
            <div className="eachLetter">
                {toggleBtn === true ? (<>
                    <textarea
                        defaultValue={letter.content}
                        onChange={onchangeEditValue}
                    />
                </>) : (
                    <>
                        <div>
                            [작성자] {letter.nickname}</div>
                        <div>[작성일시] {letter.createdAt}</div>
                        <div>[내용] {
                            letter.content.length < 50
                                ? letter.content
                                : letter.content.slice(0, 50) + '...'
                        }</div>
                    </>
                )}
                {toggleBtn === true ? (
                    <>
                        <button onClick={onClickEditCancleBtn}>수정 취소</button>
                        <button onClick={onClickEditCompleteBtn}>수정 완료</button>
                    </>
                ) : (
                    <>
                        <button onClick={onClickEditBtn}>수정</button>
                        <button onClick={() => onClickDeleteBtn(letter.id)}>삭제</button>
                    </>
                )}
            </div>
        </div >
    ) : null
}

export default DetailedPage;

 

 

 

팀원분에게 해결됐다는 사실과 해결책을 얘기했다!

 

 

함께 에러 문제를 상의했던 팀원분에게 해결책을 이야기하며 해결됐다는 기쁜 소식을 알렸다! 행복하다.

 

 

 

ChatGPT가 짠 좀 더 깔끔한 코드... 참고만 하자

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

function DetailedPage({ letters, setLetters }) {
    const { id } = useParams();
    const navigate = useNavigate();
    const letter = letters.find((letter) => letter.id === id);

    const goToMainPage = () => {
        navigate("/");
    };

    const onClickDeleteBtn = (idToDelete) => {
        const wantToDelete = window.confirm("삭제 원하세요?");
        if (wantToDelete) {
            const newLetters = letters.filter((letter) => letter.id !== idToDelete);
            setLetters(newLetters);
            navigate("/");
        } else {
            alert("취소하셨습니다.");
        }
    };

    const [toggleBtn, setToggleBtn] = useState(false);
    const [editValue, setEditValue] = useState(letter?.content || "");

    const onClickEditBtn = () => {
        setToggleBtn(true);
    };

    const onClickEditCancleBtn = () => {
        setToggleBtn(false);
    };

    const onchangeEditValue = (e) => {
        setEditValue(e.target.value);
    };

    const onClickEditCompleteBtn = () => {
        if (editValue.trim() === letter.content.trim()) {
            alert("수정사항이 없습니다.");
            return; // 수정 사항이 없는 경우 함수 종료
        }

        setLetters((prevData) => {
            return prevData.map((item) => {
                if (item.id === id) {
                    return { ...item, content: editValue };
                }
                return item;
            });
        });
        setToggleBtn(false);
    };

    return letter ? (
        <div>
            <button onClick={goToMainPage}>Main Page</button>
            <div className="eachLetter">
                {toggleBtn === true ? (
                    <>
                        <textarea
                            defaultValue={editValue}
                            onChange={onchangeEditValue}
                        />
                    </>
                ) : (
                    <>
                        <div>
                            [작성자] {letter.nickname}
                        </div>
                        <div>
                            [작성일시] {letter.createdAt}
                        </div>
                        <div>
                            [내용] {letter.content.length < 50
                                ? letter.content
                                : letter.content.slice(0, 50) + '...'}
                        </div>
                    </>
                )}
                {toggleBtn === true ? (
                    <>
                        <button onClick={onClickEditCancleBtn}>수정 취소</button>
                        <button onClick={onClickEditCompleteBtn}>수정 완료</button>
                    </>
                ) : (
                    <>
                        <button onClick={onClickEditBtn}>수정</button>
                        <button onClick={() => onClickDeleteBtn(letter.id)}>삭제</button>
                    </>
                )}
            </div>
        </div>
    ) : null;
}

export default DetailedPage;

 

 

내 코드 로직상에서는 많이 참고하기 어려웠지만 읽으면서 일부 참고했던 자료는 다음과 같다.

 

1) 수정 기능 구현하는 법

https://velog.io/@damin1025/DiaryApp-%EC%88%98%EC%A0%95%EA%B8%B0%EB%8A%A5-%EA%B5%AC%ED%98%84%ED%95%98%EA%B8%B0

 

2) 리액트 게시판 만들기 - 게시글 등록, 수정, 삭제

https://onethejay.tistory.com/195

 

3) React에서 자주 쓰는 if문 작성패턴 5개

https://codingapple.com/unit/react-if-else-patterns-enum-switch-case/

 

 

2. 앞으로의 공부 방향성

앞으로 공부는 코드를 직접 계속 작성해보는 것 위주로 할 생각이다. 지금까지 이론 위주의 공부를 하고 컴퓨팅적 사고에 대해서 파온 것은 그것 나름대로 추후에 이점이 있고, 분명 시간이 축적될수록 그 효과가 빛을 발할 것이라고 생각한다. 다만 지금 당장은 코드를 매일 작성하지도 않고 또 코드를 복붙 없이 순수하게 내 손으로 코드 짜본 게 거의 전무해서, 앞으로는 코드를 일기처럼 매일 작성하고 1일 다 push를 하는 것을 목표로 할 생각이다. 요즘 코드를 정말 많이 작성해 보는 게 중요하다는 걸 엄청 강하게 체감한다..

 

 

그리고 개발은 기획 단계를 먼저 거치고 프로그래밍에 착수한다.

그래서 기획이 중요한데, 이번 개인과제에서는 구현해야 할 필수 기능이 많다고 생각해서 구체적인 기획과 생각 없이 진행했다. 이게 방향 설정도 잘못되고 버린 시간이 많았어서 앞으로는 기획을 꼼꼼하고 자세하게 한 이후에 코딩에 들어갈 생각이다.

 

챌린지 반 분들은 개발 과정이 거의 나와 비슷했지만 더 자세하고 구체적이었다. 그 내용을 좀 정리하고 나도 적용해서 코딩할 생각이다.

 

 

[왼쪽] 이상적인 기획 [오른쪽] 현실

 

 

개발 기획 과정 및 코딩 방법

  1. 만들고자 하는 게 무엇인지 작성
  2. 필수 요구사항을 '우선순위'별로 정리해서 작성한다.
  3. 종이에다가 와이어프레임을 구체적으로 작성한다. (예시 디자인이 있을 경우, 보면서 페이지가 어떻게 구성돼있고 나뉘어져 있는지 확인)
  4. 어떤 기능이 들어갈 것인지 적는다.
  5. 페이지별 & 기능 단위로 어떤 컴포넌트, 상태가 필요할지 자세하게 작성한다.
  6. 공통된 요구사항과 상위/하위 단위로 요구사항을 묶는다.
  7. 동적 데이터, 정적 데이터를 분류하여 자료구조를 결정(array, object - arrary)
  8. 구현하기 위해서 어떤 기술이 필요할지 판단
  9. 동적 데이터의 동기/비동기 타입 결정 (backend API에서 받아와야 하면 비동기 type, 본인이 계산하면 되면 동기 type)
  10. 의사 코드를 넘버링해가며 작성한다. 넘버링 좌측에는 참고할 자료를 적는다.
  11. 최소한의 HTML과 CSS 적용
  12. 너무 막히면 기존의 소스 참고
  13. state의 위치 고민 후, 적용 (해당 페이지에서만 사용하면 지역상태... 등)
  14. Error 수정 → 잔체적인 CSS 수정
  15. 테스트 → 변경 →  튜터님들께 피드백 받기 →  수정하여 완성

 

 

* 정적 데이터

: 어디서 안 받아와도 되는 data

안 건들여도 됨

 

* 동적 데이터

: 어디서 받아와야 하는 data

User event로 상태를 건들여야 함. 상태 가지고 계산 가능함 (ex. map, filter 등)

 

 

 

3. 금일 소감

위에서 적은 것처럼 앞으로는 최대한 코드를 많이 작성해보고 매일 GutHub에 push하며 코딩을 할 생각이다. 코딩 일기 버전이라고 생각하면 더 직관적으로 와닿을 것 같다. 일반적인 작문은 지금껏 워낙 많이 해왔고 정말 매일 하였기에 웬만큼 괜찮게 하는 것 같은데 코딩은 생각해 보니 예문 긁어오고 기존 코드 보면서 따라 작성한 것 외에는 나 혼자 아무것도 안 보고 작성한 적인 단 한 번도 없는 것 같다.

 

이렇게 너무 무의식적으로 직접적인 코드 작성은 안 하고 있다는 걸 이번 주말을 통해서 깨달았다. 그래서 정말정말 많이 코드를 짜보고 에러도 마주쳐보고 왜 안 되는지 계속 혼자 좀 고민해보는 게 중요하겠다 싶다. 내일까지는 개인과제 디벨롭하는 기간이라 최대한 이 기간을 활용해, 그동안 했던 과제 다시 해보면서 코드 처음부터 작성해서 내 손으로 과제 완성해야겠다.

 

 

728x90