[TIL] 내일배움캠프 React 과정 2022.12.07

Today I Learned

  • 리액트 입문 개인 과제 - My Todo List 만들기
  • 리액트 입문 과제 리뷰 특강 시청

 


My Todo List 구현하기

배열에서 특정 객체의 프로퍼티 값만 수정하기

const [todo, setTodo] = useState([
    {id: 1, title: '운동하기', content: '테스트1', isDone: false},
    {id: 2, title: '마라탕 먹기', content: '테스트2', isDone: false},
    {id: 3, title: '잘 쉬고 공부하기', content: '테스트3', isDone: false},
]);

이 배열에서 투두리스트의 완료 버튼을 눌렀을 때 그 id 값을 가진 객체만 isDone: true로 바꿔주는 것이 내가 구현하고 싶은 것이었다. 이거 해결하느라 오늘 오전 시간 다 쓴 거 같다 ㅎㅎ

 

일단 처음에는 현재 todo 배열의 구조에서 id 값이 3인 객체의 isDone만 수정이 가능한 것인지, 아니면 배열 전체를 setTodo로 수정해야 하는지를 고민했었다. 근데 첫 번째는 도저히 방법을 모르겠어서 두 번째 방법으로 구현하기로 했다.

 

// 기존 원본 데이터
const user = [
    {id : 1, name: '일석', num: '1111' },
    {id : 2, name: '이석', num: '2222' },
    {id : 3, name: '삼석', num: '3333' },
];

// 수정할 데이터
const updateUserDto = {
    id : 2,
    name : '이놈석'
};

// 수정할 데이터와 기존 데이터의 id가 일치하는 것은 user에 updateUserDto를 업데이트하고, id가 일치하지 않으면 기존 user데이터로 나오는 배열을 만들어 newUsers에 담는다.
const newUsers = user.map((user) =>
    user.id === updateUserDto.id ? {...user, ...updateUserDto } : user
);

일단 처음에는이 방법을 사용해보려고 했다.

출처 https://velog.io/@sunkim/React-Array-CRUD-배열의-추가수정삭제#배열의-원소-수정

 

그런데 이렇게 배열의 각 항목 안에 객체가 3개씩 들어가 있는 이상한 구조가 되어버려서 몇 번 더 시도하다가 이 방법은 포기했다.

 

'react 배열 수정' 키워드로 구글링하는데 1페이지에는 다 비슷비슷한 방법만 나와서 몇 페이지 뒤로 넘겨서 다른 방법을 찾아냈다. 그런데 이 방법으로 너무나도 쉽게 해결되었다..!😳

내가 원했던 게 바로 이거야!!

let copy = [...todo]
todo[id - 1].isDone = true;
setTodo(copy);

일단 todo 배열을 spread로 복사한 후에 해당 객체의 isDone 값만 true로 수정한다. 그리고 setState를 이용해서 기존의 todo 배열까지 수정한다.

 

참고 https://ella951230.tistory.com/entry/React-useState-배열-변경방법-spread-문법

 

 

이 문제를 해결하기 위해서 몇 시간 동안 구글의 모든 문서를 다 들어가 보고 코드 수정도 엄청나게 하며 고생했었다 😂

(지금은 지워 버린) 여러 가지 시도했던 흔적들👇🏼

const doneHandler = (id) => {

    const finished = todo.map((list) => list.id);
    console.log(finished) [1, 2, 3]

    const doneTodo = todo.filter((list) => list.id === id);
    const undatedTodo = doneTodo.map((list) => list.id, list.title, list.content)
    const doneTodo = todo[id - 1]
    console.log(doneTodo);

    const donedoneTodo = {
      ...doneTodo, isDone: true,
    }
    console.log(donedoneTodo)

    const newTodo = todo.map((list) => 
      // list.id === donedoneTodo.id ? {...todo, ...donedoneTodo} : todo,
      list.id === doneTodo.id ? {...doneTodo, isDone: true} : todo,
    );
    console.log(newTodo)

    setIsDone(true);

    if (finished.id === id) {
      setIsDone(true)
    }
}

 

 

map 메서드에 에러 메시지

map 메서드에 if문을 넣을 이후로 자꾸 주의 메시지가 떠 있는 게 신경 쓰인다. 일단 기능 구현에는 문제가 없긴 혼자서 검색해 봐도 해결을 못 하겠어서 하지만 이것도 질문할 예정이다.

 

 

컴포넌트 구조

function App () {
  return (
    <div className="wrap">
      <Header />
      <Form />
      <Todo />
      <Done />
    </div>
  );
};

App 컴포넌트 안에 Header, Form, Todo, Done 컴포넌트가 들어가 있는 구조다.

 

 

CSS flex-wrap 속성 이용하기

수정 전
수정 후

카드가 많으면 설정해 둔 width 값을 넘어가 버리는 문제가 발생한다. working 텍스트와 모든 카드를 감싸고 있는 container에 flex-wrap: wrap;를 설정해서 해결했다.

 

