New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
getFirebase(...).firestore(...).set is not a function -- how to make firestore work inside action like v2 please help! #839
Comments
Main IssueIf In the next section I describe how there is built in logic for doing what you seem to be writing logic for: A Built In Way To Do SimilarSomething to note: the functionality that you are trying to write (i.e a profile written to {
userProfile: 'users',
useFirestoreForProfile: true // store profiles in Firestore instead of RTDB
// updateProfileOnLogin: false // add if you don't want profile updated on every login
/* Add to change how profiles are stored in database:
profileFactory: (userData, profileData, firebase) => {
const { user } = userData
return {
email: user.email
}
} */
} This is also described in the profile recipes within the docs. Then when you call If you need to call anything after (like const { email, password, displayName } = data
const createdUser = await firebase.login({ email, password }, { email, displayName })
await createdUser.user.updateProfile({ displayName }); |
hello here is my settings:
and firebase config firebase.initializeApp(firebaseConfig); export default firebase;` My question how to user firestore inside action, can you give me example? becouse firebase().firstore is not working |
I am not seeing any imports in your example, are you sure you are importing Firestore? Could you provide a full repo where this can be reproduced? Based on your settings, as I noted above, you should be able to do the following without creating a separate custom action: const { email, password, displayName } = data
const createdUser = await firebase.login({ email, password }, { email, displayName })
await createdUser.user.updateProfile({ displayName }) |
I believe I am having the same problem. I believe I have set everything up
In my components, I can successfully use hooks ( In my thunk actions, I can use Comparison:// in a component
const firestore = useFirestore()
console.log(firestore)
// output
{
blob: function PublicConstructor()
CACHE_SIZE_UNLIMITED: -1
CollectionReference: function PublicConstructor()
DocumentReference: function PublicConstructor()
DocumentSnapshot: function PublicConstructor()
FieldPath: function FieldPath$1()
FieldValue: function PublicConstructor()
Firestore: function PublicConstructor()
GeoPoint: function GeoPoint(latitude, longitude)
Query: function PublicConstructor()
QueryDocumentSnapshot: function PublicConstructor()
QuerySnapshot: function PublicConstructor()
Timestamp: function Timestamp(seconds, nanoseconds)
Transaction: function PublicConstructor()
WriteBatch: function PublicConstructor()
_: Object ... ,
add: function createWithFirebaseAndDispatch()
batch: function ()
collection: function ()
collectionGroup: function ()
configureClient: function ()
default: function createWithFirebaseAndDispatch()
delete: function createWithFirebaseAndDispatch()
deleteRef: function createWithFirebaseAndDispatch()
disableNetwork: function ()
doc: function ()
enableNetwork: function ()
enablePersistence: function ()
ensureClientConfigured: function ()
get: function createWithFirebaseAndDispatch()
onSnapshot: function createWithFirebaseAndDispatch()
runTransaction: function createWithFirebaseAndDispatch()
set: function createWithFirebaseAndDispatch()
setListener: function createWithFirebaseAndDispatch()
setListeners: function createWithFirebaseAndDispatch()
setLogLevel: function setLogLevel(level)
settings: function ()
unsetListener: function createWithFirebaseAndDispatch()
unsetListeners: function createWithFirebaseAndDispatch()
update: function createWithFirebaseAndDispatch()
} // in a thunk
const firebase = getFirebase()
const firestore = firebase.firestore()
console.log(firestore)
// output
{
INTERNAL: Object ... ,
_credentials: Object ... ,
_dataConverter: Object ... ,
_databaseId: Object ... ,
_firebaseApp: Object ... ,
_firestoreClient: Object ... ,
_persistenceKey: "[DEFAULT]"
_queue: Object ... ,
_settings: Object ... ,
} Any idea what is up? I can provide a complete repo/sandbox given the time if it helps. |
A full repro in codesandbox would be good - The usage of the new context API changes how gathering the extended firebase instance works. |
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 ( In a component:
In a thunk:
So, in short, the extended firestore api doesn't seem to be available when using |
can u please create an example how to use firestore inside actions? |
again here is my codes:
Configure Store:
root reducer:
index,js
and until now cant use getFirebase().firestore() |
Has anyone tried using |
Yes, that's where I started. I've added that option to the sandbox. Calling
|
help please, I did turn around = I used withFirestore & withFirebase as hoc then pass it aas urgmenets to action but this is alot of code here
|
@knour89 did you find any solution, because I'm also stuck with the same? |
@knour89 : Here is the solution of your exact problem. Instead of calling
|
@deepankar14693 : That surely works, but the issue here is specifically related to using firestore in a redux thunk. We don't want to call /* 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(/* ... */)
} |
TypeError: getFireStore is not a function when pass argument in action creator. firebase.js var firebaseConfig = { export default firebase; Root.jsx const rootReducers = combineReducers({ store..jsx import {createStore } from 'redux'; const store = createStore(rootReducers,compose( projectReducer.jsx const INITIAL_STATE = { const projectReducer = (state = INITIAL_STATE, action) => {
} projectAction.jsx export const createProject = (project) => {
} |
@eliasnorrby I was just trying to help @knour89 out so that he can move on with further development and not just get stuck. |
@deepankar14693 Yes, of course, it's just that from @knour89 's latest comment it seemed he was using a workaround involving Haven't found a solution yet, but I'll let you know if I do. Likewise to you – if you find one I'd be very grateful to know. 🙏 |
@eliasnorrby what about createFirestoreInstance which is imported from redux-firestore and passed as props to ReactReduxFirebaseProvider. Infact it takes firebase as parameter and in return gives a firestore instance. |
@knour89 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:
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:
Then in your action you can access to enhanced firestore instance by provoking getFirestore().
Hopefully it is related to what you actually need and solves your problem. |
Have you found a solution? I am having a similar issue but I am using the redux toolkit, all HOC functions and hooks works fine, but passing the getFirebase & getFirestore to thunk failed, it says Firebase not defined ... according to the doc, store enhancers are deprecated in V3 in favor of the React context API, looks like the API documentation is not up to date for Thunk in V3 thanks |
@agiguere Haven't been working on the related project for some months. Not really up to date on whether there has been any updates to react redux firebase to solve it, but the workaround I described in a previous comment should still work, I guess. Since (like you're saying) the hooks work, you can get hold of the |
Cool ! |
@Jsh007 I believe that is coming from |
@prescottprue Thank you. I'm still unable to access getFirestore and getFirebase in my thunk action creators. Presently, I'm creating an instance of useFirestore and UseFirbase in my Ui components and passing It along with payload to my thunk action creators and it is making my App unstable. Since I became comfortable with reduxToolkit; I have come to love it. I now find vanilla redux unnecessarily verbose and unusable. I'm using ReduxToolkit with configureStore. RRF is a great tool, but please could you see why getFirestore and getFirebase aren't passing through to thunk action creators when using configureStore? My store; store.js import { configureStore, getDefaultMiddleware } from "@reduxjs/toolkit";
import {
getFirestore,
firestoreReducer,
constants as rfConstants,
} from "redux-firestore";
import {
getFirebase,
firebaseReducer,
actionTypes as rrfActionTypes,
} from "react-redux-firebase";
import auth from "../features/auth/authSlice";
const reducer = {
auth,
firebase: firebaseReducer,
firestore: firestoreReducer,
};
const extraArgument = {
getFirebase,
getFirestore,
};
const middleware = [
...getDefaultMiddleware({
serializableCheck: {
ignoredActions: [
// just ignore these
...Object.keys(rfConstants.actionTypes).map(
(type) => `${rfConstants.actionsPrefix}/${type}`
),
...Object.keys(rrfActionTypes).map(
(type) => `@@reactReduxFirebase/${type}`
),
],
ignoredPaths: ["auth", "firebase", "firestore"],
},
thunk: {
extraArgument,
},
}),
];
const preLoadedState = {};
const Store = configureStore({
reducer,
middleware,
devTools: true,
preLoadedState,
enhancers: (defaultEnhancers) => [...defaultEnhancers],
});
export default Store; My App.js import React, { useState, useEffect } from "react";
import { NavigationContainer } from "@react-navigation/native";
import Navigation from "./features/navigation/Navigation";
import { Provider } from "react-redux";
import Store from "./store/Store";
import {
ReactReduxFirebaseProvider,
createFirebaseInstance,
} from "react-redux-firebase";
import { createFirestoreInstance } from "redux-firestore";
import firebase from "./config/fbConfig";
if (__DEV__) {
import("./ReactotronConfig");
}
import Reactotron from "reactotron-react-native";
import { YellowBox } from "react-native";
// UI kitten
import * as eva from "@eva-design/eva";
import { ApplicationProvider } from "@ui-kitten/components";
//HIDE YELLOW BOX
YellowBox.ignoreWarnings(["Setting a timer"]);
// Reactotron.log("Awake !");
// PRELOAD ASSETS
import { AppLoading } from "expo";
import { Asset } from "expo-asset";
import * as Font from "expo-font";
// ASSETS LOADER
function cacheImages(images) {
return images.map((image) => {
if (typeof image === "string") {
return Image.prefetch(image);
} else {
return Asset.fromModule(image).downloadAsync();
}
});
}
function cacheFonts(fonts) {
return fonts.map((font) => Font.loadAsync(font));
}
export default function App() {
// INIT ASSETS LOAD STATE
const [isReady, setisReady] = useState(false);
const _loadAssetsAsync = async () => {
const imageAssets = cacheImages([
require("./assets/images/Rantapp-Slogo.png"),
require("./assets/images/Rantapp-txt.png"),
require("./assets/images/josh9.jpeg"),
]);
const fontAssets = cacheFonts([
{ "OpenSans-Regular": require("./assets/font/OpenSans-Regular.ttf") },
{ "OpenSans-Bold": require("./assets/font/OpenSans-Bold.ttf") },
{ "OpenSans-Light": require("./assets/font/OpenSans-Light.ttf") },
]);
await Promise.all([...imageAssets, ...fontAssets]);
};
if (!isReady) {
return (
<AppLoading
startAsync={_loadAssetsAsync}
onFinish={() => setisReady(true)}
onError={console.warn}
/>
);
}
// react-redux-firebase config
const rrfConfig = {
userProfile: "users",
enableClaims: true,
useFirestoreForProfile: true,
};
// React-redux-firebase props
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: Store.dispatch,
createFirestoreInstance,
};
return (
<Provider store={Store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<NavigationContainer>
<ApplicationProvider {...eva} theme={eva.light}>
<Navigation />
</ApplicationProvider>
</NavigationContainer>
</ReactReduxFirebaseProvider>
</Provider>
);
} my RTK slice (authSlice.js) import { createSlice, createAsyncThunk } from "@reduxjs/toolkit";
const authSlice = createSlice({
name: "auth",
initialState: {
loading: "idle",
authError: null,
},
reducers: {
processStarted: (state, action) => {
if (state.loading === "idle") {
state.loading = "pending";
}
state.authError = null;
},
processCompleted: (state, action) => {
if (state.loading === "pending") {
state.loading = "idle";
}
state.authError = null;
},
processFailed: (state, action) => {
if (state.loading === "pending") {
// Receive error msg from action.payload and put on a state property called errorMessage
state.loading = "idle";
}
state.authError = "Error: " + action.payload;
},
},
extraReducers: {},
});
export const signIn = (credentials, { firebase, firestore }) => async (
dispatch,
getState,
getFirebase,
getFirestore
) => {
const firebaseRRF = getFirebase(); // NOT WORKING
try {
dispatch(processStarted());
await firebase.login(credentials); // RRF'S Ehanced function
// await firebase
// .auth()
// .signInWithEmailAndPassword(credentials.email, credentials.password);
// await firebase.authWithPassword(credentials);
dispatch(processCompleted());
} catch (error) {
const errorMsg = error.message;
const [methodError, shortMsg] = errorMsg.split(":");
dispatch(processFailed(shortMsg));
}
};
export const signUp = (credentials, profile, { firebase, firestore }) => async (
dispatch,
getState,
getFirebase,
getFirestore
) => {
const firebaseRRF = getFirebase(); // NOT WORKING
try {
dispatch(processStarted());
// await firebase
// .auth()
// .createUserWithEmailAndPassword(credentials.email, credentials.password);
// dispatch(processCompleted());
await firebase.createUser(credentials, profile);
dispatch(processCompleted());
} catch (error) {
const errorMsg = error.message;
const errorMsgShort = errorMsg.split(":");
dispatch(processFailed(errorMsgShort));
}
};
//TODO: Unable to access getFirebase and thus cannot connect to firebase. FIX IT !
export const {
processFailed,
processCompleted,
processStarted,
} = authSlice.actions;
export default authSlice.reducer; My Ui component; SignIn.js // FB instances
const firebase = useFirebase(); // - Currently doing this
const firestore = useFirestore(); // - Currently doing this
const fbref = {
firebase,
firestore,
};
// Submit handler
function handleSubmit(cred, fb) {
setTimeout(() => {
dispatch(login(cred, fb));
}, 500);
}
// I pass the firebase and firestore instances along with form data to the thunk action creator; login(). I don't want to keep doing this, I want to access getFirebase and getFirestore directly from the props on login() in my authSlice.js file ( where login is defined)
<Button
title="Login"
onPress={() => handleSubmit({ email, password }, fbref)}
backgroundColor={"#303030"}
width={dWidth("60%")}
height={"60px"}
borderRadius={"60px"}
textColor={"#fff"}
fontWeight={"bold"}
fontSize={"18px"}
textCase={"uppercase"}
customStyle={btnShadow}
buttonPaddingTop={"16px"}
buttonPaddingBottom={"16px"}
buttonMarginTop={"50px"}
buttonMarginBottom={"100px"}
/> |
@Jsh007 Try |
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
here my configure store
The text was updated successfully, but these errors were encountered: