sooleeandtomas

Firebase Storage 사용 : 이미지 저장 본문

코딩 공부 노트/React

Firebase Storage 사용 : 이미지 저장

sooleeandtomas 2021. 5. 13. 21:51

1. Firebase FireStore

 

firebase console > firestore 에서 아주 깔끔한 UI로 DB를 저장할 수 있습니다.

mySQL 을 잠깐 다뤄봤는데 설치부터 계정 연결까지 아주 머리가 아팠거든요.

firebase는 그에 반해 정말 쉽게 DB를 저장할 수 있어서 좋은 것 같습니다.

firebase storage 화면
mySQL DB 화면

 

코드에서 firebase store 사용 설정 firebase.js

import "firebase/firestore";

const firebaseConfig = {
  apiKey: "AIzaSyDzso2zaGiat_YYrH0PFi2Y7Grhxf9OXkk",
  authDomain: "imgcommunity-46e15.firebaseapp.com",
  projectId: "imgcommunity-46e15",
  storageBucket: "imgcommunity-46e15.appspot.com",
  messagingSenderId: "88009085502",
  appId: "1:88009085502:web:b79dd8f4407945f393b76f",
  measurementId: "G-SJM3XP072F"
};

firebase.initializeApp(firebaseConfig);

const firestore = firebase.firestore();

export { firestore };

 


 

2.  redux

 

GetPost 게시글 가져오기 : setPost

redux코드 firestore.collection([storename]).get()

1. 어떤 DB를 사용할 지 설정 

2. DB.get() 함수 요청

const getPostFB = () => {
  return function (dispatch, getState, {history}){
    const postDB = firestore.collection("post");
    postDB.get()
      .then(docs=>{
        docs.forEach(doc => {
          console.log(doc.id, doc.data());
        })
      })
  }
}

 

 

3. fb에서 가져온 데이터를 reducer 형식에 맞게 정리하기

4. reducer에 설정해 놓은 initialState 형식대로 [ ] 배열에 담기

5. dispatch로 리듀서 setPost에 보내기  

const getPostFB = () => {
  return function (dispatch, getState, {history}){
    const postDB = firestore.collection("post");
    postDB.get()
      .then(docs=>{
        let post_list = []
        docs.forEach(doc => {
          let _post = doc.data();
          
          let post = {
            id: doc.id,
            image_url: _post.image_url,
            contents: _post.contents,
            comment_cnt : _post.comment_cnt,
            insert_dt: _post.insert_dt,
            user_info:{
              user_name: _post.user_name,
              user_profile: _post.user_profile,
              user_id: _post.user_id
            }
          }
          post_list.push(post);
        })
        
        dispatch(setPost(post_list));
      })
  }
}

 

꿀팁! 3번 - fb에서 가져온 데이터를 잘 정리할 때  reduce로 정리하면 코드가 짧아집니다.

const getPostFB = () => {
  return function (dispatch, getState, {history}){
    const postDB = firestore.collection("post");
    postDB.get()
      .then(docs=>{
        let post_list = []
        docs.forEach(doc => {
          let _post = doc.data();
          
          let post = Object.keys(_post)
            .reduce((acc,cur)=>{
              if (cur.indexOf("user_") !== -1){ //user_정보가 있다면
                return { ...acc, user_info: { ...acc.user_info, [cur]: _post[cur] } }
              }
              return {...acc, [cur]: _post[cur]}
            }, {id: docs.id, user_info: {}})
          post_list.push(post);
        })

        dispatch(setPost(post_list));
      })
  }
}

Object.keys(_post) 를 이용하면 {  } 객체안의 키값들을 [ ] 배열로 넣어줍니다.

배열을 하나씩 순회하면서 cur : _post[cur] 로 넣어주면 됩니다.

_post[cur] : _post의 키값이 cur 인 value를 반환해줍니다.

 

 


 

addPost  게시글 추가하기 : addPost

1. 어떤 DB를 사용할 지 설정해주기

2. getState()로 현재 user의 정보 가져오기

3. 넘겨받은 contents, moment 정보 가져오기

4.  2번과 3번 합치기 

5. DB.add() 함수로 데이터(4번에서 합침)넘겨주기 

5-1 . DB가 post를 저장함과 동시에, id값을 부여해줍니다.

6. then (doc) => {

   7. redux의 addPost() 함수로 데이터(4번에서 합침) + id 값을 보내주기   

   8. history.replace("/")

}

 

const addPostFB = (contents="", ) => {
  return function(dispatch, getState, {history}){
    const postDB = firestore.collection("post");
    const _user = getState().user.user;

    const user_info = {
      user_name: _user.user_name,
      user_id: _user.uid,
      user_profile: _user.user_profile
    }

    const _post = {
      ...initialPost, 
      contents,
      inser_dt: moment().format("YYYY-MM-DD hh:mm:ss"),
    }

    //firebase Save Data
    postDB.add({...user_info, ..._post})
      .then(doc => {
        let post = {user_info, ..._post, id: doc.id}
        dispatch(addPost(post));
        history.replace("/");
     }).catch(err => {
        console.log("작성 실패했습니다." ,err)
      })
    }
}

 


 

