이미지 업로드 페이지를 만들어보자.
일단 이미지 업로드만 할 수 있는 게시판을 만들고 싶었다. 그래서 서버와 관련된 코드를 빼고 어떻게 JS와 Css를 작성했는지 한번 기록 겸 남겨두려고 한다. 필요한 건 간단하다. 맨 위 제목을 작성하고 이미지들을 업로드 드래그 앤 드롭으로 끌어 넣으면 계속 추가되는 형식의 사이트이다.
export default function ImageUploadForm() {
const [selectedFiles, setSelectedFiles] = useState([]);
const fileInputRef = useRef(null);
const handleFileChange = (event) => {
const files = Array.from(event.target.files);
setSelectedFiles((prevFiles) => [...prevFiles, ...files]);
};
const handleDrop = (event) => {
event.preventDefault();
const files = Array.from(event.dataTransfer.files);
setSelectedFiles((prevFiles) => [...prevFiles, ...files]);
};
const handleUploadTextClick = () => {
fileInputRef.current.click();
};
return (
<div>
<Navbar page="이미지 업로드 Form" />
<Container>
<section id="ex9">
<h1>사진</h1>
<TitleInput>
<label>제목</label> <input type="text" />
</TitleInput>
<ImageInput>
<div
className="upload-box"
onDrop={handleDrop}
onClick={handleUploadTextClick}
onDragOver={(e) => e.preventDefault()}
>
<Inputt>
<input
ref={fileInputRef}
className="btn-file d-none"
type="file"
onChange={handleFileChange}
multiple
/>
{selectedFiles.length > 0 ? (
<div>
<div className="viewer">
{selectedFiles.map((file, index) => (
<div key={index} className="file-preview">
<Image
src={URL.createObjectURL(file)}
alt={`미리보기 ${index + 1}`}
width={100}
height={100}
/>
</div>
))}
</div>
</div>
) : (
<div className="noneimg">
<img src="/cloude.png" alt="클라우드 이미지" />
<p>사진을 끌어서 넣거나 클릭해주세요</p>
</div>
)}
</Inputt>
</div>
</ImageInput>
<button className="btn btn-primary">등록</button>
</section>
</Container>
</div>
);
}
일단은 위에 코드가 전문이다. 코드를 하나하나 뜯어서 어떻게 제작이 된건지에 대해 말해보려고 한다.
const [selectedFiles, setSelectedFiles] = useState([]);
const fileInputRef = useRef(null);
여기서 useState를 사용하여 selectedFiles라는 상태 변수와 setSelectedFiles라는 상태 업데이트 함수를 생성한다. 이 변수는 업로드할 이미지 파일을 추적할 예정이다. useRef를 사용하여 fileInputRef라는 ref를 생성할 예정이다. 이 ref는 파일 입력(input) 엘리먼트를 참조하는 데 사용된다.
여기서 Ref 가 뭔지 모를 수 있는데 Ref는 ref는 React에서 사용되는 참조(reference)를 나타내는 개념이다. React 컴포넌트 안에서 DOM 요소나 다른 React 요소를 참조하고 조작할 때 사용된다.
const handleFileChange = (event) => {
const files = Array.from(event.target.files);
setSelectedFiles((prevFiles) => [...prevFiles, ...files]);
};
handleFileChange 함수는 파일 입력(input) 엘리먼트에서 파일을 선택했을 때 호출된다. 선택한 파일들을 배열로 변환하고, 기존에 선택한 파일 목록(selectedFiles)에 새로운 파일들을 추가한다.
const handleDrop = (event) => {
event.preventDefault();
const files = Array.from(event.dataTransfer.files);
setSelectedFiles((prevFiles) => [...prevFiles, ...files]);
};
handleDrop 함수는 파일을 드래그 앤 드롭하여 업로드할 때 호출된다. 이 함수는 드롭 이벤트를 처리하고 드롭한 파일들을 배열로 변환한 다음 기존 선택한 파일 목록에 추가한다.
const handleUploadTextClick = () => {
fileInputRef.current.click();
};
handleUploadTextClick 함수는 Div 박스를 클릭했을 때 파일 입력(input) 엘리먼트를 클릭하도록 한. 이렇게 하면 사용자가 파일 선택 대화 상자를 열 수 있다.
넣는 방식에 따라 아래와 같이 흘러간다.
드래그 해서 넣으면 -> handleDrop 호출 -> handleFileChange-> 이미지를 배열로 저장
div를 선택해서 넣으면 -> handleUploadTextClick -> handleFileChange -> 이미지를 배열로 저장
여기에 CSS랑 JSX를 적절하게 섞어서 코드를 작성한 것이다.
Flex를 활용해서 만약 이미지를 넣으면 미리 보기로 보이게 해 두었고 좌우 넓게 따라 자동으로 정렬되게끔 CSS를 짜두었다.
생각보다 제작하면서 좀 많이 헤매었다. 드래그 앤 드롭으로 파일 넣는 걸 만들어보는 건 처음이기도 했고 파일을 배열로 만들어서 저장할 생각도 못해봤었기 때문에 조금 애를 먹었던 것 같다.
css 코드가 궁금하면 댓글 달아두면 담에 Css코드도 좀 알려줘 보겠다