[ Goplan ] - Redux & Firbase 연동 (Error 해결)

승진·2019년 10월 16일
0

GoPlan

목록 보기
3/5

Redux 연동

redux에 관련된 파일들을 작성할 store 폴더에

  • reducers
  • actions

두 가지 하위 폴더를 만들어 준다.

Reducers

reducers 폴더에는 아래와 같은 파일을 생성한다.

  • projectReducer.js // 프로젝트를 생성하는 리듀서
  • authReducer.js // 로그인 인증 리듀서
  • rootReducer.js // 모든 리듀서를 연결하는 리듀서

store / reducers / projectReducer.js

const initState = {
  projects: [
    { id: '1', title: 'learn redux', content: 'blah blah blah' },
    { id: '2', title: 'exercise', content: 'blah blah blah blah' },
    { id: '3', title: 'new project', content: 'blah blah blah' },
  ],
};

const projectReducer = (state = initState, action) => {
  return state;
};

export default projectReducer;

모든 리듀서들을 하나로 합쳐준다.

store / reducers / rootReducer.js

import authReducer from './authReducer';
import projectReducer from './projectReducer';
import { combineReducers } from 'redux';

const rootReducer = combineReducers({
  auth: authReducer,
  project: projectReducer,
});

export default rootReducer;

rootReducer를 앱에 연동시킨다.

src / index.js

import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import * as serviceWorker from './serviceWorker';

// Redux
import { createStore } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './components/store/reducers/rootReducer';

const store = createStore(rootReducer);

ReactDOM.render(
  <Provider store={store}>
    <App />
  </Provider>,
  document.getElementById('root'),
);
serviceWorker.unregister();

action

store 디렉토리에 action 폴더를 생성해서 액션파일을 만들어준다.

가장 먼저 새로운 프로젝트를 생성하는 액션을 작성해준다.
사용자가 프로젝트 타이틀과 컨텐츠를 입력하면 firebase 데이터베이스에 저장할 수 있도록하는 함수를 만들어준다.

export const createProject = project => {
  return (dispatch, getState, { getFirebase, getFirestore }) => {
    // async call to database
    const firestore = getFirestore();
    firestore
      .collection('project')
      .add({
        ...project,
        authorFirstName: 'Dan',
        authorLastName: 'Jooo',
        authorId: 12345,
        createdAt: new Date(),
      })
      .then(() => {
        // callback 위 작업이 실행되면 어떤 작업을 할 것인지
        dispatch({ type: 'CREATE_PROJECT', project });
      })
      .catch(err => {
        dispatch({ type: 'CREATE_PROJECT', err });
      });
  };
};

State와 컴포넌트 연동

connect() 메서드를 사용해서 redux state를 연결해준다.

Dashboard.jsx

import React, { Component } from 'react';
import Notifications from './Notification';
import ProjectList from '../projects/ProjectList';
import { connect } from 'react-redux';

class Dashboard extends Component {
  render() {
    const { projects } = this.props;

    return (
      <div className="dashboard container">
        <div className="row">
          <div className="col s12 m6">
            <ProjectList projects={projects} />
          </div>
          <div className="col s12 m5 offset-m1"></div>
          <Notifications />
        </div>
      </div>
    );
  }
}

const mapStateToProps = state => {
  return {
    projects: state.project.projects,
  };
};

export default connect(mapStateToProps)(Dashboard);

Firebase

프로젝트에 Firebase를 설치해준다.
npm install firebase

웹에 Firebase 추가를 하고
Firebase configuration

스크립트를 복사해 src /config / fbconfig.js 폴더와 파일을 만들어 붙여넣기 한다.

필요한 모듈을 불러와 준다.

import firebase from 'firebase/app';
import 'firebase/firestore';
import 'firebase/auth';

var firebaseConfig = {
	// ...복사한 스크립트
}

// Initialize Firebase
firebase.initializeApp(firebaseConfig);
firebase.analytics();
firebase.firestore().settings({ timestampsInSnapshots: true });

export default firebase;

데이터베이스를 생성하고 프로젝트에 연결하기 위해 필요한 모듈을 설치해준다.
yarn add react-redux-firebase redux-firestore

src /index.js

// Redux
import { createStore, applyMiddleware, compose } from 'redux';
import { Provider } from 'react-redux';
import rootReducer from './store/reducers/rootReducer';
import thunk from 'redux-thunk';

// Firebase
import { reduxFirestore, getFirestore } from 'redux-firestore';
import { reactReduxFirebase, getFirebase } from 'react-redux-firebase';
import fbConfig from './config/fbconfig';

const store = createStore(
  rootReducer,
  compose(
    applyMiddleware(thunk.withExtraArgument({ getFirebase, getFirestore })),
    reduxFirestore(fbconfig),
    reactReduxFirebase(fbconfig),
  ),
);

실행을 해보니 에러가 발생했다.

