[react | redux] redux와 firebase 연결하기 - redux thunk

Urther·2022년 3월 10일
2

React , Redux

목록 보기
1/4

프로젝트 간단 설명

배민문방구 클론 리액트 프로젝트입니다.


firestore Database 를 이용하였고, Items의 객체는 위와 같은 모양입니다.

firebase database와 redux

문제점 발생 🥸

firebase에서 데이터를 가져오려면

import { getFirestore, query, collection, getDocs } from "firebase/firestore";
import { dbService } from "../firebase";

const q = query(collection(dbService, "items")); // collection 이름이 담겨있음
const querySnapshot = await getDocs(q);
querySnapshot.forEach((doc) => doc.data());

이런식으로 가져와야 합니다. 그런데 이걸 상태에 어떻게 저장할 수 있을까에 대한 고민을 많이 했습니다.

useState를 이용한 비동기 처리

만약, useState라는 훅을 이용하면

let [items, setItems] = useState([]);

const fetchItem = ( ) => {
  // 서버에서 items 배열을 가져오는 작업
  const q = query(collection(dbService, "items")); 
  const querySnapshot = await getDocs(q);
  querySnapshot.forEach((doc) => setItems([doc.data(), ...items]));
}

useEffect(()=>{
  fetchItem();
},[])

이런 식으로, 상품을 볼 수 있는 페이지의 component 가 mount 되기 전 Item 을 가져오면 됩니다.

여기서도 고민인게, 서버와 통신하는 코드가 컴포넌트 안에 있는 것이 맞는가에 대한 문제입니다. 이건 따로 fetchItem() 을 다른 파일로 빼고 import() 하여 사용해주면 될 것 같습니다 .. !

근데 나는 redux 로 상태 관리중이다..!

비동기 처리도 너무 까다롭고 내가 원하는대로 dispatch 가 되지 않는다 ...


그 때 발견한 것이 redux-thunk 였다.

redux-thunk

  1. 하나의 action에서 여러 개의 다른 action을 호출할 수 있다.
  2. action이 dispatch되는 걸 조작할 수 있어, 비동기 처리에도 사용한다.

굳이 , firebase가 아니더라도 json 형식으로 데이터를 axios 로 받아온다거나.. 그런 비동기처리가 필요할 때 유용하게 사용할 것 같다.

redux-saga 도 존재하지만, 난 then과 catch 처리가 그렇게 불편하다고 생각되지 않고 리덕스 청크만으로도 충분할 것 같다고 판단했다.

redux-thunk install

npm install redux-thunk

redux-thunk-firebase install

npm intall react-redux-firebase

firebase setting

(firebase를 쓰지 않는다면.. 가벼이 pass해도 되는 작업이다.)

firebase.js 파일

import { initializeApp } from "firebase/app";
import { getFirestore } from "firebase/firestore";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: process.env.REACT_APP_API_KEY,
  authDomain: process.env.REACT_APP_AUTH_DOMAIN,
  projectId: process.env.REACT_APP_PROJECT_ID,
  storageBucket: process.env.REACT_APP_STORAGE_BUCKET,
  messagingSenderId: process.env.REACT_APP_MESSAGING_ID,
  appId: process.env.REACT_APP_API_ID,
};

const app = initializeApp(firebaseConfig);
const authService = getAuth();
const dbService = getFirestore();

export { app, authService, dbService };

auth 서비스를 이용하지 않을 것이라면,

import { getAuth } from "firebase/auth";

const authService = getAuth();

를 없애도 된다.

보안 상의 이유로 firebaseConfig 는 .env 파일에 따로 저장해뒀습니다. :)
자신 프로젝트의 firebaseConfig 는 안다는 전제하에 넘기겠습니다 ..... !

redux-thunk setting

itemsAction.js

import { getFirestore, query, collection, getDocs } from "firebase/firestore";
//import { dbService } from "../firebase";

const FILTER_ITEMS = "FILTER_ITEMS";

const categoryFilterItemsData = (category) => async (dispatch) => {
  try {
    //const q = query(collection(dbService, "items"));
    //const querySnapshot = await getDocs(q);
    //let Item = [];
    //querySnapshot.forEach((doc) => {
    //});
    //console.log(Item);
    // <---------- axios로 받던 아무튼 비동기 처리 ------> 
    dispatch({ type: FILTER_ITEMS, payload: Item });
  } catch (e) {
    console.log(e);
  }
};

export default categoryFilterItemsData;

dispatch({type:액션이름 , payload: 비동기처리로 받아온 데이터})
해주면 된다. 만약, 액션이 두개라면 ? 화살표 함수를 두 개 만들면 끝 !

ItemReducer.js

const initialState = [];

const ItemsReducer = (state = initialState, action) => {
  switch (action.type) {
    case "FILTER_ITEMS":
      const items = action.payload;
      console.log(items);
      return items;

    default:
      return state;
  }
};

export default ItemsReducer;

Items의 action 을 처리해줄 Reducer 파일을 생성해준다.
액션은 case 별로 구별해주고, default(기본 상태)는 state를 리턴해준다.

action.type 을 이용하여 action 의 타입을 구별해줍니다.

rootReducer.js

import { combineReducers } from "redux";
import ItemsReducer from "./ItemReducer";

const rootReducer = combineReducers({ ItemsReducer });

export default rootReducer;

store 에 저장될 rootReducer를 만들어준다.
Reducer는 2개 이상일 확률이 있으니 combineReducer로 묶어줬다.

만약, 한개라면 그냥

const rootReducer = ItemsReducer;

로 한 개만 보내줘도 무방하다

store.js

import { createStore, applyMiddleware } from "redux";
import rootReducer from "./rootReducer";
import thunk from "redux-thunk";
import { getFirebase } from "react-redux-firebase";

const middlewares = [thunk.withExtraArgument(getFirebase)];
const store = createStore(rootReducer, applyMiddleware(...middlewares));

export default store;

마지막으로 store를 묶어준다.

만약 firebase를 이용하지 않는다면

const middlewares = [thunk];
const store = createStore(rootReducer, applyMiddleware(middlewares));

를 사용하면 됩니다.

사용하기

    dispatch(categoryFilterItemsData(param.id));

이런식으로 사용해주면 됩니당!
dispatch({type: 모시기}) 를 해주던 건 categoryFilterItemData에서 해주니까 그런거겠쥬?


리덕스와 파이어베이스 연결하는 방법은 한국어로 된 포스팅이 많이 없어서
혼자서 영어 유투브들을 보며 엉ㅇ엉엉 울면서 찾은 방법입니다.
서버 통신하는 것이 상태관리와 구분되지 않아서 100 % 마음에 드는 방법은 아니긴 합니다

더 나은 방법이 있다면 알려주시면 감사하겠습니다..... 🙊

profile
이전해요 ☘️ https://mei-zy.tistory.com

0개의 댓글