flex-wrap 속성이란?

Flex 컨테이너에서 Flex 아이템을 한 줄로 표시할 지, 또는 복수의 행(行)으로 표시할지 여부를 지정한다.

flex-wrap 속성을 설정하지 않으면 기본값인 flex-wrap: nowrap;이 적용된다.

  • wrap: flex 아이템이 flex 컨테이너 안에서 표시되도록 줄 바꿈한다.
  • nowrap: 행(行)의 줄 바꿈을 하지 않고 한 줄로 표시한다.

https://blog.naver.com/pjh445/221160742046

 

 

배열을 수정할 때 id 값을 정렬하는 문제

const [todo, setTodo] = useState([
    {id: 1, title: '운동하기', content: '운동해서 체력 기르기', isDone: false},
    {id: 2, title: '코딩 공부하기', content: '열심히!', isDone: true},
]);
const doneHandler = (id) => {
    let copy = [...todo]
    todo[id - 1].isDone = true;
    setTodo(copy);
};

문제 발견: 기본적으로 작성해 둔 배열에서 working 란에 있던 카드를 하나 삭제하니까 id가 2인 채로 남아서 doneHandler에서 todo[id - 1]로 해당 객체를 가져오던 구조에 문제가 생긴다.

 

배열 안에 객체가 다섯 개인 상태에서 id가 3인 객체를 삭제하면 그 객체만 사라진다. 내가 원하는 것은 id가 3인 객체를 삭제했을 때 id가 1-2-4-5가 아니라 1-2-3-4로 재정렬되는 것이다. 지금 상황에서는 id가 3인 객체를 삭제 후 객체를 추가하려고 하면 key 값이 중복되었다며 에러가 뜬다.

 

id 값에 todo 배열의 길이를 이용해서 동적으로 만들면 어떨까 싶어서 시도했지만 실패했다. 나중에 튜터님께 질문할 예정!

 

 

섬네일 위한 완성본

 


Programmers 알고리즘 문제 풀기

2차원으로 만들기

function solution(num_list, n) {
    let result = [];
    for(i=0; i<num_list.length; i+=n) {
        result.push(num_list.slice(i, n+i))
    }
    return result;
}

팀원 분의 도움으로 제출한 답변. 내가 풀었다고 볼 수는 없지만 코드가 어떤 과정으로 전개되는지는 모두 이해했다. 이렇게 다른 사람의 코드를 분석하면서 익힌 풀이 방법도 하나씩 쌓이면 많은 도움이 될 것이라고 생각한다.

 

var a = [1, 2, 3, 4, 5];
a.slice(0, 3);  // [1, 2, 3]을 반환한다.

이해의 흔적 ㅋㅋ

 

캐릭터의 좌표

function solution(keyinput, board) {
    let start = [0, 0]

    if (Math.abs(start[0]) <= Math.abs((board[0] - 1) / 2) 
        && Math.abs(start[1]) <= Math.abs((board[1] - 1) / 2)) 
    
        for (const key of keyinput) {
            if (key === "left") {
                start[0] = start[0] - 1
            }
            if (key === "right") {
                start[0] = start[0] + 1
            }
            if (key === "down") {
                start[1] = start[1] - 1
            }
            if (key === "up") {
                start[1] = start[1] + 1
            }
    } 
    return start
}

[0, 0]은 board의 정 중앙에 위치합니다. 예를 들어 board의 가로 크기가 9라면 캐릭터는 왼쪽으로 최대 [-4, 0]까지 오른쪽으로 최대 [4, 0]까지 이동할 수 있습니다. -> 이 부분을 어떻게 해야 할지 모르겠다.

 

아주 지저분한 코드를 짜기만 하고 실패했다. if문이 너무 많고.. if문 안에 for문 안에 if문을 넣고 싶은 이상한 구조가 되어버렸다ㅜㅜ 이건 일단 보류.

 

절댓값 구하기

Math.abs(-1) = 1

 


회고

오전부터 열심히 달려서 오후 4시까지 제출해야 하는 과제를 어떻게든 완성은 했다. 겉으로 보기엔 잘 작동하는 거 같아도 자세히 보면 부족한 부분이 많다. 저녁에 다른 분들 코드 리뷰 해주시는 거 보고 비슷한 듯 다른 코드를 보며 재밌기도 했고 참고할 부분도 많았다. 항상 프로젝트나 과제가 끝나면 수정하고 추가 구현하고 싶은 부분이 넘쳐나지만 언제나 그렇듯 시간이 없다. 저번 기초 프로젝트도 수정하고 싶은 부분이 너무 많은데 손도 못 댔다. 

 

그리고 매일 알고리즘 문제를 하나씩 풀어 보려고 노력하고 있는데 너무 어렵다!! 내일은 오늘 제출했던 과제를 수정해야 할지 리액트 숙련 강의를 들어야 될지 모르겠다.