[인스타그램 클론코딩] 06. 게시글 Posting 구현(Front-End)

2023. 2. 2. 14:29·Web/인스타 클론 코딩

먼저 만들기 탭의 내용인 게시글 Posting을 구현한다. 로직은 다음과 같다.

1. 사진이나 동영상을 선택한다.

2. 글을 작성한다.

3. 공유하기 버튼을 통해 서버에 등록한다.

4. 홈탭으로 리다이렉팅한다.

 

포스트 화면의 구성은 다음과 같다.

1. 헤더 부분 : 제목과 공유하기 버튼으로 구성

2. 바디 부분 : 파일선택, 사용자 정보 및 게시글 작성 부분으로 구성

만들기 탭 구성 화면

 

1.  PostContainer.js 작성

- 포스팅 화면을 랜더링할 가장 큰 컴포넌트이다.

import React, {useEffect, useState} from 'react';
import style from './Post.module.css';
import PostFile from "./PostFile";
import PostWrite from "./PostWrite";
import multiFileAxios from "../../components/axios/multiFileAxios";
import {useNavigate} from "react-router-dom";

const PostContainer = () => {

    const navigate = useNavigate();

    /* 게시글 변경 */
    const [write, setWrite] = useState();
    const onChangeWrite = (e) => {
        setWrite(e.target.value);
    }

    /* 게시물 파일 변경 */
    const [files, setFiles] = useState();
    // let files = useRef();
    const [fileNum, setFileNum] = useState(0);

    const onChangeFiles = (inputs) => {
        setFiles(inputs);
    };

    const fileNumInc = () => {
        if(fileNum < files.length-1) {
            setFileNum(fileNum => {
                return fileNum + 1;
            });
        }
    }

    const fileNumDec = () => {
        if(fileNum > 0) {
            setFileNum(fileNum => {
                return fileNum - 1;
            });
        }
    }

    const onSubmit = () => {
        if(files === undefined | files === '') {
            alert("사진을 선택하세요");
            return;
        }

        const formData = new FormData();
        const size = files.length;

        for(let i=0; i<size; i++) {
            formData.append("file", files[i]);
        }
        formData.append("content", JSON.stringify(write));

        console.log(formData)

        multiFileAxios.post('/post', formData)
            .then((response) => {
                navigate("/outstagram/home");
            });
    }

    useEffect(() => {

    }, [files])

    return (
        <div className={style.post_container}>
            <div className={style.post_header_container}>
                <div/>
                <div>
                    새 게시물 만들기
                </div>
                <div className={style.submit} onClick={onSubmit}>
                    공유하기
                </div>
            </div>
            <div className={style.post_body_container}>
                <PostFile files={files} fileNum={fileNum} fileNumInc={fileNumInc} fileNumDec={fileNumDec} onChangeFiles={onChangeFiles}/>
                <PostWrite onChangeWrite={onChangeWrite}/>
            </div>
        </div>
    );
};

export default PostContainer;

 

- 선택된 파일과 글을 formData로 싼 뒤, 서버에 post 요청한다.

 

2. PostFile.js 작성

import React, {useEffect, useState} from 'react';
import style from './PostFile.module.css'
const PostFile = (props) => {
    const files = props.files;
    const fileNum = props.fileNum;
    const onChangeFiles = props.onChangeFiles;
    const fileNumInc = props.fileNumInc;
    const fileNumDec = props.fileNumDec;

    const [thumbFile, setThumbFile] = useState({src: '', type: ''});
    const setThumbnail = (file) => {
        const reader = new FileReader()
        const type = file.type.split('/')[0];

        if(type === 'image') {
            reader.readAsDataURL(file);
            reader.onloadend = () => {
                setThumbFile(() => {return {src: reader.result, type: type};});
            }
        }
        if(type === 'video') {
            const videoUrl = URL.createObjectURL(file);
            setThumbFile(() => {return {src: videoUrl, type: type};});
        }
    }

    useEffect(() => {
        if(files != undefined) {
            setThumbnail(files[fileNum]);
        }
    }, [fileNum, files])

    return (
        <div className={style.post_file_container}>
            {files === undefined ?
                <>
                    <label className={style.selector} htmlFor='file'>
                        <i className="bi bi-images fs-1"></i>
                        <div style={{fontSize: '20px', marginTop:'10px', fontWeight:'bold'}}>
                            사진을 선택하세요
                        </div>
                    </label>
                    <input type='file' id='file' accept='image/*, video/*' onChange={(e) => onChangeFiles(e.target.files)} style={{display:'none'}} multiple/>
                </>
                :
                <div className={style.thumbnail_container}>
                    <i className="bi bi-arrow-left-circle-fill" onClick={fileNumDec}/>
                    {thumbFile.type === 'image' ?
                        <img className={style.thumbnail} src={thumbFile.src} /> :
                        <video className={style.thumbnail} controls='true' src={thumbFile.src}>
                        </video>
                    }
                    <i className="bi bi-arrow-right-circle-fill"  onClick={fileNumInc}/>
                </div>
            }
        </div>
    );
};