3. Firebase Storage

aws 서비스처럼 이미지도 저장하고, 링크를 받아올 수 있도록 해줍니다. (파이어혜자)

 

1. firebase.js  storage 사용하기 설정

import "firebase/storage";

const firebaseConfig = {
  apiKey: "AIzaSyDzso2zaGiat_YYrH0PFi2Y7Grhxf9OXkk",
  authDomain: "imgcommunity-46e15.firebaseapp.com",
  projectId: "imgcommunity-46e15",
  storageBucket: "imgcommunity-46e15.appspot.com",
  messagingSenderId: "88009085502",
  appId: "1:88009085502:web:b79dd8f4407945f393b76f",
  measurementId: "G-SJM3XP072F"
};

firebase.initializeApp(firebaseConfig);

const storage = firebase.storage();

export { storage };

 

 

 

2. input -> 이미지(File) 파이어베이스에 올립니다.

3. firebase에서 url 보내주기

  const uploadFB = () => {
    let image = inputRef.current.files[0];
    dispatch(imageActions.uploadImgFB(image))
  }
const uploadImgFB = (img) => {
  return function (dispatch, getState, {history}){

    dispatch(uploading(true));

    const _upload = storage.ref(`images/${img.name}`).put(img);

    _upload.then((snapshot)=>{
      snapshot.ref.getDownloadURL()
        .then((url)=>{
          dispatch(uploadImg(url))
          console.log(url)
        })
      }
    )
  }
}

 

4. 리덕스에 이미지 경로를 넣어주기

export default handleActions({
  [UPLOAD_IMG] : (state, action) => produce(state, (draft) => {
    draft.image_url = action.payload.image_url;
    draft.uploading = false;
  }),
  [UPLOADING] : (state, action) => produce(state, (draft) => {
    draft.uploading = action.payload.uploading;
  }),
}, initialState);

 

5. uploading 상태로 input 버튼 제어하기

const Upload = props => {
  const inputRef = useRef();
  const dispatch = useDispatch();
  const is_uploading = useSelector(state => state.image.uploading);

  const uploadFB = () => {
    let image = inputRef.current.files[0];
    dispatch(imageActions.uploadImgFB(image))
  }

  return(
    <Fragment>
      <input
        ref={inputRef}
        type="file"
        disabled={is_uploading}
      />
      <Button 
        bg="dark"
        _onClick={uploadFB}
        txt="upload"
      />
    </Fragment>
  )
};

 

 

* data:64를 FB에 보내서 url 얻기

const addPostFB = (contents="", ) => {
  return function(dispatch, getState, {history}){
    const _image = getState().image.preview;
    const _upload = storage.ref(`images/${user_info.user_id}_${new Date().getTime()}`).putString(_image, "data_url");

    _upload.then(snapshot => {
      snapshot.ref.getDownloadURL().then(url=>{return url})
        .then(url => {
          //firebase Save Data
          postDB.add({...user_info, ..._post, image_url: url})
            .then(doc => {
              let post = {user_info, ..._post, id: doc.id, image_url: url}
              dispatch(addPost(post));
              history.replace("/");
              dispatch(imageActions.setPreview(null));
            }).catch(err => {
              console.log("포스트 작성에 실패했습니다.", err)
              console.log("포스트 작성에 실패했습니다.", err)
              })
        }).catch(err => {
          window.alert("이미지 업로드에 문제가 있습니다.")
          console.log("업로드 문제가 있습니다.", err);
        })
      })
    }
}

 

 

* data:64를 FB에 보내서 url 얻은 후에 redux에 저장하기

const addPostFB = (contents="", ) => {
  return function(dispatch, getState, {history}){
    const postDB = firestore.collection("post");
    const _user = getState().user.user;

    const user_info = {
      user_name: _user.user_name,
      user_id: _user.uid,
      user_profile: _user.user_profile
    }

    const _post = {
      ...initialPost, 
      contents,
      insert_dt: moment().format("YYYY-MM-DD hh:mm:ss"),
    }

    const _image = getState().image.preview;

    const _upload = storage.ref(`images/${user_info.user_id}_${new Date().getTime()}`).putString(_image, "data_url");

    _upload.then(snapshot => {
      snapshot.ref.getDownloadURL().then(url=>{return url})
        .then(url => {
          //firebase Save Data
          postDB.add({...user_info, ..._post, image_url: url})
            .then(doc => {
              let post = {user_info, ..._post, id: doc.id, image_url: url}
              dispatch(addPost(post));
              history.replace("/");
              dispatch(imageActions.setPreview(null));
            }).catch(err => {
              console.log("포스트 작성에 실패했습니다.", err)
              console.log("포스트 작성에 실패했습니다.", err)
              })
        }).catch(err => {
          window.alert("이미지 업로드에 문제가 있습니다.")
          console.log("업로드 문제가 있습니다.", err);
        })
      })
    }
}

 

Comments