1.13- React masterClass (trello cloning final)

hun2__2·2022년 1월 13일
0

Have a fruitful vacation

목록 보기
17/24

먼저 해야할 작업을 정리해보자

  1. user의 입력을 받아 card를 만들 수 있는 form을 작성한다.
  2. user의 입력을 받을 수 있게 atom state를 수정한다.
  3. card를 수정/삭제 할 수 있는 기능을 추가해 준다.
  4. user의 입력을 받아 board를 만들 수 있는 form을 작성한다.
  5. board를 수정/삭제 할 수 있는 기능을 추가해 준다.

react-hook-form을 이용해서 input을 받을 수 있는 form을 만들어보자
card를 만들 수 있는 input과 board를 만들 수 있는 input이 필요하다.

먼저 card input에 필요한 값은 내용을 담은 text: string, card의 고유값이 될 id가 있다. id로는 만만한 new Date()로 작성시간을 고유값으로 만들자.
board input에는 boardName : string이 추가될 것이다.
그러면 atom state에 {text: '', id : Date()값} 이들어간 obj가 들어가게 될 것이다.

이제 card form을 만들어보자

Trello.tsx

const [test, setTest] = useState<string>();
cosnt {register, setValue, handleSubmit} = useForm()
const onVlaid = ({addList} : IForm) =>{
	setTest(addList)
    setValue("addList", "")
}

return(
	   ...
      <Form onSubmit={handleSubmit(onValid)}>
        <input
          {...register("addList", { required: "text를 입력해주세요" })}
          type="text"
          placeholder={`${boardId}에 추가하기`}
        />
        <button>add</button>
      </Form>
      {console.log(test)}
      ...
)


입력을 잘 받아오는것을 확인하고 이제 입력받은 값을 atom state에 추가할 수 있게 변경해준다.

먼저 atom state에 추가를할 값을 만들어보면

TrelloBoard.tsx

  const setBoard = useSetRecoilState(toDoState);
  const { register, setValue, handleSubmit } = useForm();
  const onValid = ({ addList }: IFrom) => {
    setBoard((oldBoard) => {
      const copyBoard = [...oldBoard[boardId]];
      const addCard = { id: Date.now(), text: addList };
      console.log(addCard);
      const newBoard = [copyBoard, addCard];
      console.log(newBoard);
      return oldBoard;
    });
    setValue("addList", "");
  };

이렇게 {id :number, text : string}인값을 넣어줄 것이다.
하지만 console을찍어보면 이렇게 넣어주면 error가 나올 것을 예상하게된다( type이 다름)

따라서 먼저 atom의 type을 변경해준다.

value 값이 바뀜에 따라 우리가 정했던 state의 타입이었던 IToDoState와 맞지않게 되고 error가 난다.

type을 수정해주면

아래 error가 해결되었다! 이제 될까?
어림도 없지

이제부터 시작이다.. type을 바꿔주면서 그전에 atom state값을 array로서 참조되었던 곳들을 모두 수정해줘야한다.

먼저 하나하나씩 고쳐나가보자
componenet의 구조가

Trello
- TrelloBoard
- DragabbleCard

구조이므로

첫번째 type error는

ICard타입을 기대하는 board에 string타입인 dragItem 값이 들어간 것이다.
이전에는 바로 string 값을 atom state의 board 배열에 추가해주었지만 추가해주는 형식이 obj형식으로 바뀌었다.
따라서

기존의 코드에서
Trello.tsx

      //! 같은 board내에서 움직일 때
      setList((oldObj) => {
        const board = [...oldObj[dragItemId]];
        board.splice(dragItemIdx, 1);
        board.splice(dropItemIdx, 0, dragItem );
        return { ...oldObj, [dragItemId]: board };
      });

dragItem(string값) 대신 새롭게 해당하는 값인 board[dragItemIdx](obj값) 을 넣어줘야 한다.

      //! 같은 board내에서 움직일 때
      setList((oldObj) => {
        const board = [...oldObj[dragItemId]];
        const dragcard = board[dragItemIdx];
        board.splice(dragItemIdx, 1);
        board.splice(dropItemIdx, 0, dragcard);
        return { ...oldObj, [dragItemId]: board };
      });

다른 board로 움직일때도 동일하게 drop값을 변경해주면

      //! 다른 board로 움직일 때
      setList((oldObj) => {
        const drag = [...oldObj[dragItemId]];
        const drop = [...oldObj[dropItemId]];
        const dragcard = drag[dragItemIdx];
        drag.splice(dragItemIdx, 1);
        drop.splice(dropItemIdx, 0, dragcard);
        return { ...oldObj, [dragItemId]: drag, [dropItemId]: drop };
      });

type error가 해결되었다.

그 다음 error는 list는 string[] 값을 받아오기를 기대하는데 ICard[] type을 넘겨준다는 error가 나온다

TrelloBoard 쪽에서 list의 type을 변경시켜주면

interface IBoardProps {
  list: string[];
  boardId: string;
}

=>

interface IBoardProps {
  list: ICard[];
  boardId: string;
}

이제 Trello쪽에서 TreeloBoard로 보내주는쪽 error는 모두 해결되었다.
이제 list에는 [{id: number, text: string}, {id: number, text: string}, ... ] 값들이 들어가므로 Card쪽에 보내주는 값에 error가 나게된다.

바뀐 값에맞게 card에 새로 atom state를 prop로 넘겨주고
card에서도 ICard를 상속받은 type으로 prop를 받아온다.

TrelloBoard.tsx

...
            {list.map((toDo, index) => (
              <DragabbleCard key={index} index={index} toDo = {toDo}/>
            ))}
...

=>

...
            {list.map((toDo, index) => (
              <DragabbleCard key={index} index={index} {...toDo}/>
            ))}
