TRELLO Clone #6 Code challenge

Leesu·2022년 12월 8일
0

Code challenge

  • 목표
  1. 스타일 꾸미기
  2. 작성한 모든 toDo 를 localStroage 에 저장 및 로드하기
  3. 작성한 toDo 삭제하기
  4. 새로운 보드 생성하기
  5. 보드 삭제하기

(보너스)보드끼리도 순서 바꾸면 대박!

  • 스타일꾸미기는 중간중간 코드짜면서 손봐줄 예정이라~ 패스~

2. 작성한 모든 toDo 를 localStroage 에 저장 및 로드하기

  • 처음에는, atom.tsx 에 const useLocalStroage = localStroage.setItem(...) 이런식으로 함수를 만들어서, 값이 업데이트되는 곳에 다 넣어줬는데
    하다보니 이렇게 하면 값을 불러올때 어쩌냔 생각이 확 들기 시작함;;; 일일이 넣는게 맞나 싶고.......
  • 생각해보면 atom 은 한개인데, 이 atom 을 가지고는 안되나?는 생각에 구글링해보니
    엄청난 훅이 있었다!!!!!!!!!!!
  • 공식문서참고글
  • 공식문서에서 적으라는 데로 적었더니;; 완성됨...... 베리굿
const localStorageEffect =
  (key: string) =>
  ({ setSelf, onSet }: any) => {
    const savedValue = localStorage.getItem(key);
    if (savedValue != null) {
      setSelf(JSON.parse(savedValue));
      // 연결된 atom의 값을 초기화 해주는 함수
    }

    onSet((newValue: any, _: any, isReset: boolean) => {
      // atom의 값이 변경이 되었을 때 실행되는 함수
      isReset
        ? localStorage.removeItem(key)
        : localStorage.setItem(key, JSON.stringify(newValue));
    });
  };

export const toDoState = atom<IToDoState>({
  key: "toDo",
  // 로컬스토리지에 저장되는 key값
  default: {
    "To Do": [],
    Doing: [],
    Done: [],
  },
  effects: [localStorageEffect("toDo")],  <<<----
});

저장도 아주 잘 되고 :)


3. 작성한 toDo 삭제하기

  • 와 이건 일단 진짜 filter 함수랑 개싸우다가 결국 다른분 코드를 참고해서 작성했다..
  • 처음에, 아래와같이 filter 함수를 가지고 아이디가 다를 경우 삭제되도록 하려고했는데
  const [todoList, setToDoList] = useRecoilState(toDoState);
  const handleDeleteTodo = (toDoId: number): void => {
    setToDoList(todoList => todoList.filter(t => t.toDoId !== toDoId));
  };
  • .....호출 시그니처에 대해 더 공부한뒤에 코드 변경 예정이다.. 꼭 위의 코드로 쓰고야 말겠어
  • 결국 다른분 코드 참고하여 아래와 같이 작성 ㅠㅠ
-- DraggableCard.tsx

interface IDragabbleCardProps {
  toDoId: number;
  toDoText: string;
  index: number;
  boardId: string;  // 추가
}

function DragabbleCard({
  boardId,
  toDoId,
  toDoText,
  index,
}: IDragabbleCardProps) {
  // 코드챌린지 - 리스트 삭제
  const setTodos = useSetRecoilState(toDoState);
  const handleDeleteTodo = (todoId: number): void => {
    setTodos((todos: IToDoState) => {
      const copiedTodos: IToDo[] = [...todos[boardId]];
      const filteredTodos: IToDo[] = copiedTodos.filter(
        (todo: IToDo) => todo.id !== todoId
      );
      const result = { ...todos, [boardId]: filteredTodos };
      return result;
    });
  };
  return (
    <Draggable draggableId={toDoId + ""} index={index}>
      {(magic, snapshot) => (
        <Card
          isDragging={snapshot.isDragging}
          ref={magic.innerRef}
          {...magic.dragHandleProps}
          {...magic.draggableProps}
        >
          <span>{toDoText}</span>
          <span onClick={() => handleDeleteTodo(toDoId)}>🗑️</span>
        </Card>
      )}
    </Draggable>
  );
}
--Board.tsx
      .
      .
      .
            {toDos.map((toDo, index) => (
              <DragabbleCard
                key={toDo.id}
                index={index}
                toDoId={toDo.id}
                toDoText={toDo.text}
                boardId={boardId}  // 추가
              />
            ))}
      .
      .

