-
Notifications
You must be signed in to change notification settings - Fork 0
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
grade upload/#9 #41
grade upload/#9 #41
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 수고하셨습니다
import { ChangeEvent, DragEvent } from 'react'; | ||
|
||
function UploadPdf() { | ||
const { file, changeFile } = useFile(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[comment]
- 이 hook이 존재하는 이유는 input type=file이 uncontrolled component 만 가능하기 때문인가요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
uncontrolled component
가 의미하는 것이 무엇인지 조금 더 설명해주실 수 있을까요? 해당 hook이 존재하는 이유는 pdf 파일에 대한 관심사를 분리하고 캡슐화를 통한 관리를 위함입니다. 당시에는 저희 서비스에서 사용하는 file이 pdf파일밖에 존재하지않으므로 naming을 useFile
로 가져갔는데, 명확함을 위해 usePdfFile
로 수정하겠습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- React에서 input 태그 같은 것을 조작할 때, control 방식과 uncontrolled 방식이 있습니다. 제가 알기론, type=file인 경우에는 uncontrolled 컴포넌트만 가능하다고 알고 있습니다.
- 둘의 차이를 간단하게 설명하자면, control은 value를 직접 state로 관리하여 input에 넣는 방식이고, uncontrolled는 defaultValue를 지정한 후에는 기본 input처럼 동작하는 방식입니다.
- 질문한 이유는 type=file 태그는 uncontrolled 방식이지만, 파일의 유무에 따라 렌더링을 control해야 하기 때문에 이 hook을 만든 것인지 의도가 궁금해서 질문한 것입니다.
- 말씀해주신 관심사의 분리와 캡슐화에는 동의합니다.
- usePdfFile로 변경하는 것도 괜찮아 보입니다.
https://legacy.reactjs.org/docs/uncontrolled-components.html
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
파일의 유무에 따라 렌더링을 control하려는 목적으로 useState
를 사용한 것은 맞습니다. (제어 컴포넌트를 의도) 하지만, hook으로 분리한 목적은 앞서 말씀드린 관심사의 분리와 캡슐화 목적이 더 크게 작용했습니다.
아이러니하게도 의도는 일치했지만 Controlled Component, Uncontrolled Component의 개념적인 부분을 알고 개발에 적용했던 부분은 아니었는데 덕분에 공부해볼 수 있었습니다. 감사합니다 :)
const handleClickInputBox = (event: ChangeEvent) => { | ||
const { files } = event.target as HTMLInputElement; | ||
if (files) changeFile(files[0]); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[request change]
- 클릭 이벤트가 아닌 onChange 이벤트 핸들러로 명칭을 변경해야 할 것 같습니다.
const handleDrop = (event: DragEvent<HTMLDivElement>) => { | ||
event.preventDefault(); | ||
const targetFile = event.dataTransfer.files[0]; | ||
changeFile(targetFile); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[comment]
- changeFile 함수를 실행해도 input의 value 값이 변경되지 않는 것 같습니다. 이 경우, form을 통해 전송할 때 drag&drop 방식이 동작하나요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 흠 그렇다면, 제 생각에는 input의 너비가 drag & drop이 있는 div를 모두 덮고 있어서, drag & drop 시에 onChange 이벤트가 작동하여 동작하는 것 같습니다.
- 따라서 2가지 문제가 있는 것으로 보입니다.
- 첫째, div에 onDrag와 onDragOver 이벤트가 작동하지 않는 것 같습니다. 이 이벤트 핸들러를 제거하고 테스트 해보시겠어요? 기능이 정상적으로 동작한다면, 이 이벤트 핸들러는 혼동을 방지하기 위해 제거해야 할 것 같습니다.
- 둘째, input의 className을 보면, 파일을 드래그 & 드랍하는 파란색 사각형의 X축 범위를 넘어서 파일을 드래그해도 파일이 업로드 될 것으로 예상됩니다. 이미지를 첨부하겠습니다. 해당 위치에 파일을 업로드할 때 파일이 업로드 되는지 확인해 주세요. 그리고 이것이 문제라고 생각한다면 수정이 필요할 것 같습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
중요한 부분을 놓치고 있었네요 반영해서 수정했습니다. 감사합니다 !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
고생하셨습니다!
const handleClickInputBox = (event: ChangeEvent) => { | ||
const { files } = event.target as HTMLInputElement; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ChangeEvent<HTMLInputElement>
로 작성하면 단언을 안해도 될 것 같네요!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
폴더명은 upload-taken-lecture인데 컴포넌트명은 upload-grade-card로 되어있네요
lecture와 grade 가 혼재되어있어서 헷갈릴 수 있을 것 같네요!
성적 업로드라고 부르긴 하지만 사실 자신이 수강한 과목을 업로드 하는 거랑 마찬가지이니 grade를 taken-lecture 또는 lecture로 변경하는 건 어떨까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
upload-taken-lecture가 더 명확하게 와닿을 수 있겠네요. 감사합니다 :)
app/(sub-page)/grade-upload/page.tsx
Outdated
@@ -0,0 +1,12 @@ | |||
import ContentContainer from '../../ui/view/atom/content-container'; | |||
import Manual from './components/manual'; | |||
import UploadGradeCard from '../../ui/lecture/upload-taken-lecture/upload-taken-lecture'; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
import문은 아직 upload grade card네요!
app/(sub-page)/grade-upload/page.tsx
Outdated
export default function GradeUploadPage() { | ||
return ( | ||
<ContentContainer className="flex flex-col justify-center gap-8 min-h-[70vh]"> | ||
<Manual /> | ||
<UploadGradeCard /> | ||
</ContentContainer> | ||
); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
혹시 페이지는 그대로 gradeupload로 가져가는 이유가 있을까요?!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
/taken-lecture-upload
보다 사용자에게 /grade-upload
가 더 직관적일 것 같다는 생각에 변경을 진행하지 않았습니다 !
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 알겠습니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 조금 확인이 늦었네요.
- 수정 요청사항 남겨놨어요. 확인 부탁드릴게요
it('pdf가 아닌 파일을 업로드할 수 없다', async () => { | ||
render(<UploadPdf />); | ||
|
||
const targetFile = new File(['grade'], 'grade.pdf', { | ||
type: 'text/plain', | ||
}); | ||
|
||
const uploadBox = await screen.findByTestId('upload-box'); | ||
fireEvent.upload(uploadBox, targetFile); | ||
|
||
expect(screen.queryByText('추가')).not.toBeInTheDocument(); | ||
}); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
[request change]
- 이 부분은 지금 확인해서 코멘트를 남깁니다.
- 테스트명만 보면 pdf가 아닌 파일이 업로드될 때 업로드가 안 되는 것처럼 보이지만, 테스트 내용을 보면 pdf 파일을 업로드했을 때를 테스트하는 것 같습니다.
- 두 가지 수정사항을 제안하고 싶습니다.
- 첫째, 테스트명을 변경해야 할 것 같습니다. 테스트명만 보아도 어떤 테스트인지 알 수 있어야 합니다. 테스트명에 대한 의견은 PR #42에 남겨두었으니 참고하시면 좋을 것 같습니다.
- 둘째, 추가 테스트가 필요해 보입니다. pdf 파일을 업로드했을 때와 pdf가 아닌 파일을 업로드했을 때를 테스트하는 것이 필요해 보입니다.
- 현재는 처리가 안 되어 있는 것 같은데, 성적표가 아닌 pdf가 업로드되었을 때 어떻게 처리되는지에 대한 테스트 코드도 나중에 추가되면 좋을 것 같네요.
expect(screen.getByText(targetFile.name)).toBeInTheDocument(); | ||
}); | ||
|
||
it('파일이 업로드 될 때, pdf가 아닌 file을 업로드 하면 변화가 발생하지않는다.', async () => { | ||
render(<UploadPdf />); | ||
|
||
const targetFile = new File(['grade'], 'grade.png', { | ||
type: 'text/plain', | ||
}); | ||
|
||
const uploadBox = await screen.findByTestId('upload-box'); | ||
await userEvent.upload(uploadBox, targetFile); | ||
expect(screen.queryByText('마우스로 드래그 하거나 아이콘을 눌러 추가해주세요.')).toBeInTheDocument(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
getByText랑 queryByText 사용하는 기준을 여쭤봐도 될까요!?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
개발과정에서 로직을 위해 메소드를 다르게 가져갔는데, 변경이 발생하면서 현재는 어떤 메소드를 사용해도 적용이 되는 상황입니다!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
- 수고 많았어요.
- 그런데 도메인 컴포넌트인 upload-taken-lecture 컴포넌트가 아니라 뷰 컴포넌트인 upload-pdf 컴포넌트를 테스트한 이유가 있을까요?
테스트를 진행하고자하는 case가 view component인 upload-pdf에 종속된다는 생각이 들어 해당 컴포넌트를 대상으로 테스트를 진행했습니다 :) |
확인했어요 |
📌 작업 내용
🤔 고민 했던 부분
1.
taken-lecture.command.ts
: taken lecture에 변경을 가하고, 또 다시 유저 lecture정보를 변경시키는 경우로 lecture custom 기능이 있는데 두 가지 케이스에 공통으로 적용될수있는 네이밍2.
ui/lecture/upload-taken-lecture
: 기존lecture
도메인에서taken lecture
라는 네이밍을 갖고있으므로 해당 일관성을 확보하며,pdf=taken lecture list
이므로pdf upload=upload taken lecture
으로 명확한 의미 전달해당 이유로 위와 같이 작성했습니다:)
🔊 전달하고 싶은 부분
file-upload
페이지에서grade-upload
로 페이지 명 변경upload-grade-card
컴포넌트의 경우 서버 컴포넌트를 의도하고 작성했지만, form을 구성하는form-number-input.tsx
등의 컴포넌트에서 client component를 요구하므로 'use client'; 추가하여 클라이언트 컴포넌트로 작업했습니다.