// File 자체를 저장하는 state
const [files, setFiles] = useState<File[]>([]);
// File을 읽어 미리보기 url을 저장하는 state
const [fileUrls, setFileUrls] = useState<string[]>([]);
function onChangeFiles(file: File, index: number, url: string) {
// 기존 state들을 담아줍니다.
const newFiles = [...files];
const newFileUrls = [...fileUrls];
// 세개의 버튼 중 이미 사진이 들어있는 곳을 클릭했다면 덮어씌워줍니다.
if (files[index]) {
newFiles[index] = file;
newFileUrls[index] = url;
} else { // 빈 곳이라면 맨 뒤에 추가해줍니다.
newFiles.push(file);
newFileUrls.push(url);
}
// 변경된 배열을 state에 저장해줍니다.
setFiles([...newFiles]);
setFileUrls([...newFileUrls]);
}
return (
<BoardWriteUI
// ...기존 props들을 적어줍니다.
onChangeFiles={onChangeFiles}
fileUrls={fileUrls}
/>
);
<ImageWrapper>
<Label>사진첨부</Label>
// 항상 3개의 컴포넌트가 뿌려집니다.
// 이미지를 보여줄지, 추가 버튼을 보여줄지는 안에서 조건부로 구분합니다.
{new Array(3).fill(1).map((data, index) => (
<Uploads01
key={`${data}_${index}`}
index={index}
onChangeFiles={props.onChangeFiles}
fileUrls={props.fileUrls}
/>
))}
</ImageWrapper>
export default function Uploads01(props: IUploads01Props) {
const fileRef = useRef<HTMLInputElement>(null);
// 상위 컴포넌트에서 배열 state로 관리하기 때문에
// 기존에 각각 url을 state로 저장해서 사용했던 부분을 주석처리합니다.
// const [fileUrl, setFileUrl] = useState("");
function onClickUpload() {
fileRef.current?.click();
}
async function onChangeFile(event: ChangeEvent<HTMLInputElement>) {
const file: any = event.target.files?.[0];
if (!checkValidationFile(file)) return;
const fileReader = new FileReader();
fileReader.readAsDataURL(file);
fileReader.onload = (data) => {
// setFileUrl(data.target?.result as string);
// 파일 자체, 부모에서 map으로 뿌려줄 때의 인덱스, 파일을 읽어서 얻은 미리보기 url
props.onChangeFiles(file, props.index, data.target?.result as string);
};
}
return (
<Uploads01UI
fileRef={fileRef}
// 미리보기 url이 담겨있는 배열에서 해당 위치의 값을 보내줍니다.
fileUrl={props.fileUrls[props.index]}
onClickUpload={onClickUpload}
onChangeFile={onChangeFile}
/>
);
}
export default function Uploads01UI(props: IUploads01UIProps) {
return (
<>
// fileUrls 배열에서 해당 인덱스 위치에 값이 있다면 이미지를 보여주고
// 없다면 추가 버튼을 보여주게 됩니다.
{props.fileUrl ? (
<UploadImage onClick={props.onClickUpload} src={props.fileUrl} />
) : (
<UploadButton onClick={props.onClickUpload}>
<>+</>
<>Upload</>
</UploadButton>
)}
<UploadFileHidden
type="file"
ref={props.fileRef}
onChange={props.onChangeFile}
/>
</>
);
}
new Array(3).fill(1).map()
을 함으로써 Uploads01
컴포넌트가 3개 그려집니다. 각각 인덱스를 넘겨줍니다. 0, 1, 2가 되겠습니다.
0번째 Uploads01
컴포넌트를 보겠습니다.
fileUrls
라는 state가 있습니다. 초기값은 빈 배열입니다.
fileUrls[0]
은 fileUrls
가 빈 배열이기 때문에 undefined
입니다. fileUrls[0]
을 fileUrl
이라는 이름으로 넘겨줍니다. 이 값을 기준으로 이미지를 보여줄지 추가 버튼을 보여줄지 판별합니다.
props.fileUrl ? <이미지를 보여주는 컴포넌트> : <버튼 추가 컴포넌트>
할 경우 undefined는 false이기 때문에 버튼 추가 컴포넌트를 보여줍니다.