export default PostFile;

 

- PostContainer로 부터 files, fileNum, onChangeFiles, fileNumInc, fileNumDec를 프롬스로 받아온다.

- input의 파일 속성을 통해 입력받은 파일들을 files에 등록한다.

- 서버에 올리기전 등록한 파일들을 볼 수 있도록 뷰를 작성하였다.

 

3. PostWrite.js 작성

import React from 'react';
import style from './PostWrite.module.css'
import {Static_Base_Url} from "../../index";
import {useSelector} from "react-redux";

const PostWrite = (props) => {
    const onChangeWrite = props.onChangeWrite;
    const userDetail = useSelector(state => state.userDetail);

    return (
        <div className={style.post_write_container}>
            <div className={style.header}>
                <img className={style.header_thumbnail} src={Static_Base_Url + userDetail.profileUrl}/>
                <div className={style.header_nickname}>{userDetail.nickname}</div>
            </div>
            <textarea className={style.inputs} name='write' onChange={onChangeWrite} placeholder="문구 입력..."></textarea>
        </div>
    );
};

export default PostWrite;

 

- PostContainer로 부터 onChangeWrite를 프롭스로 받아, textarea에 입력된 값을 write에 저장한다.

 

4. 동작 화면

 

저작자표시 비영리 변경금지 (새창열림)

'Web > 인스타 클론 코딩' 카테고리의 다른 글

[인스타그램 클론코딩] 07. 팔로우 기능 구현(Front-End)  (0) 2023.02.02
[인스타그램 클론코딩] 06. 게시글 Posting 구현(Back-End)  (0) 2023.02.02
[인스타그램 클론코딩] 05. 기본 화면 구성(Front-End)  (0) 2023.02.02
[인스타그램 클론코딩] 04. JWT 필터 구현(Front-End)  (0) 2023.02.01
[인스타그램 클론코딩] 04. JWT 필터 구현(Back-End)  (0) 2023.02.01
'Web/인스타 클론 코딩' 카테고리의 다른 글
  • [인스타그램 클론코딩] 07. 팔로우 기능 구현(Front-End)
  • [인스타그램 클론코딩] 06. 게시글 Posting 구현(Back-End)
  • [인스타그램 클론코딩] 05. 기본 화면 구성(Front-End)
  • [인스타그램 클론코딩] 04. JWT 필터 구현(Front-End)
뚝딱뚝딱2
뚝딱뚝딱2
  • 뚝딱뚝딱2
    개발도상국
    뚝딱뚝딱2
  • 전체
    오늘
    어제
    • 분류 전체보기
      • 공부
        • Java
        • Spring Boot
        • LORA
      • Web
        • 인스타 클론 코딩
        • GPT 응답 API 서버
        • Spring Boot 예외 처리
        • 코테 준비용 서비스 만들기
      • DevOps
        • 쿠버네티스
        • 서버 만들기
      • 코딩테스트
        • 알고리즘
      • 교육
        • 스파르타코딩클럽 - 내일배움단
        • 혼자 공부하는 컴퓨터 구조 운영체제
      • 잡다한것
  • 블로그 메뉴

    • 홈
  • 링크

    • GITHUB
  • 공지사항

  • 인기 글

  • 태그

    쿠버네티스
    백준
    Entity
    스프링 부트
    클러스터
    오블완
    스프링부트
    OpenAI API
    MSA
    chat GPT
    인스타그램
    리액트
    spring boot
    클론코딩
    REST API
    react
    mapstruct
    Java
    예외
    티스토리챌린지
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.1
뚝딱뚝딱2
[인스타그램 클론코딩] 06. 게시글 Posting 구현(Front-End)
상단으로

티스토리툴바