4. 새로운 보드 생성하기

  • 기존 TODO, DOING, DONE toDoState atom 값에 새로운 board 추가하기!
-- atoms.tsx

export const toDoState = atom<IToDoState>({
  key: "toDo",
  // 로컬스토리지에 저장되는 key값
  default: {
    "To Do": [],
    Doing: [],
    Done: [],
  },
  effects: [localStorageEffect("toDo")],
});
  • 나는 디폴트로 TODO, DOING, DONE 이 3개는 만들어진 상태에서,
    필요에 따라 추가적인 board 를 추가하기 위해 기존 atom 을 건들이지 않고 만들었다.
  • 방법은 아래와 같다!
    1. 새로운 값을 추가하기위해, 'AddBoard' 파일을 만들고 그 안에 코드를 작성해주었다.
    2. useSetRecoilState 함수로 toDoState 값을 가져온다음,
    3. useForm 에 입력한 {...register("category")} 값을 toDoState 에 넣어주고,
    4. 기존 값과 신규값을 모두 포함하여 return 하였다
      (추가된 board 는 기존 값 뒤로 오게 했다)
-- AddBoard.tsx

const FORM = styled.form`
	...
`;

const AddBtn = styled.button`
	...
`;

interface IForm {
  category: string;
}

function NewBoard() {
  const setToDos = useSetRecoilState(toDoState);
  const { register, handleSubmit, setValue } = useForm<IForm>();
  const onVaild = ({ category }: IForm) => {
    setToDos(prev => {
      return {
        ...prev,
        [category]: [],
      };
    });
    setValue("category", "");
  };
  return (
    <>
      <FORM onSubmit={handleSubmit(onVaild)}>
        <input
          {...register("category")}
          type="text"
          id="category_text"
          placeholder="Add To Caterogy !"
        />
        <AddBtn>
          <div></div>
        </AddBtn>
      </FORM>
    </>
  );
}

  • 추가사항 빨간색 박스 처리

추가도 잘 되고, 삭제도 잘 됨!


5. 보드 삭제하기

  • 디폴트 3형제(기존 todo,doing,done)를 제외하고는, 새로 만든 board는 삭제하는 기능 추가하기
--- Board.tsx

function Board({ toDos, boardId }: IBoardProps) {
  const SetToDos = useSetRecoilState(toDoState);
  const { register, setValue, handleSubmit } = useForm<IFrom>();
  const onValid = ({ toDo }: IFrom) => {
    const newToDo = {
      id: Date.now(),
      text: toDo,
    };
    SetToDos(allBoards => {
      const result = {
        ...allBoards,
        [boardId]: [newToDo, ...allBoards[boardId]],
      };
      return result;
    });
    setValue("toDo", "");
  };
  // -- 코드챌린지 - board 삭제하기
  const deleteBoard = () => {
    SetToDos(allBoards => {
      const copyBoards = { ...allBoards };
      delete copyBoards[boardId];
      return { ...copyBoards };
    });
  };
  return (
    <Wrapper>
      <Title>{boardId}</Title>
      {boardId !== "To Do" && boardId !== "Doing" && boardId !== "Done" && (
        <DelBoardBtn onClick={deleteBoard}></DelBoardBtn>
      )}
  • 이게 좋은 코드인지는 모르겠다..
  • 위에서 말한 IToDo[] 호출 시그니처 때문에 filter 함수를 사용하지 못해서,
    다른 방법이 있나 찾아보던 와중 delete 연산자를 발견
  • 여기 설명을 보고 만들었다.
  • 디폴트 3형제가 아닐 경우 boardId 우측에 deleteBoard ❌ 버튼이 생성되고, 클릭하면 삭제된다.
  • 빨간 박스가 새로 추가된 것이고
  • deleteBoard ❌ 버튼을 누르면 삭제된다.

리팩토링해야할 부분이 많아 보이지만,
진도를 나가려면.. 다음을 기약..하는걸로...


수정 목록


1. board 가 add board input 화면을 가림. css 수정하기 [ ]
2. 전체적인 CSS ... [ ]

profile
기억력 안 좋은 FE 개발자의 메모장

0개의 댓글