so woon!

[REACT] 클릭시 카테고리 바꾸기1 본문

ReactJS/개념정리

[REACT] 클릭시 카테고리 바꾸기1

xowoony 2023. 4. 19. 16:00

학습일 : 2023. 04. 19


이번 글에서는
사용자들이 버튼을 이용해서

 toDo의 카테고리를 바꿀 수 있는 기능을 추가해보고자 한다.

 


그리고 toDo의 카테고리에 따라서 알맞는 버튼만 보이게 할 것이다.

카테고리를 받아오고, 카테고리가 "DOING" 이 아닐 때만
DOING 버튼을 보여주도록 조치한다.

import { IToDo } from "./atoms";

function ToDo({ text, category }: IToDo) {
  return (
    <li>
      <span>{text}</span>
      <button>TODO</button>
      {category !== "DOING" && <button>Doing</button>}
      <button>Done</button>
    </li>
  );
}

export default ToDo;




아래에도 똑같이 해주겠당.

import { IToDo } from "./atoms";

function ToDo({ text, category }: IToDo) {
  return (
    <li>
      <span>{text}</span>
      {category !== "TODO" && <button>TODO</button>}
      {category !== "DOING" && <button>DOING</button>}
      {category !== "DONE" && <button>DONE</button>}
    </li>
  );
}

export default ToDo;




실행시켜보면
등록한 리스트는 TODO 카테고리에 있기 때문에

TODO 버튼은 안뜨고
DOING, DONE 버튼만 뜨게 된다.

 


 

이번에는 toDo의 카테고리를 바꾸는 함수를 만들 차례이다.
함수 하나로 해결할 수 있는데
이름을 onClick으로 지어주겠다.

이 함수를 호출할 때, 특정한 카테고리를 인자로 받고 싶다.
예를 들자면, 어떤 사용자가 DOING 버튼을 클릭하게되면,

인자를 통해서 DOING 버튼이 클릭이 되었다는 것을 알고 싶다는 의미이다.

 


이름을 newCategory로 설정하고 이 함수를 세 버튼의 onClick 함수로 설정하고자 한다.


각각 TODO, DOING, DONE 을 적어주어 인자가 있는 onClick event 처리를 해준다.
그냥 onClick={onClick} 이라고 해주면 인자가 넘어가지 않음



<ToDo.tsx>

import { IToDo } from "./atoms";

function ToDo({ text, category }: IToDo) {
  // newCategory가 IToDo의 category 항목이라는 것을 알려줌
  const onClick = (newCategory: IToDo["category"]) => {
    console.log("i wanna to ", newCategory); // 콘솔에 찍어보면
  };

  return (
    <li>
      <span>{text}</span>
      {category !== "TODO" && (
        <button onClick={() => onClick("TODO")}>TODO</button>
      )}
      {category !== "DOING" && (
        <button onClick={() => onClick("DOING")}>DOING</button>
      )}
      {category !== "DONE" && (
        <button onClick={() => onClick("DONE")}>DONE</button>
      )}
    </li>
  );
}

export default ToDo;





실행결과

 

 

 


조금 다른 방법으로 해보면,
newCategory가 IToDo의 category 항목이라는 것을 알려줌
const {currentTarget:{name}} = event; 를 적어주어
currentTarget으로 이벤트를 발생시킨 버튼의 name을 잡아주면 된다.

다음으로는 toDo를 수정하는 부분을 해볼텐데
id가 있기 때문에 어떤 toDo를 수정해야 하는지 이미 알고 있기 때문에 편하다.
function ToDo({ text, category, id }: IToDo)
id를 적어 추가해준다

이젠 atom을 수정 가능하게 해주어야 할 것이다.
전에 했던 방식처럼 useSetRecoilState을 사용하면 된다.
따라서 setToDos라는 이름으로 만들어주겠다

 


<ToDo.tsx>

import { useSetRecoilState } from "recoil";
import { IToDo, toDoState } from "./atoms";

function ToDo({ text, category, id }: IToDo) {
  const setToDos = useSetRecoilState(toDoState);
  const onClick = (event:React.MouseEvent<HTMLButtonElement>) => {
    const {currentTarget:{name}} = event;
  };

  return (
    <li>
      <span>{text}</span>
      {category !== "TODO" && (
        <button name="TODO" onClick={onClick}>TODO</button>
      )}
      {category !== "DOING" && (
        <button name="DOING" onClick={onClick}>DOING</button>
      )}
      {category !== "DONE" && (
        <button name="DONE" onClick={onClick}>DONE</button>
      )}
    </li>
  );
}

