Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Course/dnd #69

Merged
merged 15 commits into from Sep 20, 2021
Merged

Course/dnd #69

merged 15 commits into from Sep 20, 2021

Conversation

TaehwanGo
Copy link
Member

강의 생성 부 drag and drop 구현

  • react-sortable.js, sortable.js 사용

삭제 아이콘 클릭 후 적용되던 로직 변경

  • 기존 : 리덕스 스토어 값까지 변경
  • 변경 : 리덕스는 서버에서 받아오는 것만 저장, 드래그 앤 드랍이나 삭제 후 서버로 바뀐 데이터를 전송

drag and drop list 리덕스와 연결

@TaehwanGo TaehwanGo added this to In progress in Inflearn-front via automation Sep 19, 2021
item: ItemInterface;
// onClickDelete: () => void;
list: ItemInterface[];
setList: React.Dispatch<React.SetStateAction<ItemInterface[]>>;
Copy link
Collaborator

@hyoni0817 hyoni0817 Sep 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 코드는 어떤식으로 동작하는 건가요?
이 dispatch는 redux의 dispatch를 뜻하는 것은 아닌걸로 보이는데, setList가 setState를 가져오고 이 setState를 타입스크립트로 선언할 때 이렇게 코드를 작성하는건가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextListBox가 부모 컴포넌트로 부터 받는 Props에 대한 타입을 정의한 부분이에요
setList의 React.Dispatch<React.SetStateAction<ItemInterface[]>> 는
setState에 ItemInterface[]가 초기값으로 들어갈 때 타입입니다.
저도 이것을 외우거나 찾아본것은 아니고 setState에 마우스를 오버하면 vscode에서 제공해주는 툴팁에 적혀있는 부분을 그대로 복사해서 사용했습니다

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setList가 useState의 set쪽을 props로 내리시는거 같은데 함수같은걸로 내리고 state는 컴포넌트 내에서 설정을 하는게 어떨지 생각이 들긴하네요. 재사용성에 있어서 어려움이 있을 것 같은 생각이 들어서요.
무조건 같이 딸려가는 자식 컴포넌트라면 괜찮을것 같기도 합니다.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MinwooJJ
TextListBox는 리스트 중에서 한줄이에요
그런데 setList까지 보낸 이유는 삭제를 TextListBox컴포넌트 안에서 처리하기 위해서 같이 보냈어요
useState를 밖에서 선언한 이유는

  const [expectedStudents, setExpectedStudents] = useState<ItemInterface[]>(
    lectureData?.courseInfo.expectedStudents.map((item) => ({
      id: item.order,
      name: item.name,
    }))
  );

        <ReactSortable list={expectedStudents} setList={setExpectedStudents} animation={200} handle=".handle">
          {expectedStudents.map((item, index) => (
            <TextListBox
              key={item.id}
              item={item}
              list={expectedStudents}
              setList={setExpectedStudents}
              index={index}
            />
          ))}
        </ReactSortable>

TextListBox를 사용하는 course_info 페이지에서 useState에 리스트를 넣어서 리스트 개수만큼 TextListBox를 만들어줘야 되기 때문에 밖에서 사용했습니다. 🙂

@@ -51,6 +54,9 @@ export const initialState: ILectureState = {
level: '',
},
},
saveCourseInfoLoading: false,
saveCourseInfoDone: false,
saveCourseInfoError: undefined,
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

saveCourseInfoError의 초기값을 ''(빈 문자열)로 하지 않고 undefined를 하신 이유가 있나요? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

별 이유는 없는데 나중에 혹시 예외 처리를 할 때 편하지 않을까 하는 생각에
타입을 saveCourseInfoError?: string; - string or undefined로 정의했습니다.
그렇지만 사실 ''(빈 문자열) 도 false이기 때문에
saveCourseInfoError: string; 로 타입을 지정하고 초기값을 빈 문자열로 줘도 상관없을 것 같네요

requiredKnowledge: string[];
whatYouCanLearn: LectureInfoChild[];
expectedStudents: LectureInfoChild[];
requiredKnowledge: LectureInfoChild[];
Copy link
Collaborator

@hyoni0817 hyoni0817 Sep 19, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LectureInfoChild[]는 배열 안 값의 타입이 LectureInfoChild 타입이어야 한다고 선언하는 건가요?

[{name: '홍길동', order: 1, city: '서울' }] 이런 식으로 값이 들어가면 에러가 발생하는 거죠?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

