反応深化班3週目-1


22.04.19(火)
スパルタ符号化クラブ反応深化班-第2週過程-2

◇記事リストのインポート


作成
  • モジュール
  • // 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>
        )
    ...

    ◇Fire Storeのバインド

  • FirebaseコンソールでFirebase Storeを有効にし、一時データ
  • を配置します.
  • firebase.Firestoreをjsに追加する
  •  // 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함
        });
      };
    };
    ...
  • userEffectによるgetPostFB
  • の実行
    // PostList.js
    // 최초 로딩시에 실행
    React.useEffect(() => {
      dispatch(postActions.getPostFB());
    }, []);

    ◇文章を書く

  • ログイン後のみ/writeにアクセス
  • UserSeletor stateを使用します.user.is login値
  • is login値がfalseの場合、他のページの
  • が表示されます.
  • (+)ボタンを押すとhistory.push("/write")
  • による投稿の送信(inputbox値をcontentsにインポート)
  • const [contents, setContents] = React.useState('');
    ...
    const changeContents = (e) => {
        setContents(e.target.value);
    }
    ...
    <Grid padding="16px">
        <Input _onChange={changeContents} label="게시글 내용" placeholder="게시글 작성" multiLine />
    </Grid>
  • Firestoreにデータを入れる
  • 分インストール(現在の日付、時間が使いやすい)
  • 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コンソール規則
  • を設定します.
    // 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;
        }
      }
    }