Error

Firebase를 처음 사용해 보기 때문에 redux를 연동하는 강좌를 참고해서 만들다 보니
옛 버전의 코드로 작성이 된것을 참고해 많은 오류가 생겼다..ㅠ
4시간정도에 걸쳐 해결한 오류들을 정리해본다.

첫 번째 Error

TypeError: Object(…) is not a function on index.js

stackoverflow에 검색을 해보니
예전 버전의 방식으로 셋팅을 해서 그렇다고 한다.

 reactReduxFirebase(firebase, config),
 reduxFirestore(firebase)

예전 버전인 두가지를 제거하고,

import { ReactReduxFirebaseProvider } from 'react-redux-firebase';
import { createFirestoreInstance } from 'redux-firestore';

지금은 이렇게 업데이트된 방식으로 바꿔줘야 한다.

import firebase from 'firebase/app';
import { ReactReduxFirebaseProvider } from 'react-redux-firebase';
import { createFirestoreInstance } from 'redux-firestore';
import fbConfig from './config/fbconfig';

const store = createStore(rootReducer, compose(applyMiddleware(thunk)));

const rrfProps = {
  firebase,
  config: fbConfig,
  dispatch: store.dispatch,
  createFirestoreInstance,
};

ReactDOM.render(
  <Provider store={store}>
    <ReactReduxFirebaseProvider {...rrfProps}>
      <App />
    </ReactReduxFirebaseProvider>
  </Provider>,
  document.getElementById('root'),
);
serviceWorker.unregister();

이제 잘 작동한다!

그런데 콘솔을 확인해 보니 다른 경고창이 확인됐다.

두 번째 Error

timestampsInSnapshots setting의 기본 설정이 true이고,
향후 릴리즈에서 이 셋팅이 완전히 제거될 것이므로 제거하는 것이 좋다는 것이였다.

fbconfig.js

firebase.firestore().settings({ timestampsInSnapshots: true });

파일에서 위 코드를 지워주면 해결된다.
이제 New Project에서 새로운 프로젝트를 입력후 데이터베이스에 저장이 되는지 확인해보자

세 번째 Error

또 에러

이번엔 액션파일에서 에러가 발생했다..
이 에러 역시 버전이 업데이트 되면서 생긴 에러이고 react-redux-firebase에서 최신 버전의 사용방법을 찾아서 여러가지 적용을 시도해본 결과

예전 방식인 { getFirebase, getFirestore } 두가지를 제거하고,
firebase를 불러와 firestore를 사용해주는 걸로 해결할 수 있었다.

import firebase from 'firebase/app'; // firebase 불러오기

export const createProject = project => {
  return (dispatch, getState) => {	//  { getFirebase, getFirestore } 제거
    // async call to database
    firebase	// 수정된 부분
      .firestore()	// 수정된 부분
      .collection('project')
      .add({
        ...project,
        authorFirstName: 'Dan',
        authorLastName: 'Jooo',
        authorId: 12345,
        createdAt: new Date(),
      })
      .then(() => {
        // callback 위 작업이 실행되면 어떤 작업을 할 것인지
        dispatch({ type: 'CREATE_PROJECT', project });
      })
      .catch(err => {
        dispatch({ type: 'CREATE_PROJECT', err });
      });
  };
};

이렇게 해서 다시 새 프로젝트를 입력하고 데이터베이스에 잘 저장하는 것을 성공했다!!

Firebase Data Component 연동

이제 State에 만들어둔 데이터가 아닌 Firebase에 저장된 데이터를 연동시켜보자

rootReducer.js

import authReducer from './authReducer';
import projectReducer from './projectReducer';
import { firebaseReducer } from 'react-redux-firebase'; // 추가
import { firestoreReducer } from 'redux-firestore';	// 추가
import { combineReducers } from 'redux';

// ..생략

const mapStateToProps = state => {
  console.log(state);
  return {
    projects: state.firestore.ordered.projects,
  };
};

export default compose(
  firestoreConnect([{ collection: 'projects' }]),
  connect(mapStateToProps),
)(Dashboard);

이렇게 firebase의 상태를 연동해주면 state가 데이터베이스에 있는 데이터로 적용된다.

마무리

Redux를 이해하기 위해 계속해서 적용하고 있는데 점점 익숙해 지는 느낌이 들어 다행이다.
프로젝트를 만들면서 항상 느끼는 점은 오류가 발생하는 것이 가장 힘들다.
그렇지만 오류를 해결하면서 가장 많이 배운다는 점이다.
때문에 어렵고 복잡해도 포기하지 해결하면 그만큼 얻는 것도 많고 뿌듯하다!

다음 포스팅 - 사용자 인증

http://docs.react-redux-firebase.com/history/v3.0.0/docs/v3-migration-guide.html
https://sebhastian.com/react-firestore

profile
Front-end 개발 공부일지

0개의 댓글