13일차

그루트·2021년 9월 28일
0

firestore 데이터를 리덕스 스토어에 넣으려면? (미들웨어 설치!)

우리가 firestore에서 데이터를 가져올 때 비동기 통신을 한다고 했죠!
리덕스에서 비동기 통신을 할 때 필요한 미들웨어라는 친구 먼저 설치할 거예요.

미들웨어가 뭐냐구요?
리덕스 데이터를 수정할 때 [액션이 디스패치 되고 → 리듀서에서 처리] 하던 과정 기억하시죠?
미들웨어는 이 과정 사이에 미리 사전 작업을 할 수 있도록 하는 중간 다리 같은 거예요!
즉! [액션이 일어나고 → 미들웨어가 할 일 하기 → 리듀서에서 처리] 이 순서로 처리하게 됩니다!

yarn add redux-thunk

redux-thunk는 뭐하는 미들웨어일까?
우리 액션 생성 함수가 뭘 반환한다고 했었죠? 맞아요! 객체 반환하죠. 🙂
redux-thunk는 객체 대신 함수를 생성하는 액션 생성함수를 작성할 수 있게 해줍니다!

그게 왜 필요하냐구요?
리덕스는 기본적으로는 액션 객체를 디스패치합니다! → 즉, 함수를 생성하면 특정 액션이 발생하기 전에 조건을 주거나, 어떤 행동을 사전에 처리할 수 있겠죠!!

설치가 끝났다면! configStore.js에 미들웨어를 추가해봅시다! 그럼 준비 끝!

import { createStore, combineReducers, applyMiddleware, compose } from "redux";
import thunk from "redux-thunk";
import bucket from "./modules/bucket";

export const history = createBrowserHistory();

const middlewares = [thunk];

const enhancer = applyMiddleware(...middlewares);
const rootReducer = combineReducers({ bucket });
const store = createStore(rootReducer, enhancer);

export default store;

firestore 적용하기

(1) load할 때 데이터를 가지고 와보자!

일단은 액션부터!

// 액션 타입
const LOAD = "bucket/LOAD";
...
// 액션 생성 함수
export function loadBucket(bucket_list){
  return {type: LOAD, bucket_list};
}

파이어베이스랑 통신하는 함수 만들고,


import {
  collection,
  doc,
  getDoc,
  getDocs,
  addDoc,
  updateDoc,
  deleteDoc,
} from "firebase/firestore";

import {db} from "../../firebase";

// 파이어베이스랑 통신하는 부분
export const loadBucketFB = () => {
  return async function (dispatch) {
    // 데이터를 가져와요!
    const bucket_data = await getDocs(collection(db, "bucket"));
    
    let bucket_list  = [];

    // 하나씩 우리가 쓸 수 있는 배열 데이터로 만들어줍시다!
    bucket_data.forEach((b) => {
      // 콘솔로 확인해요!
      console.log(b.id, b.data());
      bucket_list.push({ id: b.id, ...b.data() });
    });

    // 잘 만들어졌는 지 리스트도 확인해봐요! :)
    console.log(bucket_list);
    dispatch(loadBucket(bucket_list));
  }
}

리듀서를 고쳐요!

case "bucket/LOAD": {
      return {list: action.bucket_list}
    }

그 후에는요? 불러다 쓰면 되겠죠!

// App.js
...
// 잠깐!! loadBucketFB를 import해오는 거 잊지말기!
React.useEffect( () => {
    dispatch(loadBucketFB());
  }, []);
...

(2) create에 firestore 적용

순서는 항상 똑같을 거예요!
파이어베이스랑 통신 → 필요하다면 리듀서 고치고 → 불러다 쓰기

import { db } from "./firebase";
import { collection, addDoc } from "firebase/firestore";
...
const docRef = await addDoc(collection(db, 'bucket'), {
     completed: false,
     text: "new"
   })

파이어베이스랑 통신하는 함수 만들고,