/>
<ReactSortable list={whatYouCanLearn} setList={setWhatYouCanLearn} animation={200} handle=".handle">
{whatYouCanLearn.map((item, index) => (
<TextListBox key={item.id} item={item} list={whatYouCanLearn} setList={setWhatYouCanLearn} index={index} />
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextListBox의 key와 index 속성은 어떤 차이가 있는건가요? :)

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key는 array.map으로 같은 컴포넌트를 여러개 반복해서 사용할 때
React의 Virtual Dom이 각 컴포넌트를 구분하기 위한 값입니다.
그래서 보통 item의 id같이 겹치지 않는 값을 사용합니다
index는 삭제 버튼을 클릭했을 때 해당 컴포넌트가 리스트에서 몇번째 위치가 몇번째 인지 알아야 삭제를 할 수 있어서 보 prop으로 보내줬습니다.
key에 map의 index를 사용하기도 하지만 eslint에서 권장하지 않는 방식이고
무엇보다 ReactSortable 라이브러리의 문서에서

key !== index

DO NOT use the index as a key for your list items. Sorting will not work.
In all the examples above, I used an object with an ID. You should do the same!
I may even enforce this into the design to eliminate errors.
와 같이 나와있어서 사용하지 않았습니다.

@hyoni0817
Copy link
Collaborator

작성하신 코드보면서 덕분에 저도 react-sortable.js에 대해 알게되었고, 다양한 라이브러리를 접해보게 되었습니다. 저도 나중에 한번 공부삼아 사용해봐야겠습니다 :)

아 그리고 실행시켜봤는데 추가하기 버튼은 추후에 구현하시는 거죠? :)

코멘트 남겨주시면 확인 후에 승인 바로 하겠습니다 :D

@TaehwanGo
Copy link
Member Author

@hyoni0817 추가버튼은 잊고 있었네요 ㅋㅋ
해야할 목록과 이슈에 추가하고 다음 PR로 올리겠습니다

@TaehwanGo
Copy link
Member Author

TaehwanGo commented Sep 19, 2021

@hyoni0817 추가 버튼 기능 추가했습니다.
다른 PR로 올리려고 했는데 노아님 리뷰 승인보다 제가 구현하는게 더 빨라서 여기에 같이 push 했습니다.
다시 리뷰 부탁드립니다 😅
e923d0b

@TaehwanGo
Copy link
Member Author

Copy link
Collaborator

@hyoni0817 hyoni0817 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

말로 제대로 표현이 안되는 것 같아서 gif도 함께 첨부했습니다 ;)
코드 리뷰를 하다보니 drag & drop이 생각보다 신경써야할 부분이 많은 것 같아서 쉽지 않다고 느껴지는데 여러 라이브러리를 비교 분석하신 뒤 빠른 시간 내에 구현을 하신 것 같다는 생각이 들었습니다👍

아 그리고 이번에 토니님이 수정하신 파일은 아니지만, 코드 실행해보다가 create_course 페이지가 렌더링되고 나면 콘솔창에 아래와 같은 경고가 떠서 궁금한 마음에 혹시 해결 방법이 없나 하고 알아봤어요.

Warning: Received `false` for a non-boolean attribute `loading`.

If you want to write it to the DOM, pass a string instead: loading="false" or loading={value.toString()}.

If you used to conditionally omit it with loading={condition && value}, pass loading={condition ? value : undefined} instead.

일단 typeof로 props.loading이 혹시 string값으로 들어오나 확인해봤는데 boolean 값만 받더라구요.
그래서 관련 글을 찾아보고 아래와 같이 코드를 수정하니 에러는 나타나지 않았는데 저도 사실 가볍게 훑어본거라 자세히 공부하지는 못했고,
나중에 한 번 확인해보시면 좋지 않을까하고 코멘트 남깁니다 :)

const BtnMakeCourse = styled.button`
  ...
  //loading앞에 $를 붙여줬어요. props가 dom 요소에 전달되는 것을 막아주는 역할을 한다고 합니다.
  pointer-events: ${(props: IBtnProps) => (props.$loading ? 'none' : 'auto')};
`;
{/* loading 속성에 기존 boolean 값 대신 string으로 false를 줬어요. 이렇게 해도 pointer-events: auto;가 되었어요. */}
<BtnMakeCourse loading="false" type="button" onClick={handleSubmit}>
  강의 만들기
</BtnMakeCourse>

참고한 글
Warning Received true for non-boolean attribute 관련 분석글
Warning: Received false for a non-boolean attribute. How do I pass a boolean for a custom boolean attribute?

