[Project] Image Upload
이미지 업로드하기
1. 이미지는 3개까지 업로드 할 수 있다.
2. 이미지를 업로드 하면 미리보기로 어떤 이미지를 올렸는지 알 수 있다.
3. 게시물 등록 버튼을 클릭하면 이미지가 구글 스토리지에 저장되고 url을 받아온다.
4. 게시물 상세 페이지에서 내가 올린 이미지를 확인할 수 있다.
차근차근...
1. 이미지 업로드 하기
게시물 등록하기 화면에서 +Upload 박스를 클릭하면 이렇게 이미지 파일을 등록할 수 있는 창이 뜬다.
코드..코드를 보자! 🤔
하지만 그 전에 우선 설치해줘야 하는 녀석이 있다.
npm install apollo-upload-client
아폴로 업로드 클라이언트를 설치해줬다면 이제 _app.js로 가자
import {createUploadLink } from 'apollo-upload-client'
function MyApp({ Component, pageProps }) {
const uploadLink = createUploadLink({
uri: "http://backend03.codebootcamp.co.kr/graphql",
})
const client = new ApolloClient({
link: ApolloLink.from([uploadLink]),
cache: new InMemoryCache()
})
//코드 중략...
apollo-upload-client를 import해주고 코드를 작성해줬다면 이제 이미지 업로드를 할 수 있다. 이제 진짜 코드..코드를 보자!
BoardWrite.presenter.tsx파일에 이미지 업로드 해주는 UI부분을 보면
<ImageWrapper>
<Label>사진첨부</Label>
{props.fileUrls.map((el, index) => (
<Uploads01
key={`${el}_${index}`}
index={index}
fileUrl={el}
onChangeFileUrls={props.onChangeFileUrls}
/>
))}
</ImageWrapper>
map..maaap! ! ! map으로 돌려서 저렇게 받는구나..확인을 하고 이제 BoardWrite.container.tsx로 가서 <script> 부분을 보자.
const [fileUrls, setFileUrls] = useState(["", "", ""]);
fileUrls라는 state를 배열에 빈 문자열 3개로 초기값을 줬구나!
저녀석을 props로 BoardWrite.presenter.tsx에 넘겨주면 map으로 돌려진다. (3번)
map으로 돌려지는 Uploads01이 어떤 코드인지 확인하러 가보자.
Uploads01.presenter.tsx
export default function Uploads01UI(props: IUploads01UIProps) {
return (
<> //삼항연산자를 이용해서 화면에 원하는 UI 뿌려주기
{props.fileUrl ? ( //props.fileUrl이 있으면 내가 올린 이미지 파일 보여주기
<UploadImage
onClick={props.onClickUpload}
src={`https://storage.googleapis.com/${props.fileUrl}`}
/>
) : (
<UploadButton onClick={props.onClickUpload}> // props.fileUrl이 없으면 등록버튼 보여주기
<>+</>
<>Upload</>
</UploadButton>
)}
<UploadFileHidden
type="file"
ref={props.fileRef}
onChange={props.onChangeFile}
/>
</>
);
}
fileUrls 초기값을 빈문자열로 줬기 때문에 false일 때 조건인 등록버튼이 화면이 보여진다.
이미지를 올렸을 때와 올리기 전 둘다 같은 onClick함수를 사용한다. 이미지를 올렸어도 다른 이미지를 업로드 할 수 있기 때문이다.
onClick={props.onClickUpload} // 같은 onClick함수
onClickUpload 함수가 있는 친구들은 사실 훼이크다!
UploadImage와 UploadButton이 클릭되는게 아니라 사실 숨어있는 <UploadFileHidden input type="file">이 클릭된다.
어떻게 가능하냐면 useRef( )를 사용해 줬으니까 ⭐️ [킵코 React useRef( ) 보러가기 👉👉 https://keepcoing.tistory.com/4]
<UploadFileHidden
type="file"
ref={props.fileRef}
onChange={props.onChangeFile} <- 실제 실행되는 함수
/>
함수가 실행되면 이미지를 업로드 할 수 있다.
async function onChangeFile(event: ChangeEvent<HTMLInputElement>) {
const file = event.target.files?.[0];
if (!file?.size) {
Modal.error({ content: "파일이 없습니다." });
return;
}
if (file.size > 5 * 1024 * 1024) {
Modal.error({ content: "파일이 너무 큽니다.(제한: 5MB)" });
return;
}
if (!file.type.includes("png") && !file.type.includes("jpeg")) {
Modal.error({
content: "파일 확장자가 올바르지 않습니다.(png, jpeg만 가능)",
});
return;
}
try {
const result = await uploadFile({ variables: { file } });
props.onChangeFileUrls(result.data.uploadFile.url, props.index);
} catch (error) {
Modal.error({ content: error.message });
}
}
이미지를 선택해서 3단계 검증을 통과하면 uploadFile가 내가 올린 이미지 파일을 보낸다.
이미지를 보내고 받은 url을 result에 담아줬다.
이 부부은 조금 더 공부를 해서 올려야 겠다.
function onChangeFileUrls(fileUrl: string, index: number) {
const newFileUrls = [...fileUrls];
newFileUrls[index] = fileUrl;
setFileUrls(newFileUrls);
}
여기까지 해주면 이미지등록이 완료!
짱짱 이제 등록하기 버튼을 누르면 상세페이지에서 내가 올린 이미지 url을 맵으로 가져와서 화면이 보여주면 된다!
정리하면..
1. uploadfile 컴포넌트를 만들어준다.
1.1 container에 uploadFile해주는 함수를 만들어준다.
1.2 실제 이미지 파일을 가져올 수 있는 input 태그에 ref 속성을 넣어준다.
1.3 presenter에 props 시켜준다.
<Uploads01UI
fileRef={fileRef} fileUrl={props.fileUrl}
onClickUpload={onClickUpload}
onChangeFile={onChangeFile} />
1.4 presenter에 삼항연사자로 조건에 맞는 화면을 만들어 준다.
2. 등록페이지에 uploadfile import시키기
2-1. BoardWrite.container 에 fileUrl state를 만들어서 BoardPresenter에 props 해준다.
...keepcoing