...

DragabbleCard.tsx

interface IDragabbleCardProps {
  toDo: string;
  index: number;
}

function DragabbleCard({ toDo, index }: IDragabbleCardProps) {
  return (
    <Draggable key={toDo} draggableId={toDo} index={index}>
      {(provided, snapshot) => (
        <Card
          ref={provided.innerRef}
          {...provided.dragHandleProps}
          {...provided.draggableProps}
          isDragging={snapshot.isDragging}
        >
          <p>🥱 {toDo}</p>
        </Card>
      )}
    </Draggable>
  );
}

=>

...
interface IDragabbleCardProps extends ICard{
  index: number;
}

function DragabbleCard({ index, id, text }: IDragabbleCardProps) {
  return (
    <Draggable key={id} draggableId={id+''} index={index}>
      {(provided, snapshot) => (
        <Card
          ref={provided.innerRef}
          {...provided.dragHandleProps}
          {...provided.draggableProps}
          isDragging={snapshot.isDragging}
        >
          <p>🥱 {text}</p>
        </Card>
      )}
    </Draggable>
  );
}

따라서 {...toDo}를 prop로 넘겨주며 card쪽에서 받아오는값의 type에 ICard를 상속받아오면
TrelloBoard 에서 DragabbleCard로 넘겨주는쪽 error는 모두 해결되었고,
Card에서 ICard안에있는 값인 id, text를 사용해서 띄워주면 모든 error가 해결되었다!!

모든 type error가 수정되었으니 다시 TrelloBoard에서 atom state에 추가할 값을 설정해주자
TrelloBoard.tsx

  const onValid = ({ addList }: IFrom) => {
    setBoard((oldBoard) => {
      const addCard = { id: Date.now(), text: addList };
      return { ...oldBoard, [boardId]: [addCard, ...oldBoard[boardId]] };
    });
    setValue("addList", "");
  };

이제 레거시 data를 모두 없애고 input으로 추가해보자ㅎㅎ

와우! 드디어 정상작동한다!!


하면서 또한번 TS에게 감사한점이 JS로 짰다면..? 이거를 일일이 다 확인하기 너무 빡셋을 것이다.
귀찮다고 불평하지 말고 감사히 살자ㅜㅜ
componenet 구조대로!! 변경된 초기값부터 하나씩차근차근 고쳐나가면 된다!!!

뭔가 뿌듯하다ㅠㅠ TS가 조금씩 익숙해지고 있다ㅠㅠ

이제 이전에 배운것을 이용해서 card를 없애보자!
어떻게 없애야 할까?
먼저 card component에서 해당 card를 atom state에서 지워주도록 로직을 짠다

어떤 card 인지 알아야 함으로 boardId를 prop로 추가해주고 이동할때와 비슷하게 로직을 짜주면된다!
TrelloBoard.tsx

...
            {list.map((toDo, index) => (
              <DragabbleCard
                key={index}
                index={index}
                {...toDo}
                boardId={boardId}
              />
            ))}
...

DragabbleCard.tsx

interface IDragabbleCardProps extends ICard {
  index: number;
  boardId: string;
}
...
  //! card delete
  const onClick = () => {
    setState((oldObj) => {
      const newBoard = [...oldObj[boardId]];
      newBoard.splice(index, 1);
      return { ...oldObj, [boardId]: newBoard };
    });
  };
  ...
  return(
  	...
            <Card
          ref={provided.innerRef}
          {...provided.dragHandleProps}
          {...provided.draggableProps}
          isDragging={snapshot.isDragging}
        >
          <p>🥱 {text}</p>
          <button onClick={onClick}>del</button>
        </Card>
  )
...


바로 완성! 수정을 위해서는 form을 만들어줘야하니 나중으로 미루고
먼저 board도 추가할 수 있도록 바꿔보자!

위와 동일한 로직으로 form을 만들어주고 input값을 받아와서 atom state에 [key:string] : ICard[] type에 맞게 넣어준다!!
Trello.tsx

...

  // ! board add
  const {
    register,
    setValue,
    handleSubmit,
    formState: { errors },
  } = useForm();

  const onValid = ({ newBoard }: INewBoard) => {
    console.log(newBoard);
    setList((oldObj) => {
      const copyObj = { ...oldObj };
      return { ...copyObj, [newBoard]: [] };
    });
    setValue("newBoard", "");
  };
...
        <form onSubmit={handleSubmit(onValid)}>
          <input
            {...register("newBoard", {
              required: "board의 이름을 입력해주세요",
            })}
            type="text"
            placeholder="새로운board 추가하기"
          />
          <button>add</button>
        </form>

마지막으로 board를 지워보자 card 지우는 것과 비슷한 로직으로 짜주면된다.
TrelloBoard.tsx

...
  // ! board delete
  const deleteBoard = () => {
    setBoard((oldObj) => {
      const newObj = { ...oldObj };
      delete newObj[boardId];
      return newObj;
    });
  };
...
      <Error>{errors?.addList?.message}</Error>
      <Form onSubmit={handleSubmit(onValid)}>
        <input
          {...register("addList", { required: "text를 입력해주세요" })}
          type="text"
          placeholder={`${boardId}에 추가하기`}
        />
        <button>add</button>
      </Form>

이제 card,board를 추가/삭제 해줄 수 있다ㅠㅠㅠㅠ엉엉 신기하고 재밌다ㅠㅜ


ps.
오늘 신나서 TS를 하다보니 파이썬 챌린지를 안했다.
빨라끝내자,,,,후딱후딱 그리고 몇시에 자던, 오후에 조금 더 자던

기상은 5시30분으로 고정이다. 명심해라!

profile
과정을 적는 곳

0개의 댓글