-파일을 선택하면 이미지를 추가할 수 있게 개발
-이미지 삭제 기능 추가
-반응형으로 개발하여 화면이 작아지면 좌우로 스크롤하여 이미지를 볼 수 있는 기능 추가
그냥 리액트를 사용하게 되면 따로 리액트, 리액트 돔, 번들러, 바벨 등등을 일일이 설치해야되기 때문에
create react-app 설치 권장
$ npm i -g yarn
$ yarn create react-app image-gallery[폴더명] --template typescript
-버튼을 클릭하면 이미지 파일을 드래그해서 내려받을 수 있고 삭제할 수 있는 가능 구현
-이미지 박스들은 무한히 늘어날 수 있다. [이미지를 계속 추가할 수 있기 때문]
*이미지가 들어갈 컴포넌트 만들기
// src/components/ImageBox.tsx
//타입스크립트 문법으로 props의 타입을 정해준다.[props는 기본적으로 오브젝트여야함 {}]
function ImageBox(props: { src: string }) {
return (
<div className="image-box">
{/* 이미지를 받을 수 있게 기능 구현 */}
<img src={props.src} />
</div>
);
}
//해당 함수를 다른 곳에서 사용할 것이니까 export를 통해 내보내준다.
export default ImageBox;
*이미지 렌더링
// App.tsx
import React, { useRef, useState } from "react";
import "./App.css";
import ImageBox from "./components/ImageBox";
function App() {
const inpRef = useRef<HTMLInputElement>(null);
const [imageList, setImageList] = useState<string[]>([]);
console.log(imageList);
return (
<div className="container">
<div className={"gallery-box" + (imageList.length > 0 && "row")}>
{imageList.length === 0 && (
<div className="text-center">
이미지가 없습니다. <br />
이미지를 추가해주세요.
</div>
)}
<input
type="file"
ref={inpRef}
onChange={(event) => {
if (event.currentTarget.files?.[0]) {
const file = event.currentTarget.files[0];
console.log(file.name);
//파일을 이미지 url로 바꿔주기
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onloadend = (event) => {
setImageList((prev) => [
...prev,
event.target?.result as string,
]);
};
}
}}
/>
{imageList.map((el, idx) => (
<ImageBox key={el + idx} src={el} />
))}
<div
className="puls-box mt"
onClick={() => {
inpRef.current?.click();
}}
>
+
</div>
</div>
</div>
);
}
export default App;
react-dropzone 라이브러리를 사용하여 드래그 드롭 기능 구현
$ yarn add react-dropzone
$ yarn add @types/react-dropzone
파일을 클릭해서 넣는 것이 아닌 폴더에서 드래그 앤 드롭으로 이미지 추가 가능하게 구현
// App.tsx
import React, { useCallback, useRef, useState } from 'react';
import { useDropzone } from 'react-dropzone';
import './App.css';
import ImageBox from './components/ImageBox';
function App() {
const [imageList, setImageList] = useState<string[]>([])
const onDrop = useCallback(acceptedFiles => {
console.log(acceptedFiles)
if (acceptedFiles.length) {
for (const file of acceptedFiles) {
const reader = new FileReader();
reader.readAsDataURL(file)
reader.onloadend = (event) => {
setImageList(prev => [...prev, event.target?.result as string])
}
}
}
}, [])
const { getRootProps, getInputProps } = useDropzone({ onDrop })
return (
<div className='container'>
<div className={'gallery-box ' + (imageList.length > 0 && 'row')}>
{
imageList.length === 0 &&
<div className='text-center'>
이미지가 없습니다.<br />
이미지를 추가해주세요.
</div>
}
{
imageList.map((el, idx) => <ImageBox key={el + idx} src={el} />)
}
<div className='plus-box'
{...getRootProps()}
>
<input
{...getInputProps()}
/>
+
</div>
</div>
</div>
);
}
export default App;