I'm trying to figure out how to query a record in firestore using an authUser uid as the document id.
I have seen this post and am trying to implement the logic by updating the state of the user so that the componentDidMount function can find a document in the users collection in firestore, where that document has an id which is the same as the authUser.uid in the Authentication collection.
I have an authListener with:
import React from 'react';
import { AuthUserContext } from '../Session/Index';
import { withFirebase } from '../Firebase/Index';
const withAuthentication = Component => {
class WithAuthentication extends React.Component {
constructor(props) {
super(props);
this.state = {
authUser: null,
};
}
componentDidMount() {
this.listener = this.props.firebase.auth.onAuthStateChanged(
authUser => {
authUser
? this.setState({ authUser })
: this.setState({ authUser: null });
},
);
}
// componentDidMount() {
// this.listener = this.props.firebase.onAuthUserListener(
// /* next() */ (authUserWithData) => this.setState({authUser: authUserWithData}),
// /* fallback() */ () => this.setState({authUser: null})
// );
// }
componentWillUnmount() {
this.listener();
};
render() {
return (
<AuthUserContext.Provider value={this.state.authUser}>
<Component {...this.props} />
</AuthUserContext.Provider>
);
}
}
return withFirebase(WithAuthentication);
};
export default withAuthentication;
My firebase config file defines a helper with:
onAuthUserListener(next, fallback) {
// onUserDataListener(next, fallback) {
return this.auth.onAuthStateChanged(authUser => {
if (!authUser) {
// user not logged in, call fallback handler
fallback();
return;
}
this.user(authUser.uid).get()
.then(snapshot => {
let snapshotData = snapshot.data();
let userData = {
...snapshotData, // snapshotData first so it doesn't override information from authUser object
uid: authUser.uid,
email: authUser.email,
emailVerified: authUser.emailVerifed,
providerData: authUser.providerData
};
setTimeout(() => next(userData), 0); // escapes this Promise's error handler
})
.catch(err => {
// TODO: Handle error?
console.error('An error occured -> ', err.code ? err.code + ': ' + err.message : (err.message || err));
setTimeout(fallback, 0); // escapes this Promise's error handler
});
});
}
Then, in the component where I'm trying to use the logged in user's attributes from the related user collection in cloud firestore, I have a component with:
import React from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
useRouteMatch,
} from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification, withAuthentication } from '../Session/Index';
const { Title, Text, Paragraph } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;
class Dashboard extends React.Component {
// state = {
// collapsed: false,
// loading: false,
// };
constructor(props) {
super(props);
this.state = {
collapsed: false,
loading: false,
user: null,
...props.location.state,
};
}
componentDidMount() {
if (this.state.user) {
return;
}
this.setState({ loading: true });
// this.unsubscribe =
// this.props.firebase
// .user(this.props.match.params.id)
// .onSnapshot(snapshot => {
// this.setState({
// user: snapshot.data(),
// loading: false,
// });
// });
// }
// firebase.firestore().collection("users")
// .doc(this.state.uid)
// .get()
// .then(doc => {
// this.setState({ post_user_name: doc.data().name });
// });
// }
// - this is the current attempt -
this.unsubscribe =
this.props.firebase.db
.collection('users')
.doc(this.props.authUser.uid)
.get()
.then(doc => {
this.setState({ name: doc.data().name });
// loading: false,
}
// else {
// // doc.data() will be undefined in this case
// console.log("Can't find this record");
// }
);
}
componentWillUnmount() {
this.unsubscribe && this.unsubscribe();
}
onCollapse = collapsed => {
console.log(collapsed);
this.setState({ collapsed });
};
render() {
// const { loading } = this.state;
// const { user, loading } = this.state;
// let match = useRouteMatch();
// const dbUser = this.props.firebase.app.snapshot.data();
// const user = Firebase.auth().currentUser;
return (
<div>
<Header>
<Text style={{ float: 'right', color: "#fff"}}>{this.state.authUser.uid}
{/*
{this.props.firebase.db.collection('users').doc(authUser.uid).get()
.then(doc => {
console.log(doc.data().name)
})
}
{
this.props.firebase.db.collection('users').doc(this.props.authUser.uid).get()
.then(doc => {
console.log("test", doc.data().name
)
})
}
{console.log(this.props.user.email)}
*/}
</div>
);
}
}
When I try to use the authUser.uid in the componentDidMount query, I get an error that says:
FirebaseError: Function CollectionReference.doc() requires its first argument to be of type non-empty string, but it was: a custom DocumentReference object
The route for this component is wrapped in the authUser Context.Consumer:
<Route path={ROUTES.DASHBOARD} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
I can console.log the attributes stored in the user collection with the doc id which is the authUser uid in the Authentication collection - but I can't find a way to put that authUser uid into a firebase query on the users collection in the componentDidMount function.
I have seen this post which suggests that a doc() value can be something other than a string, but that it might be a timing problem in that firebase may not have identified the authUser by the point at which the query runs. If that's true, where can I put an await tag on the query to fix this problem?
I have also seen this post which suggests that I need to build a work around to convert the authUser.uid to a string before I give it to the firestore query. Several of those responses express interest in knowing if the doc id can be something other than a string.