react-redux-firebase: getFirebase(...).firestore(...).set is not a function -- how to make firestore work inside action like v2 please help!

as we know from V3 no more getFirestore() it should be replaced with getFirebase().firestore() - but it’s not working and give me below message getFirebase(...).firestore(...).set is not a function

here is my action

export const registerUser = data => async (dispatch, getState, getFirebase) => {
  const firebase = getFirebase();
  const firestore = getFirebase().firestore();
  try {
    let createdUser = await firebase
      .auth()
      .createUserWithEmailAndPassword(data.email, data.password);

    await createdUser.user.updateProfile({
      displayName: data.displayName
    });

    await firestore.set(`users/${createdUser.user.uid}`, {
      displayName: data.displayName,
      createdAt: firestore.FieldValue.serverTimestamp()
    });
}catch(error){}

here my configure store

import { createStore, applyMiddleware } from "redux";
import { composeWithDevTools } from "redux-devtools-extension";
import { getFirebase } from "react-redux-firebase";

import thunk from "redux-thunk";
import rootReducer from "../reducers/rootReducer";

export const configureStore = () => {
  const middlewares = [thunk.withExtraArgument(getFirebase)];

  const composeEnhancers = composeWithDevTools(applyMiddleware(...middlewares));

  const store = createStore(rootReducer, composeEnhancers);
  return store;
};

About this issue

  • Original URL
  • State: open
  • Created 4 years ago
  • Reactions: 1
  • Comments: 25 (5 by maintainers)

Most upvoted comments

@knour89 Hi,

I find that when firestore instance created by firebase.firestore() we don’t have access to “set”, because it is not a native firestore method, you can change your code like this:

const firestore = firebase.firestore();
await firestore.collection("users").doc(createdUser.user.uid).set({yourProperties})

In addition of “set” there are other methods such as “get, add, update, delete ,…” which they are available through getFirestore(). For more information you can check reduxFirestore enhancer

If you still need those enhanced capabilities you can set thunk to pass down getFirestore like this:

import { createStore, compose, applyMiddleware } from "redux";
import thunk from "redux-thunk";
import { getFirestore, reduxFirestore } from "redux-firestore";
import { getFirebase } from "react-redux-firebase";
import firebase from "../config/fb-config";
import { createFirestoreInstance } from "redux-firestore";

import rootReducer from "./reducers/root-reducer";

const rrfConfig = {
  userProfile: "users",
  useFirestoreForProfile: true,
  enableClaims: true
};

const initialState = {};
const middlewares = [thunk.withExtraArgument({ getFirebase, getFirestore })]; 
const store = createStore(
  rootReducer,
  initialState,
  compose(applyMiddleware(...middlewares), reduxFirestore(firebase, rrfConfig))
);

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

export default store;

Then in your action you can access to enhanced firestore instance by provoking getFirestore().

export const createDoc = newDoc => {
  return async (dispatch, getState, { getFirebase, getFirestore }) => {
  const firestoreEnhanced = getFirestore(); // with additional methods like set, get,..
  const firestoreOrginal = getFirebase.firestore(); // not enhanced, set method is not available
 
}

Hopefully it is related to what you actually need and solves your problem.

Okay, here’s an example: https://codesandbox.io/s/rrf-bug-repro-839-nret4

It started pretty minimal but grew when I wanted to test different cases, I hope there’s not too much fluff. The demo just fetches a document from firestore in different contexts (component vs thunk), using different apis (base vs extended) and different ways of acquiring the firestore instance (firebase.firestore() vs useFirestore()). Here’s a summary:

In a component:

  • useFirebase().firestore().get(..) : broken
  • useFirebase().firestore().collection(..).doc(..).get() : works
  • useFirestore().get(..) : works
  • useFirestore().collection(..).doc(..).get() : works

In a thunk:

  • getFirebase().firestore().get(..) : broken
  • getFirebase().firestore().collection(..).doc(..).get() : works

So, in short, the extended firestore api doesn’t seem to be available when using firebase.firestore().

@deepankar14693 : That surely works, but the issue here is specifically related to using firestore in a redux thunk. We don’t want to call firestore.set within a onClick or onFormSubmit handler, but within a thunk, i.e.

/* component.js */
onFormSubmit = (values) => dispatch(registerUser(values))

/* some-thunk.js */
registerUser = (values) => async (dispatch, getState, { getFirebase }) => {
  const firestore = getFirebase().firestore()
  firestore.set(/* ... */)
}

The workaround for now seems to be to get hold of the firestore instance within the component (using either the hooks or the HOC API) and pass it along in the action creator.

/* component.js */
const  firestore = useFirestore()
/* ... */
onFormSubmit = (values) => dispatch(registerUser(values, firestore))

/* some-thunk.js */
registerUser = (values, firestore) => async (dispatch, getState) => {
  firestore.set(/* ... */)
}

@knour89 did you find any solution, because I’m also stuck with the same?