// 파이어베이스랑 통신하는 부분
export const addBucketFB = (bucket) => {
  return async function (dispatch) {
		// 파이어스토어에 추가하기를 기다려요!
    const docRef = await addDoc(collection(db, "bucket"), bucket);
		// 추가한 데이터 중 id를 가져와서 bucket_data를 만들어줬어요!
    const bucket_data = { id: docRef.id, ...bucket };
		// 그럼 이제 액션을 일으키자! (수정해달라고 요청하자!)
    dispatch(createBucket(bucket_data));
  }
}

그 후에는요? 불러다 쓰면 되겠죠!

// App.js
...
// 잠깐!! addBucketFB를 import해오는 거 잊지말기!
const addBucketList = () => {   
    dispatch(addBucketFB({ text: text.current.value, completed: false }));
  };

(3) update에 firestore 적용
순서는 항상 똑같을 거예요!
파이어베이스랑 통신 → 필요하다면 리듀서 고치고 → 불러다 쓰기

import { db } from "./firebase";
import { collection, doc, updateDoc } from "firebase/firestore";
...
React.useEffect(async() => {
    const docRef = doc(db, "bucket", "[도큐먼트 아이디]");
    await updateDoc(docRef, {
      completed: true,
    });

  }, []);

파이어베이스랑 통신하는 함수 만들고,

// 파이어베이스랑 통신하는 부분
export const updateBucketFB = (bucket_id) => {
  return async function (dispatch, getState) {
		// 수정할 도큐먼트를 가져오고,
    const docRef = doc(db, "bucket", bucket_id);
		// 수정합시다!
    await updateDoc(docRef, { completed: true });
		// getState()를 사용해서 스토어의 데이터를 가져올 수 있어요.
    console.log(getState().bucket);
    // bucket list 데이터를 가져와요.
    const _bucket_list = getState().bucket.list;
		// findIndex로 몇 번째에 있는 지 찾기!
    const bucket_index = _bucket_list.findIndex((b) => {
			// updateBucketFB의 파라미터로 넘겨받은 아이디와 
			// 아이디가 독같은 요소는 몇 번째에 있는 지 찾아봐요!
      return b.id === bucket_id;
    })

    dispatch(updateBucket(bucket_index));
  };
};

그 후에는요? 불러다 쓰면 되겠죠!

// Detail.js
...
// 잠깐!! updateBucketFB를 import해오는 거 잊지말기!
<button onClick={() => {
          dispatch(updateBucketFB(bucket_list[bucket_index].id));
      }}>완료하기</button>
...

(4) delete에 firestore 적용

(4) delete에 firestore 적용
순서는 항상 똑같을 거예요!
파이어베이스랑 통신 → 필요하다면 리듀서 고치고 → 불러다 쓰기


import { db } from "./firebase";
import { collection, doc, deleteDoc } from "firebase/firestore";
...
React.useEffect(async() => {
    const docRef = doc(db, "bucket", "[도큐먼트 아이디]");
    await deleteDoc(docRef);

  }, []);

파이어베이스랑 통신하는 함수 만들고,

// 파이어베이스랑 통신하는 부분
export const deleteBucketFB = (bucket_id) => {
  return async function (dispatch, getState) {
    if(!bucket_id){
      window.alert("아이디가 없네요!");
      return;
    }
    const docRef = doc(db, "bucket", bucket_id);
    await deleteDoc(docRef);

     const _bucket_list = getState().bucket.list;
     const bucket_index = _bucket_list.findIndex((b) => {
       return b.id === bucket_id;
     });

     dispatch(deleteBucket(bucket_index));
  }
}

그 후에는요? 불러다 쓰면 되겠죠!

// Detail.js
...
<button
        onClick={() => {
          dispatch(deleteBucketFB(bucket_list[bucket_index].id));
          history.goBack();
        }}
      >
        삭제하기
      </button>
...

고난이였다...... 진짜 리얼... 리덕스 때 느낀 고통 정돈 아니지만 꽤나 힘들었다.
이것도 과제에 적용하면서 해야겠다.
피곤하다 자자

profile
i'm groot

0개의 댓글