export default ToDo;





다음으로 살펴볼 것이 있는데,

<ToDoList.tsx>
toDos를 console.log 해보면
  console.log(toDos);



이런 결과가 나오는데
index 2번 TODO의 카테고리를 변경시켜보도록 하자!


카테고리를 바꾸기 위해서
state를 mutate하면 안되며, 우리는 새로운 state를 만들어야 한다.

일단 개발자도구에 뜬 마지막 object를 우클릭 후 카피 해준 다음



ToDo.tsx에 붙여넣어서 잘 살펴보면
1.  우리는 id로 TODO를 찾아야 함을 알게 될 것이다.
2. 두번째로는 TODO의 index를 알면 된다.
3. 결국 우리는 이 array 안에 있는 object의 index를 찾는 방법만 알면 되는 것이다.

확인했으니 잘 지워주고



수정하고자 하는 to do의 경로를 찾아보자
그러기 위해 먼저 setToDos를 해줄 것이다.
setToDos를 사용하면 값을 즉시 변경할 수 있고, 
현재 값 또는 oldToDos를 argument로 주는 함수를 만들 수 있다.
타겟의 현재 경로를 받아야 하므로
oldToDos를 받아서 그냥 다시 리턴하는 함수를 만들어준다

(이 경우엔 같은 state를 유지하기 때문에 re-render가 일어나지 않는다.)
findIndex 안에서는 조건을 만족하는 to do의 index를 찾아 줄 것이다.
toDo의 id와 props에서 오는 id가 같은지 비교해주면 된다.

<ToDo.tsx>

import { useSetRecoilState } from "recoil";
import { IToDo, toDoState } from "./atoms";

function ToDo({ text, category, id }: IToDo) {
  const setToDos = useSetRecoilState(toDoState);
  const onClick = (event: React.MouseEvent<HTMLButtonElement>) => {
    const {
      currentTarget: { name },
    } = event;

   // setToDos
   setToDos((oldToDos) => {
    // toDo의 id와 props에서 오는 id가 같은지 비교
   // 여기서 oldToDos의 array를 받아오고 있고 이 array에서 toDo의 index를 찾기 위해
   // toDo의 id가 props에서 온 id와 같은지 비교하고 있다.
    const targetIndex = oldToDos.findIndex(toDo => toDo.id === id)
     return oldToDos;
   });
 };

  return (
    <li>
      <span>{text}</span>
      {category !== "TODO" && (
        <button name="TODO" onClick={onClick}>
          TODO
        </button>
      )}
      {category !== "DOING" && (
        <button name="DOING" onClick={onClick}>
          DOING
        </button>
      )}
      {category !== "DONE" && (
        <button name="DONE" onClick={onClick}>
          DONE
        </button>
      )}
    </li>
  );
}

export default ToDo;





실행결과

 

 

이렇게 우리는 이제 taget의 경로를 찾게 되었다.

첫번째 단계는 끝났다.

 

 

다음으로 해야할 것은

우리는 기본적으로 to do를 만들어서

원래의 to do를 업데이트 해야한다.

따라서 우리는 새 카테고리로 새로운 to do를 만들어야 한다.

 

oldToDo를 만들고

const oldToDo = oldToDos[targetIndex];

 

newToDo도 만들어 보자

newToDo는 object가 될 것이고 기존의 to do와 똑같은 props를 가지게 될 것이다.

text:text 이렇게 써주지 않아도 된다.

위에서 받은 text, id 를 써주고,  category는 조금 다르게 써주어야 하는데

위 props에서 온 category 가 아니라 클릭된 버튼의 카테고리를 가져야 하기 때문에

category: name 이라 써주면 된다.

 

const newToDo = {text, id, category: name};

 

 

oldToDo와 newToDo를 console에 찍어보면

뒤에나오는 newToDo는 내가 클릭해준 버튼의 상태대로 정상적으로 바뀜을 볼 수 있다.

 

 

 

 

 

'ReactJS > 개념정리' 카테고리의 다른 글

[REACT] Drag and Drop1  (0) 2023.04.25
[REACT] 클릭시 카테고리 바꾸기2  (1) 2023.04.20
[REACT] Refactoring  (0) 2023.04.19
[REACT] todolist 만들기  (0) 2023.04.18
[REACT] useRecoilState 사용하기  (0) 2023.04.18
Comments