1. AddItem
useState Hook을 사용하여 values
상태를 관리하여 여기에 imgFile
이라는 이미지 파일을 저장합니다.
const [values, setValues] = useState({
imgFile: null,
});
handleChange
함수는 자식 컴포넌트 FileInput
에서 전달받은 파일 정보를 values
상태에 업데이트 합니다.
const handleChange = (name, value) => {
setValues({
[name]: value,
});
};
이제 values
와 handleChange
함수를 FileInput
컴포넌트에 prop으로 내려줍니다.
<FileInput
name="imgFile"
value={values.imgFile}
onChange={handleChange}
/>
2. FileInput
a. 파일 선택 시 미리보기 이미지 설정
handleChange
함수는 사용자가 파일을 선택할 때 호출 됩니다. FileInput
의 onChange
이벤트 핸들러를 통해 사용자가 선택한 파일 정보를 AddItemWrapper
컴포넌트로 전달합니다.
const handleChange = (e) => {
const nextValue = e.target.files[0];
onChange(name, nextValue);
};
b. preview 상태 관리
useState Hook을 사용하여 preview
상태를 관리합니다.
const [preview, setPreview] = useState();
c. 미리보기 URL 생성
사용자가 파일을 선택할 때마다 useEffect Hook이 실행됩니다. 여기서 URL.createObjectURL()
을 사용해 선택한 파일에 대한 미리보기 URL을 생성하고 preview
상태에 업데이트 합니다. 이 URL은 임시적으로 생성되며 컴포넌트가 언마운트되거나 이미지가 변경될 때 URL.revokeObjectURL()
로 메모리를 해제합니다.
useEffect(() => {
if (!value) return;
const nextPreview = URL.createObjectURL(value);
setPreview(nextPreview);
return () => {
setPreview();
URL.revokeObjectURL(nextPreview);
};
}, [value]);
d. 이미지 초기화 버튼
이미지가 선택된 경우에만 X
버튼이 표시됩니다. 이 버튼을 클릭하면 useRef Hook을 사용하여 input의 value인 파일 입력 필드의 값을 지우고, AddItem에 null을 전달해 이미지를 초기화 합니다.
const inputRef = useRef();
const handleClearClick = () => {
const inputNode = inputRef.current;
if (!inputNode) return;
inputNode.value = "";
onChange(name, null);
};
3. 컴포넌트 렌더링
렌더링 시, 사용자가 선택한 이미지의 미리보기와 파일 입력 필드가 나타납니다. 파일을 선택하면 이미지 미리보기가 보이며, X
버튼을 클릭하면 파일이 초기화됩니다.
return (
<>
<img src={preview} alt="이미지 미리보기" />
<input
type="file"
accept="image/png, image/jpeg"
onChange={handleChange}
ref={inputRef}
/>
{value && <button onClick={handleClearClick}>X</button>}
</>
);
전체 코드
// AddItem 컴포넌트
const AddItem = () => {
const [values, setValues] = useState({
imgFile: null,
});
const handleChange = (name, value) => {
setValues({
...values,
[name]: value,
});
};
return (
<div>
<h1>이미지 업로드</h1>
<FileInput
name="imgFile"
value={values.imgFile}
onChange={handleChange}
/>
</div>
);
};
// FileInput 컴포넌트
const FileInput = ({ name, value, onChange }) => {
const [preview, setPreview] = useState();
const inputRef = useRef();
const handleChange = (e) => {
const nextValue = e.target.files[0];
onChange(name, nextValue);
};
// 미리보기 URL 생성
useEffect(() => {
if (!value) return;
const nextPreview = URL.createObjectURL(value);
setPreview(nextPreview);
return () => {
setPreview();
URL.revokeObjectURL(nextPreview);
};
}, [value]);
const handleClearClick = () => {
const inputNode = inputRef.current;
if (!inputNode) return;
inputNode.value = "";
onChange(name, null);
};
return (
<>
<img src={preview} alt="미리보기" />
<input
type="file"
accept="image/png, image/jpeg"
onChange={handleChange}
ref={inputRef}
/>
{value && <button onClick={handleClearClick}>X</button>}
</>
);
};
'Front-End > React' 카테고리의 다른 글
[React] useEffect, useCallback, useMemo, useRef (1) | 2024.10.15 |
---|---|
[React] Styled Components (0) | 2024.10.15 |
[React] Router, Routes, Route, Link, NavLink, Navigate (5) | 2024.10.09 |
[React] JSON 파일 데이터 렌더링 (map, sort, filter) (2) | 2024.10.03 |
[React] useState (0) | 2024.10.01 |