리액트 심화반 3주차 - 1

35282 단어 ReactReact

22.04.19(화)
스파르타코딩클럽 리액트 심화반 - 2주차 과정 - 2

◎ 포스트 목록 가져오기

  • module 만들기
// src > redux > modules > post.js

// import
import { createAction, handleActions } from "redux-actions"; // Action Creater를 쉽게 만들어줌
import { produce } from "immer"; // 불변성 관련 library

import { firestore } from "../../shared/firebase";
import moment from "moment"

// action
const SET_POST = "SET_POST";
const ADD_POST = "ADD_POST";

// action creators / Using redux-actions
const setPost = createAction(SET_POST, (post_list) => ({post_list}))
const addPost = createAction(ADD_POST, (post) => ({post}))

// initialState
const initialState = {
    list: [],
}

const initialPost = {
    image_url: "https://velog.velcdn.com/images%2Fgwichanlee%2Fpost%2F5cc3bbe0-550a-4cb7-8804-467f420f6002%2Ftest2.jpg",
    contents: "",
    comment_cnt: "0",
    insert_dt: moment().format("YYYY-MM-DD hh:mm:ss"),
};

// reducer Using redux-actions, immer
export default handleActions(
    {
        [SET_POST]: (state, action) => produce(state, (draft) => {
            draft.list = action.payload.post_list
        }),

        [ADD_POST]: (state, action) => produce(state, (draft) => {
            draft.list.unshift(action.payload.post);
        }),
    }, initialState
);

// export
const actionCreators={
    setPost,
    addPost,
    getPostFB,
    addPostFB,
}

export {actionCreators}
  • rootreducer에 추가 (Storeconfig 설정)
// redux/configureStore.js
...
import Post from "./modules/post";
...
const rootReducer = combineReducers({
  user: User,
  post: Post,
  router: connectRouter(history),
});
...
  • 게시글 연동하기
// pages/PostList.js
...
import {useSelector} from "react-redux";
import Post from "../components/Post";
...
const PostList = (props) => {
	const post_list = useSelector((state) => state.post.list);
...
return (
        <React.Fragment>
            {post_list.map((p, idx) => {
                return <Post key={p.id} {...p}/>
            })}
        </React.Fragment>
    )
...

◎ 파이어스토어 연동하기

  • Firebase Console에서 Firebase Store 활성화 및 임시 데이터 넣어놓기
  • firebase.js 에 Firestore 추가
 // shared/firebase.js
import "firebase/firestore";
...
const firestore = firebase.firestore();
...
export{auth, apiKey, firestore};
  • firestore에서 데이터 가져오기
//redux/modules/post.js
import { firestore } from "../../shared/firebase";
...
const getPostFB = () => {
  return function (dispatch, getState, { history }) {
    const postDB = firestore.collection("post"); // firestore.collection 가져오기, "post": collection 이름

    postDB.get().then((docs) => {
      let post_list = [];

      // 반복문 사용
      docs.forEach((doc) => { 
        
        // console.log(doc.id, doc.data()); // 데이터 형태 확인

        let _post = doc.data(); // 데이터 내용 가져오기
        // 데이터 모양 수정
        let post = {
            id: doc.id,
            user_info: {
                user_name: _post.user_name,
                user_profile: _post.user_profile,
                user_id: _post.user_id,
            },
            contents: _post.contents,
            image_url: _post.image_url,
            comment_cnt: _post.comment_cnt,
            imsert_dt: _post.insert_dt
        }

        post_list.push(post);
      });

      // 리스트 확인하기!
      console.log(post_list);

      dispatch(setPost(post_list)); // Action을 Dispatch함
    });
  };
};
...
  • useEffect를 통해, getpostFB 실행
// PostList.js
// 최초 로딩시에 실행
React.useEffect(() => {
  dispatch(postActions.getPostFB());
}, []);

◎ 포스트 작성하기

  • 로그인 후에만 /write에 접근하게 하기
    • useSeletor를 이용해 state.user.is_login 값을 가져옴
    • is_login 값이 false 일때, 다른 페이지를 보여줌
    • (+) 버튼 누를 때, history.push("/write")
  • 작성한 게시글 내용 넘겨주기 (contents에 inputbox값 가져오기)
const [contents, setContents] = React.useState('');
...
const changeContents = (e) => {
    setContents(e.target.value);
}
...
<Grid padding="16px">
    <Input _onChange={changeContents} label="게시글 내용" placeholder="게시글 작성" multiLine />
</Grid>
  • firestore에 데이터 넣기
    • moment 설치 (현재 날짜, 시간을 쉽게 사용할 수 있음)
    yarn add moment
    • firestore에 저장하는 함수 만듦 / 성공시, redux에 데이터를 넣음.
    // redux/modules/post.js
    import moment from "moment";
    ...
    const initialPost = {
      image_url: "기본 이미지 url",
      contents: "",
      comment_cnt: 0,
      insert_dt: moment().format("YYYY-MM-DD hh:mm:ss"),
    };
    ...
    const addPostFB = (contents = "") => {
      return function (dispatch, getState, { history }) {
        // DB를 설정
        const postDB = firestore.collection("post");
        // user 정보를 state에서 가져옴
        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: contents,
          insert_dt: moment().format("YYYY-MM-DD hh:mm:ss")
        };
        // 잘 만들어졌나 확인
        // console.log(_post);
    		  // DB에 내용 저장	
        postDB.add({...user_info, ..._post}).then((doc) => {
            // 아이디를 추가
            let post = {user_info, ..._post, id: doc.id};
            // redux에 넣어줌
            dispatch(addPost(post));
            // 페이지 이동 / replace: 뒤로가기시, 원래 페이지로 안감
            history.replace("/")
        }).catch((err) => {
            console.log('post 작성 실패!', err);
        });
      };
    };
    ... 
    [ADD_POST]: (state, action) => produce(state, (draft) => {
            // unshift: 배열 맨 앞에 데이터를 넣어줌
             draft.list.unshift(action.payload.post);
        }),

◎ firebase Storage

  • 이미지 업로드시, 이용할 예정
  • Storge 연결하기 및 Firebase Console Rules 세팅
// shared/firebase.js
...
import "firebase/firestore";
import "firebase/storage";
...
const apiKey = firebaseConfig.apiKey;
const auth = firebase.auth();
const firestore = firebase.firestore();
const storage = firebase.storage();

export{auth, apiKey, firestore, storage};
// 파이어베이스 콘솔 -> Storage에서 규칙(rules) 탭으로 이동!아래처럼 바꿔주기!
rules_version = '2';
service firebase.storage {
  match /b/{bucket}/o {
    match /{allPaths=**} {
			allow read, write: if request.auth != null;
    }
  }
}

좋은 웹페이지 즐겨찾기