case DELETE_ITEM_REQUIREDKNOWLEDGE:
draft.lectureData.courseInfo.requiredKnowledge = action.data;
case ADD_REQUIREDKNOWLEDGE:
draft.lectureData.courseInfo.requiredKnowledge.push(action.data);
break;

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

드래그 버튼으로 단어를 이동시킨 후 '추가하기' 작업을 했을 때 기존에 정렬했던 방식이 초기화되고 단어가 추가되더라구요.
예를 들면 아래 gif에서 보시면 저는 [ 인프런, 리액트, 타입스크립트] 이렇게 있던 것을 [인프런, 타입스크립트, 리액트] 이렇게 바꾼 후에 '코딩'이라는 단어를 추가했는데 [인프런, 리액트, 타입스크립트, 코딩] 이런 식으로 정렬이 되었습니다.
강의 추가하기

혹시 인프런도 이와 같은 방식으로 진행되나요? :)

react-sortable.js에 드래그 후 바뀐 배열값을 저장해주는 API같은 건 따로 제공하지 않는건지 궁금합니다😃

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삭제나 변경은 useState에서 하는데 추가를 리덕스를 연결해서 이런문제가 발생하는 것 같네요
추가할 때에도 useState에 추가하면 될 것 같습니다.
수정하고 다시 리뷰 요청드릴게요
좋은 지적 감사합니다 !
어제 급하게 하느라 테스트를 안하고 넣으니 이런 문제가 발생하네요 😅

const copiedList = [...list];
copiedList.splice(index, 1); // 현재 항목을 지움
setList(copiedList); // 지운 것을 반영
};
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

모든 항목을 삭제후에, 항목을 추가하면 기존에 삭제했던 게 다시 복구가 되고 단어가 추가되는 문제가 발생합니다😢
강의 삭제 후 데이터 추가

그리고 위 과정을 거치고 나면 맨 첫번째 항목이 삭제가 안되고, 여기서 또 항목을 추가하게 되면 맨 첫번째 항목이 중복되어서 나타납니다
첫번째 강의 삭제 문제

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 제가 삭제나 변경은 useState에서 하는데 추가를 리덕스를 연결해서 이런문제가 발생하는 것 같네요
추가할 때에도 useState에 추가하면 될 것 같습니다.
수정하고 다시 리뷰 요청드릴게요

@TaehwanGo
Copy link
Member Author

TaehwanGo commented Sep 20, 2021

@hyoni0817 @MinwooJJ

추가하기 버튼에 있던 버그 수정했습니다.

추가 하기 버튼 기능 구현

  • 추가하기를 누르면 store가 아닌 setState에서 변경
    • redux store에 직접 변경하지 않는 이유는 react-sortablejs에서 useState를 사용하기 때문
// ReactSortable 컴포넌트에서 setList 속성에 setState가 들어가야 함
<ReactSortable list={expectedStudents} setList={setExpectedStudents} animation={200} handle=".handle">
  {expectedStudents.map((item, index) => (
    <TextListBox key={item.id} item={item} list={expectedStudents} setList={setExpectedStudents} index={index} />
  ))}
</ReactSortable>

43c8853

@MinwooJJ MinwooJJ closed this Sep 20, 2021
Inflearn-front automation moved this from In progress to Done Sep 20, 2021
@MinwooJJ MinwooJJ reopened this Sep 20, 2021
Inflearn-front automation moved this from Done to In progress Sep 20, 2021
item: ItemInterface;
// onClickDelete: () => void;
list: ItemInterface[];
setList: React.Dispatch<React.SetStateAction<ItemInterface[]>>;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

setList가 useState의 set쪽을 props로 내리시는거 같은데 함수같은걸로 내리고 state는 컴포넌트 내에서 설정을 하는게 어떨지 생각이 들긴하네요. 재사용성에 있어서 어려움이 있을 것 같은 생각이 들어서요.
무조건 같이 딸려가는 자식 컴포넌트라면 괜찮을것 같기도 합니다.

// order: item.id,
order: index, // front에서 변경된 order 반영
}));
const expectedStudentsList: LectureInfoChild[] = expectedStudents.map((item, index) => ({
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분이 order가 변경되면 그것을 다시 바뀐 순서대로 1부터 적용해주는 부분인가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다. 저장할 때 변경된 order를 서버에 전송에서 서버에서도 기억했다가
변경된 order로 서버에서 데이터를 받기 위한 부분입니다.

});
router.push(`/course/${id}/edit/description`);
}
}, [saveCourseInfoDone]);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

