Advanced Course 주특기 3강 - React

박경준·2021년 7월 4일
0

advanced course - react

목록 보기
3/8

심화 주특기 3강!

  1. 파이어스토어로 데이터를 관리한다.
  2. 파이어베이스의 스토리지 서비스를 사용하여 이미지 업로드 기능을 만든다.
  3. 파일 업로드 전 이미지 미리보기를 하려면 어떻게 하는 지 알아본다.
  4. 잦은 이벤트 처리 기법에 대해 알아본다.

여러가지 잔기술...

reduce 쓰는 법

let _post = doc.data();
let post = Object.keys(_post).reduce(
  // reduce 쓰는법 참고!!!
  (acc, cur) => {
    if (cur.indexOf("user_") !== -1) {
      return {
        ...acc,
        user_info: { ...acc.user_info, [cur]: _post[cur] },
        // [cur] 이렇게 써야 cur의 변수 값이 들어가짐. 그냥 cur 쓰면 문자열이 들어감...?!
        // value 가져올때도 _post.cur라고 쓰면 안되고 _post[cur] 라고 써야함
        // reduce만의 특징인듯?
      };
    }
    return { ...acc, [cur]: _post[cur] };
  },
  { id: doc.id, user_info: {} }
  // 초기값 지정
);

딕셔너리를 한번에 props 넘기는 법

return <Post key={p.id} {...p}></Post>;
// p에 있는 각 key, value를 한 번에 props로 넘겨줄때 {...p} 이렇게 쓰면 되네...?

특이한 딕셔너리 할당법 (위와 반대 상황)

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

PostDB.add({ ...user_info, ..._post })
  .then((doc) => {
  let post = { user_info, ..._post, id: doc.id };
  // {user_info} 이렇게 넣으면 알아서
  // {user_info: {user_name: _user.user_name, user_id: _user.uid, user_profile: _user.user_profile}} 이렇게 됨.
  dispatch(addPost(post));
  history.replace("/");
})
  .catch((err) => {
  console.log("post 작성에 실패했습니다", err);
});

FileReader() 쓰는 법

const fileInput = React.useRef();
const selectFile = (e) => {
  const reader = new FileReader();
  const file = fileInput.current.files[0];
  reader.readAsDataURL(file);
  reader.onloadend = () => {
    dispatch(imageActions.setPreview(reader.result));
  };
};

return (
  <React.Fragment>
    <input
      type="file"
      onChange={selectFile}
      ref={fileInput}
      />
  </React.Fragment>
);

이미지와 게시글을 같은 버튼(같은 actioncreator) 올리는법

const _image = getState().image.preview;
const _upload = storage.ref(
  `images/${user_info.user_id}_${new Date().getTime()}`.putString(
    _image,
    "data_url"
  )
);
_upload.then((snapshot) => {
  // 먼저 이미지를 firebase storage에 올리고
  snapshot.ref
    .getDownloadURL()
    .then((url) => {
    return url;
    // 생성된 firebase storage 이미지 주소를 가져와서
  })
    .then((url) => {
    // 그 이미지 주소로 firestore에 저장함.
    // 이러면 게시글 작성 버튼으로 사진과 글을 한번에 저장할 수 있음.
    PostDB.add({ ...user_info, ..._post, image_url: url })
      .then((doc) => {
      let post = { user_info, ..._post, id: doc.id, image_url: url };
      // {user_info} 이렇게 넣으면 알아서
      // {user_info: {user_name: _user.user_name, user_id: _user.uid, user_profile: _user.user_profile}} 이렇게 됨.
      dispatch(addPost(post));
      history.replace("/");
    })
      .catch((err) => {
      console.log("post 작성에 실패했습니다", err);
    });
  });
});

styled components에서 변수 사용하는 법

const ImageDefault = styled.div`
  --size: ${(props) => props.size}px;
  // css 값을 변수화해서
  width: var(--size); // 이렇게 불러서 사용함
  height: var(--size);
  background-image: url("${(props) => props.src}");
  background-size: cover;
`;

이미지 수정하는 법

// post.js
const editPostFB = (post_id = null, post = {}) => {
  return function (dispatch, getState, { history }) {
    if (!post_id) {
      console.log("게시글 정보가 없어요.");
      return;
    }

    const _image = getState().image.preview;
    const _post_idx = getState().post.list.findIndex((p) => p.id === post_id);
    // findIndex: 조건에 일치하는 요소의 index를 반환함
    const _post = getState().post.list[_post_idx];
    const postDB = firestore.collection("image_community");

    if (_image === _post.image_url) {
      // 이미지는 수정 안하고, 게시글 내용만 수정할때
      postDB
        .doc(post_id)
        .update(post)
        .then((doc) => {
        dispatch(editPost(post_id, { ...post }));
        history.replace("/");
      });
    } else {
      // 이미지와 게시글 내용 모두 수정할때
      // 이미지는 storage에서 수정을 해줘야하기때문에 분기함.
      const user_id = getState().user.user.uid;
      const _upload = storage
      .ref(`images/${user_id}_${new Date().getTime()}`)
      .putString(_image, "data_url");
      _upload.then((snapshot) => {
        snapshot.ref
          .getDownloadURL()
          .then((url) => {
          return url;
        })
          .then((url) => {
          postDB
            .doc(post_id)
            .update({ ...post, image_url: url })
            .then((doc) => {
            dispatch(editPost(post_id, { ...post, image_url: url }));
            history.replace("/");
          });
        })
          .catch((err) => {
          window.alert("이미지 업로드에 실패했어요.");
          console.log("앗, 이미지 업로드에 문제가 있어요.");
        });
      });
    }
  };
};

...

export default handleActions(
  {
    ...
    [EDIT_POST]: (state, action) =>
    produce(state, (draft) => {
      let idx = draft.list.findIndex((p) => p.id === action.payload.post_id);
      draft.list[idx] = { ...draft.list[idx], ...action.payload.post };
      // immer를 사용중인데도 스프레드 문법을 쓰는 이유...
      // action.payload.post에서 게시글 내용만 바뀌었을지, 사진도 바뀌었을지 모름.
      // 근데 이걸 분기해서 하자니 귀찮음.
      // 그래서 변경된건 알아서 처리해달라는 의미로 스프레드 문법 사용
    }),
  },
  initialState
);
profile
빠굥

0개의 댓글