Hello Guys and @prescottprue I have been facing a major issue with setting up my React Redux Firebase & Redux Firestore on a base project. The issue is when i use firestoreConnect
The errors that i get are : TypeError: this.props.firestore.setListeners & this.props.firestore.unsetListeners is not a function
I have read through all the docs as well read through the examples of the repo at the next branch but couldn't solve it.
i would be very grateful if someone could help me here.
I have all my react-redux libraries to the latest version , my package.json :
"dependencies": {
"firebase": "^6.0.1",
"react": "^16.8.6",
"react-dom": "^16.8.6",
"react-redux": "^7.1.0-alpha.4",
"react-redux-firebase": "^3.0.0-alpha.11",
"react-scripts": "3.0.0",
"redux": "^4.0.1",
"redux-firestore": "^0.7.3"
},
My index.js
file with setup :
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import Todos from "./Todos";
import * as serviceWorker from "./serviceWorker";
import { Provider } from "react-redux";
import firebase from "firebase/app";
import "firebase/auth";
import "firebase/firestore"; // <- needed if using firestore
import { createStore, combineReducers, compose } from "redux";
import ReactReduxFirebaseProvider from "react-redux-firebase/lib/ReactReduxFirebaseProvider";
import firebaseReducer from "react-redux-firebase/lib/reducer";
import { createFirestoreInstance, firestoreReducer } from "redux-firestore"; // <- needed if using firestore
const fbConfig = { // XXXXXXX to hide actual config
apiKey: "XXXXXXXX_R_E-faSBKZ0FmS4o",
authDomain: "XXXXXXXX-8261c.firebaseapp.com",
databaseURL: "https://XXXXXXXX-8261c.firebaseio.com",
projectId: "XXXXXXXXXX-8261c",
storageBucket: "XXXXXXX-8261c.appspot.com",
messagingSenderId: "XXXXXXXXXXXXX",
appId: "1:XXXXXXXXXXX:web:XXXXXXXXXXX"
};
// react-redux-firebase config
const rrfConfig = {
userProfile: "users",
useFirestoreForProfile: true // Firestore for Profile instead of Realtime DB
};
// Initialize firebase instance
firebase.initializeApp(fbConfig);
// Initialize other services on firebase instance
firebase.firestore(); // <- needed if using firestore
// firebase.functions() // <- needed if using httpsCallable
// Add firebase to reducers
const rootReducer = combineReducers({
firebase: firebaseReducer,
firestore: firestoreReducer // <- needed if using firestore
});
// Create store with reducers and initial state
const initialState = {};
const store = createStore(rootReducer, initialState);
const rrfProps = {
firebase,
config: rrfConfig,
dispatch: store.dispatch,
createFirestoreInstance // <- needed if using firestore
};
// Setup react-redux so that connect HOC can be used
function Index() {
return (
<Provider store={store}>
<ReactReduxFirebaseProvider {...rrfProps}>
<Todos />
</ReactReduxFirebaseProvider>
</Provider>
);
}
ReactDOM.render(<Index />, document.getElementById("root"));
The Todos.js
file where i am using firestoreConnect :
import React, { Component } from "react";
import PropTypes from "prop-types";
import { compose } from "redux";
import { connect } from "react-redux";
import { firestoreConnect } from "react-redux-firebase";
/* function Todos(props) {
return (
<div>
<p>This is a todo page</p>
{console.log(props)}
</div>
);
} */
class Todos extends Component {
render() {
return (
<div>
<p>This is a todo page</p>
{console.log(this.props)}
</div>
);
}
}
const enhance = compose(
firestoreConnect({ collection: "todos" }), // or () => ["users"]
connect((state, props) => {
console.log(state.firestore.ordered);
return { todos: state.firestore.ordered.todos };
})
);
export default enhance(Todos);
I have tried functional component also, i get the same error.
The following are the logs i get:
Few warnings :
1. Warning: Failed prop type: The prop `dispatch` is marked as required in `FirestoreConnectWrapped(Connect(Todos))`, but its value is `undefined`.
2. Warning: Failed prop type: Invalid prop `firebase` of type `string` supplied to `FirestoreConnectWrapped(Connect(Todos))`, expected `object`.
3. Warning: Failed prop type: Invalid prop `firestore` of type `string` supplied to `FirestoreConnectWrapped(Connect(Todos))`, expected `object`.
The debugs i had added :
4. {}
__proto__:
constructor: ƒ Object()
hasOwnProperty: ƒ hasOwnProperty()
isPrototypeOf: ƒ isPrototypeOf()
propertyIsEnumerable: ƒ propertyIsEnumerable()
toLocaleString: ƒ toLocaleString()
toString: ƒ toString()
valueOf: ƒ valueOf()
__defineGetter__: ƒ __defineGetter__()
__defineSetter__: ƒ __defineSetter__()
__lookupGetter__: ƒ __lookupGetter__()
__lookupSetter__: ƒ __lookupSetter__()
get __proto__: ƒ __proto__()
set __proto__: ƒ __proto__()
5. {firestore: "ReduxFirestore", firebase: "ReactReduxFirebase", dispatch: ƒ, todos: undefined}
dispatch: ƒ dispatch(action)
firebase: "ReactReduxFirebase"
firestore: "ReduxFirestore"
todos: undefined
__proto__: Object
The errors because of which the code breaks :
6. Uncaught TypeError: this.props.firestore.setListeners is not a function
at FirestoreConnectWrapped.componentDidMount (firestoreConnect.js:133)
7. Uncaught TypeError: this.props.firestore.unsetListeners is not a function
at FirestoreConnectWrapped.componentWillUnmount (firestoreConnect.js:139)
Some extra erros, i am assuming these indicate the location of the above errors :
8. index.js:1437 The above error occurred in the <FirestoreConnectWrapped(Connect(Todos))> component:
in FirestoreConnectWrapped(Connect(Todos)) (created by Context.Consumer)
9. Uncaught TypeError: this.props.firestore.setListeners is not a function
at FirestoreConnectWrapped.componentDidMount (firestoreConnect.js:133)
I have read through all the docs i could but i couldn't get to make a working solution, also because all the examples are updated according to the newer version.
Any help would be really appreciated
Also a major thing @prescottprue was getting Firestore to work with the latest version of react-redux-firebase as now we don't have getFirebase & getFirestore
I read along your issue no 635 on that thread and i was able to build a final working solution with latest version of react-redux, redux, react-redux-firebase, redux-firestore and redux-devtools-extension as well. I will be sharing my codepen soon here for others who want to get a working setup atleast as i the docs aren't cleaned up yet; i noticed you are working on them, but i'm sure i will be able to save alot of people's time with that codepen setup because it took me a whole day to get them working.
Hello Guys, i would like to share a working solution for getting redux, react-redux, react-redux-firebase, redux-firestore, redux-thunk and redux-devtools-extension completely working back up.
The below code uses the latest version of all the libraries so please look at the version of dependencies on the left first and to get it working in your project.
Please take a look at this code-pen : https://codesandbox.io/s/8423o1m529
Here i have created separate actions file which has (actions / actionCreator as some say) and call firestore functions from there, which is one of the most common use case from what i have seen.
I have organized everything as i have done in my original project just not added files to folders.
Also it would be great if you could just have a glimpse through it @prescottprue.
The reason for me not posting everything here is that it would take too much space and this will not be a great place to do it.
Can someone help me just get a particular document from firestore.
@illuminist I'm using the useFirestoreConnect
hook too :
const gId = "6IY8IFS9";
const Game = props => {
const firestore = useFirestore();
useFirestoreConnect("games/${gId}");
const game = useSelector(state => state.firestore.data.games[gId]);
if (game) console.log("Output: game", game);
I get an error :
Uncaught TypeError: Cannot read property '6IY8IFS9' of undefined
at Function.mapToProps (Game.js:77)
Instead of useSelector i also tried connect
as in your example here, prescottprue/react-redux-firebase#684
export default connect(state => ({ game: state.firestore.data.games[gId] }))(
Game
);
still same error!
if i just do
userFirestoreConnect("games");
const games = useSelector(state => state.firestore.data.games);
if (games) console.log("Output: games", games);
it works perfectly
@samsoul16 First,
useFirestoreConnect(`games/${gId}`)
it needed to be grave accemt in order to use ${...}
which is javascript string templete feature.
So that it you use single quote or double quote like "games/${gId}"
it will be just games/${gId}
. In the other hand, using grave accent js will interprets it to games/6IY8IFS9
Second, because of state.firestore.data.games
initially will be undefined before a data arrive, hence TypeError
is thrown. You need to make sure that your code can handle the empty data before loading too. My usual to go code is const game = useSelector(state => _.get(state, ['firestore', 'data', 'games', gId]))
, utilizing lodash's get
will just return undefined even if some of the deeper property cannot be accessed. This doesn't only apply to the new hook API but you should have already done the same when implement with HOC.
Thanks @illuminist for the hint to using `
instead of "
Also thanks for the solution, now i will use this :const game = useSelector(state => _.get(state, ['firestore', 'data', 'games', gId]))
But i think it should have been mentioned somewhere in docs to use _.get
instead of directly accessing as it can lead to questions for alot of people.
export default connect((state, {todoId}) => ({ todoData: state.firebase.data.todos[todoId] }))(Component)
My first thought is because of it being a separated library so I decided to not put it there. But I forgot to mention about the data is initially empty. So I think I will change it the example to match the usage of original firestoreConnect
useSelector(({firestore: { data }}) => data.games && data.games[gId] ))
This code is taken from an original example before I implement hooks.
Hi! I appreciate all the work y'all do, the project looks great though I think I'm missing something. Could someone help me understand the right way to build queries (in v3)? I'm not quite sure of the right way to do things after reading the docs/examples.
In firestore, I have collections for users
, companies
, and work_orders
, where users
and work_orders
reference companies
for ownership. (I'm not tied to any structure if this is the wrong way to do things)
My goal here is to grab the user's company and that companies work orders
In my container I have:
export default compose(
withFirebase,
connect(({ firebase, firestore }) => ({
firebase: firebase,
firestore: firestore,
companies: firestore.ordered.companies,
work_orders: firestore.ordered.work_orders
})),
firestoreConnect((props) => {
return [
{
collection: "companies",
// Part where I'm thinking I'm mixed up
doc: firebase.profile.company
},
{
collection: "work_orders",
where: [
"company",
"==",
// ? something like profile.company
]
}
];
}),
)(WorkOrderList);
state.firebase
or state.firestore
in connect by themselves. This will cause unnecessary re-render whenever their internal states are updated. The best practice for connect
is to return only the deepest state value you need for the next component. Eg. if you need to use firebase.profile.company
, returning state.firebase.profile
in connect is more sufficient than returning a whole state.firebase
.firestoreConnect
, if you do the first part as I said, you need to access doc id from props.profile.company
.firebase.profile
which you need to wait for it to have its value first, then you can return both the queries.