서버로 혹시 전송이 되지 않을 경우는 어떻게 되나요?
전송 후 redirect가 되는데 혹시 서버 문제나 어떠한 요청 문제로 보내지지 않을 경우는 어떻게 되는지 궁금하네요.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reducer에서 실패한 경우엔 saveCourseInfoDone을 true로 바꾸지 않기 때문에 페이지가 이동되지 않도록 했습니다.
전송에 실패한 경우엔 콘솔창에 에러메세지를 띄워주도록 설정했습니다.

function* saveCourseInfo(action: IAction) {
  try {
    // const result = yield call(() => postSaveCourseInfo(action.data), action.data);
    yield delay(1000);
    yield put({
      type: SAVE_COURSE_INFO_SUCCESS,
      // data: result?.data
      data: 'course info 저장 성공',
    });
  } catch (error) {
    console.error(error);
    yield put({
      type: SAVE_COURSE_INFO_FAILURE,
      error,
    });
  }
}

Copy link
Member Author

@TaehwanGo TaehwanGo left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

submit을 해야 여태까지 댓글 단 것들이 보이는건가요?

item: ItemInterface;
// onClickDelete: () => void;
list: ItemInterface[];
setList: React.Dispatch<React.SetStateAction<ItemInterface[]>>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TextListBox가 부모 컴포넌트로 부터 받는 Props에 대한 타입을 정의한 부분이에요
setList의 React.Dispatch<React.SetStateAction<ItemInterface[]>> 는
setState에 ItemInterface[]가 초기값으로 들어갈 때 타입입니다.
저도 이것을 외우거나 찾아본것은 아니고 setState에 마우스를 오버하면 vscode에서 제공해주는 툴팁에 적혀있는 부분을 그대로 복사해서 사용했습니다

const TextListBox = ({ item, list, setList, index }: Props) => {
const onClickDelete = () => {
const copiedList = [...list];
copiedList.splice(index, 1); // 현재 항목을 지움
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

매우 좋은 아이디어 입니다 !
제가 코드를 짤때 filter가 생각이 안났었네요 ㅎㅎ
위 코드에서 list는 useState의 state 부분으로 직접 변경이 되지 않아서
copiedList에 destructuring assignment - [...array] - 을 사용해서 복사 후 수정한 뒤
setState로 변경하는 코드입니다.

/>
<ReactSortable list={whatYouCanLearn} setList={setWhatYouCanLearn} animation={200} handle=".handle">
{whatYouCanLearn.map((item, index) => (
<TextListBox key={item.id} item={item} list={whatYouCanLearn} setList={setWhatYouCanLearn} index={index} />
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

key는 array.map으로 같은 컴포넌트를 여러개 반복해서 사용할 때
React의 Virtual Dom이 각 컴포넌트를 구분하기 위한 값입니다.
그래서 보통 item의 id같이 겹치지 않는 값을 사용합니다
index는 삭제 버튼을 클릭했을 때 해당 컴포넌트가 리스트에서 몇번째 위치가 몇번째 인지 알아야 삭제를 할 수 있어서 보 prop으로 보내줬습니다.
key에 map의 index를 사용하기도 하지만 eslint에서 권장하지 않는 방식이고
무엇보다 ReactSortable 라이브러리의 문서에서

key !== index

DO NOT use the index as a key for your list items. Sorting will not work.
In all the examples above, I used an object with an ID. You should do the same!
I may even enforce this into the design to eliminate errors.
와 같이 나와있어서 사용하지 않았습니다.

@@ -51,6 +54,9 @@ export const initialState: ILectureState = {
level: '',
},
},
saveCourseInfoLoading: false,
saveCourseInfoDone: false,
saveCourseInfoError: undefined,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

별 이유는 없는데 나중에 혹시 예외 처리를 할 때 편하지 않을까 하는 생각에
타입을 saveCourseInfoError?: string; - string or undefined로 정의했습니다.
그렇지만 사실 ''(빈 문자열) 도 false이기 때문에
saveCourseInfoError: string; 로 타입을 지정하고 초기값을 빈 문자열로 줘도 상관없을 것 같네요

requiredKnowledge: string[];
whatYouCanLearn: LectureInfoChild[];
expectedStudents: LectureInfoChild[];
requiredKnowledge: LectureInfoChild[];
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const copiedList = [...list];
copiedList.splice(index, 1); // 현재 항목을 지움
setList(copiedList); // 지운 것을 반영
};
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이게 제가 삭제나 변경은 useState에서 하는데 추가를 리덕스를 연결해서 이런문제가 발생하는 것 같네요
추가할 때에도 useState에 추가하면 될 것 같습니다.
수정하고 다시 리뷰 요청드릴게요

case DELETE_ITEM_REQUIREDKNOWLEDGE:
draft.lectureData.courseInfo.requiredKnowledge = action.data;
case ADD_REQUIREDKNOWLEDGE:
draft.lectureData.courseInfo.requiredKnowledge.push(action.data);
break;

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

삭제나 변경은 useState에서 하는데 추가를 리덕스를 연결해서 이런문제가 발생하는 것 같네요
추가할 때에도 useState에 추가하면 될 것 같습니다.
수정하고 다시 리뷰 요청드릴게요
좋은 지적 감사합니다 !
어제 급하게 하느라 테스트를 안하고 넣으니 이런 문제가 발생하네요 😅

item: ItemInterface;
// onClickDelete: () => void;
list: ItemInterface[];
setList: React.Dispatch<React.SetStateAction<ItemInterface[]>>;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@MinwooJJ
TextListBox는 리스트 중에서 한줄이에요
그런데 setList까지 보낸 이유는 삭제를 TextListBox컴포넌트 안에서 처리하기 위해서 같이 보냈어요
useState를 밖에서 선언한 이유는

  const [expectedStudents, setExpectedStudents] = useState<ItemInterface[]>(
    lectureData?.courseInfo.expectedStudents.map((item) => ({
      id: item.order,
      name: item.name,
    }))
  );

        <ReactSortable list={expectedStudents} setList={setExpectedStudents} animation={200} handle=".handle">
          {expectedStudents.map((item, index) => (
            <TextListBox
              key={item.id}
              item={item}
              list={expectedStudents}
              setList={setExpectedStudents}
              index={index}
            />
          ))}
        </ReactSortable>

TextListBox를 사용하는 course_info 페이지에서 useState에 리스트를 넣어서 리스트 개수만큼 TextListBox를 만들어줘야 되기 때문에 밖에서 사용했습니다. 🙂

// order: item.id,
order: index, // front에서 변경된 order 반영
}));
const expectedStudentsList: LectureInfoChild[] = expectedStudents.map((item, index) => ({
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

네 맞습니다. 저장할 때 변경된 order를 서버에 전송에서 서버에서도 기억했다가
변경된 order로 서버에서 데이터를 받기 위한 부분입니다.

});
router.push(`/course/${id}/edit/description`);
}
}, [saveCourseInfoDone]);
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

reducer에서 실패한 경우엔 saveCourseInfoDone을 true로 바꾸지 않기 때문에 페이지가 이동되지 않도록 했습니다.
전송에 실패한 경우엔 콘솔창에 에러메세지를 띄워주도록 설정했습니다.

function* saveCourseInfo(action: IAction) {
  try {
    // const result = yield call(() => postSaveCourseInfo(action.data), action.data);
    yield delay(1000);
    yield put({
      type: SAVE_COURSE_INFO_SUCCESS,
      // data: result?.data
      data: 'course info 저장 성공',
    });
  } catch (error) {
    console.error(error);
    yield put({
      type: SAVE_COURSE_INFO_FAILURE,
      error,
    });
  }
}

Copy link
Collaborator

@hyoni0817 hyoni0817 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아 Conversation 탭이 아닌 Files changed 탭에서 코멘트를 작성하셔서 submit을 하셔야 했던 게 아닐까 하는 생각이 듭니다 :)
이전에 작성하신 코멘트가 등록된 것과 추가하기 버그 수정하신거 확인했습니다!😄
고생많으셨습니다! 👍

const TextListBox = ({ item, list, setList, index }: Props) => {
const onClickDelete = () => {
const copiedList = [...list];
copiedList.splice(index, 1); // 현재 항목을 지움
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 어제 이 부분을 splice로 보고 코멘트 단 후에 갑자기 제 눈이 splice를 slice로 인식해버려서 코멘트를 잘못 작성한 것 같다고 생각하여 삭제해버렸네요😂
토니님 생각하신대로 state부분이 직접 변경이 되지 않으니 splice를 써도 괜찮은 것 같습니다 :)

@TaehwanGo TaehwanGo merged commit 9f2ebba into main Sep 20, 2021
Inflearn-front automation moved this from In progress to Done Sep 20, 2021
@TaehwanGo TaehwanGo deleted the course/dnd branch September 20, 2021 05:35
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
Development

Successfully merging this pull request may close these issues.

None yet

3 participants