Я пытаюсь выяснить, как получить имя пользователя, которое является атрибутом, хранящимся в коллекции пользователей, которая была объединена с атрибутами, созданными моделью аутентификации firebase.
Я могу получить доступ к authUser - который дает мне ограниченные поля, которые firebase собирает в инструменте аутентификации, и затем я пытаюсь перейти оттуда к связанной коллекции пользователей (которая использует тот же uid).
У меня есть потребитель реагирующего контекста с:
import React from 'react';
const AuthUserContext = React.createContext(null);
export default AuthUserContext;
Затем в моем компоненте я пытаюсь использовать:
const Test = () => (
<AuthUserContext.Consumer>
{authUser => (
<div>
{authUser.email} // I can access the attributes in the authentication collection
{authUser.uid.user.name} //i cannot find a way to get the details in the related user collection document - where the uid on the collection is the same as the uid on the authentication table
</div>
)}
</AuthUserContext.Consumer>
);
const condition = authUser => !!authUser;
export default compose(
withEmailVerification,
withAuthorization(condition),
)(Test);
В моей базе данных. js - Я думаю, Я попытался объединить атрибуты authUser из модели Authentication с атрибутами пользовательской коллекции следующим образом:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
/* helpers */
this.fieldValue = app.firestore.FieldValue;
/* Firebase APIs */
this.auth = app.auth();
this.db = app.firestore();
onAuthUserListener = (next, fallback) =>
this.auth.onAuthStateChanged(authUser => {
if (authUser) {
this.user(authUser.uid)
.get()
.then(snapshot => {
const dbUser = snapshot.data();
// default empty roles
if (!dbUser.roles) {
dbUser.roles = {};
}
// merge auth and db user
authUser = {
uid: authUser.uid,
email: authUser.email,
emailVerified: authUser.emailVerified,
providerData: authUser.providerData,
...dbUser,
};
next(authUser);
});
} else {
fallback();
}
});
Я не могу найти способ получить от authUser (который работает, чтобы получить меня к Атрибуты аутентификации) - для пользовательской коллекции, у которой есть идентификатор с тем же идентификатором из коллекции аутентификации.
Я видел этот пост , который, кажется, имеет ту же проблему и пытался работать из того, на что намекает ответ, - но я не могу найти способ, который работает, чтобы перейти от коллекции Authentication к коллекции пользователей, и я не знаю, что такое слияние делаю для меня, если он не дает мне доступ к атрибутам в коллекции пользователей из authUser.
Я пытался использовать помощник в своей базе данных. js, чтобы дать мне пользователя из uid - но это тоже не помогает.
user = uid => this.db.doc(`users/${uid}`);
users = () => this.db.collection('users');
Следующая попытка
Чтобы добавить больше фона, я создал тестовый компонент, который может регистрировать (но не отображать) ) authUser, следующим образом:
import React, { Component } from 'react';
import { withFirebase } from '../Firebase/Index';
import { Button, Layout } from 'antd';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';
class Test extends Component {
constructor(props) {
super(props);
this.state = {
loading: false,
user: null,
...props.location.state,
};
}
componentDidMount() {
if (this.state.user) {
return;
}
this.setState({ loading: true });
// this.unsubscribe = this.props.firebase
// .user(authUser.uid)
// .onSnapshot(snapshot => {
// const userData = snapshot.data();
// console.log(userData);
// this.setState({
// user: snapshot.data(),
// loading: false,
// });
// });
}
componentWillUnmount() {
this.unsubscribe && this.unsubscribe();
}
render() {
const { user, loading } = this.state;
return (
<div>
<AuthUserContext.Consumer>
{authUser => (
console.log(authUser),
<p>
</p>
)}
</AuthUserContext.Consumer>
</div>
);
};
}
export default Test;
В журнале отображаются подробные данные для uid, email и c в журналах, но он входит в длинный список элементов, многие из которых начинаются с 1 или 2 буквы (я не могу найти ключ, чтобы узнать, что означают эти префиксные буквы). Пример, извлеченный ниже:
ОБНОВЛЕНИЕ НА ЭТОМ КОММЕНТАРИИ:
Ранее я говорил: поля для uid, email et c похоже, что они не вложены в эти префиксы, но если я пытаюсь:
console.log(authUser.email)
, я получаю сообщение об ошибке:
TypeError: Невозможно прочитать свойство 'email' из null
Обновление: Я только что понял, что в журнале консоли мне нужно развернуть выпадающее меню с надписью:
Q {I : Array (0), l:
, чтобы увидеть атрибут электронной почты. Кто-нибудь знает, на что намекает этот jibberi sh? Я не могу найти ключ, чтобы выяснить, что означает Q, I или l, чтобы узнать, должен ли я ссылаться на эти вещи, чтобы добраться до соответствующих атрибутов в таблице Authentication. Может быть, если я смогу это выяснить - я смогу найти способ добраться до коллекции пользователей, используя uid из коллекции Authentication.
Кто-нибудь использовал реакцию на интерфейс, с потребителем контекста, чтобы узнать, кто текущий пользователь есть? Если да, то как вы получаете доступ к их атрибутам в модели аутентификации и как вы обращались к атрибутам в связанной коллекции пользователей (где docId в документе пользователя является идентификатором пользователя из таблицы аутентификации)?
СЛЕДУЮЩАЯ ПОПЫТКА
Следующая попытка дала очень странный результат.
У меня есть две отдельные страницы, которые являются потребителями контекста. Разница между ними заключается в том, что один является функцией, а другой - компонентом класса.
В компоненте функции я могу выполнить {authUser.email}. Когда я пытаюсь сделать то же самое в компоненте класса, я получаю сообщение об ошибке:
TypeError: Невозможно прочитать свойство 'email' со значением null
Эта ошибка приходит из того же сеанса с тем же вошедшим в систему пользователем.
Примечание: хотя в документации firebase сказано, что свойство currentUser доступно при авторизации - я не смог заставить его работать вообще.
Мой функциональный компонент имеет:
import React from 'react';
import { Link } from 'react-router-dom';
import { compose } from 'recompose';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';
const Account = () => (
<AuthUserContext.Consumer>
{authUser => (
<div>
{authUser.email}
</div>
)}
</AuthUserContext.Consumer>
);
// const condition = authUser => !!authUser;
// export default compose(
// withEmailVerification,
// withAuthorization(condition),
// )(Account);
export default Account;
Хотя я не могу добраться до атрибутов коллекции User, где docId в пользовательском документе совпадает с uid аутентифицированного пользователя, из этого компонента я могу вывести атрибут email в коллекции auth для этого пользователя.
Хотя документация Firebase предоставляет этот совет для управления пользователями и доступа к атрибутам, я не нашел способа реализовать этот подход в реакции. Каждый вариант попытки сделать это, как с помощью помощников в моем firebase. js, так и с попытки начать с нуля в компоненте, приводит к ошибкам в доступе к firebase. Тем не менее, я могу создать список пользователей и связанную с ними информацию о коллекции пользователей (я не могу получить пользователя на основе того, кто является authUser).
Мой компонент класса имеет:
import React from 'react';
import {
BrowserRouter as Router,
Route,
Link,
Switch,
} from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';
class Dashboard extends React.Component {
state = {
collapsed: false,
};
onCollapse = collapsed => {
console.log(collapsed);
this.setState({ collapsed });
};
render() {
const { loading } = this.state;
// const dbUser = this.props.firebase.app.snapshot.data();
// const user = Firebase.auth().currentUser;
return (
<AuthUserContext.Consumer>
{authUser => (
<div>
{authUser.email} // error message as shown above
{console.log(authUser)} // output logged in amongst a long list of menus prefixed with either 1 or 2 characters. I can't find a key to decipher what these menus mean or do.
</div>
)}
</AuthUserContext.Consumer>
);
}
}
//export default withFirebase(Dashboard);
export default Dashboard;
В моем AuthContext.Provider - у меня есть:
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 });
},
);
}
componentWillUnmount() {
this.listener();
};
render() {
return (
<AuthUserContext.Provider value={this.state.authUser}>
<Component {...this.props} />
</AuthUserContext.Provider>
);
}
}
return withFirebase(WithAuthentication);
};
export default withAuthentication;
СЛЕДУЮЩАЯ ПОПЫТКА
Странно, что с этой попыткой я пытаюсь сохранить в журнале значения, которые, как я вижу, существуют в базе данных, и значение name возвращается как «неопределенное», где в базе данных есть строка.
Эта попытка имеет:
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 { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';
class Dash extends React.Component {
// state = {
// collapsed: 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)
// .user(this.props.user.uid)
// .user(authUser.uid)
// .user(authUser.id)
// .user(Firebase.auth().currentUser.id)
// .user(Firebase.auth().currentUser.uid)
.onSnapshot(snapshot => {
this.setState({
user: snapshot.data(),
loading: false,
});
});
}
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 (
<AuthUserContext.Consumer>
{authUser => (
<div>
{loading && <div>Loading ...</div>}
<Layout style={{ minHeight: '100vh' }}>
<Sider collapsible collapsed={this.state.collapsed} onCollapse={this.onCollapse}>
<div />
</Sider>
<Layout>
<Header>
{console.log("authUser:", authUser)}
// this log returns the big long list of outputs - the screen shot posted above is an extract. It includes the correct Authentication table (collection) attributes
{console.log("authUser uid:", authUser.uid)}
// this log returns the correct uid of the current logged in user
{console.log("Current User:", this.props.firebase.auth.currentUser.uid)}
// this log returns the correct uid of the current logged in user
{console.log("current user:", this.props.firebase.db.collection("users").doc(this.props.firebase.auth.currentUser.uid
))}
// this log returns a big long list of things under a heading: DocumentReference {_key: DocumentKey, firestore: Firestore, _firestoreClient: FirestoreClient}. One of the attributes is: id: (...) (I can't click to expand this).
{console.log("current user:", this.props.firebase.db.collection("users").doc(this.props.firebase.auth.currentUser.uid
).name)}
//this log returns: undefined. There is an attribute in my user document called 'name'. It has a string value on the document with the id which is the same as the currentUser.uid.
<Text style={{ float: 'right', color: "#fff"}}>
{user && (
<Text style={{ color: "#fff"}}>{user.name}
//this just gets skipped over in the output. No error but also does not return the name.
</Text>
)}
</Text>
</Header>
</Layout>
</Layout>
</div>
)}
</AuthUserContext.Consumer>
);
}
}
export default withFirebase(Dash);
СЛЕДУЮЩАЯ ПОПЫТКА
Так что эта попытка неуклюжа и не использует хелперы или запросы снимков что я пытался использовать выше, но зарегистрируйте атрибуты документа коллекции пользователей на консоли следующим образом:
{this.props.firebase.db.collection ('users'). do c (authUser.uid ) .get ()
.then(doc => {
console.log(doc.data().name)
})
}
Что я не могу сделать, так это найти способ отрисовки этого имени в jsx
Как вы на самом деле печатаете вывод?
Когда я пытаюсь:
{
this.props.firebase.db.collection('users').doc(authUser.uid).get().data().name
}
Я получаю сообщение об ошибке:
Ошибка типа: this.props.firebase.db.collection (...). Do * +1194 * (...). get (...). data не является функцией
Когда я пытаюсь:
{
this.props.firebase.db.collection('users').doc(authUser.uid).get()
.then(doc => {
console.log(doc.data().name),
<p>doc.data().name</p>
})
}
я получаю сообщение об ошибке:
Строка 281: 23: ожидал присваивания или вызова функции и вместо этого видел выражение no-unused-expression *
Когда я пытаюсь:
{
this.props.firebase.db.collection('users').doc(authUser.uid).get("name")
.then(doc => {
console.log(doc.data().name),
<p>doc.data().name</p>
})
}
Сообщение об ошибке гласит:
Ожидал назначения или вызова функции и вместо этого увидел выражение
Я готов отказаться от попыток выяснить, как получить Запросы моментальных снимков для работы - если я могу просто получить имя коллекции пользователей для визуализации на экране. Кто-нибудь может помочь с этим шагом?
СЛЕДУЮЩАЯ ПОПЫТКА
Я нашел этот пост . В нем есть хорошее объяснение того, что должно произойти, но я не могу реализовать это, как показано, потому что componentDidMount не знает, что такое authUser.
Моя текущая попытка заключается в следующем - однако, как написано в настоящее время, authUser обертка для возвращаемого значения - и сегмент componentDidMount не знает, что такое authUser.
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 } from '../Session/Index';
const { Title, Text } = 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.props.firebase.db
.collection('users')
.doc(authUser.uid)
.get()
.then(doc => {
this.setState({ user_name: doc.data().name });
// loading: false,
});
}
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 (
<AuthUserContext.Consumer>
{ authUser => (
<div>
<Header>
{/*
{
this.props.firebase.db.collection('users').doc(authUser.uid).get()
.then(doc => {
console.log( doc.data().name
)
})
}
*/}
</Text>
</Header>
<Switch>
</Switch>
</div>
)}
</AuthUserContext.Consumer>
);
}
}
export default withFirebase(Dashboard);
СЛЕДУЮЩАЯ ПОПЫТКА
Далее я попытался обернуть маршрут для панель инструментов внутри AuthContext.Consumer, чтобы его мог использовать весь компонент, что позволило мне получить доступ к зарегистрированному пользователю в функции componentDidMount.
Я изменил маршрут на:
<Route path={ROUTES.DASHBOARD} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
и удалил потребителя из оператора рендеринга компонента панели мониторинга.
Затем в componentDidMount компонента Dashboard я попытался:
componentDidMount() {
if (this.state.user) {
return;
}
this.setState({ loading: true });
this.unsubscribe =
this.props.firebase.db
.collection('users')
//.doc(this.props.firebase.db.collection('users').doc(this.props.firebase.authUser.uid))
.doc(this.props.firebase.db.collection('users').doc(this.props.authUser.uid))
.get()
.then(doc => {
this.setState({ name: doc.data().name });
loading: false,
});
}
При попытке этого я получаю сообщение об ошибке:
FirebaseError: Функция CollectionReference.do c () требует, чтобы ее первый аргумент имел тип непустой строки, но было: пользовательский объект DocumentReference
СЛЕДУЮЩАЯ ПОПЫТКА Представленные ниже люди, кажется, находят что-то полезное в первом предложенном решении. Я не смог найти в нем ничего полезного, но, читая его предложения, я изо всех сил пытаюсь понять, как работает пример в документации по firebase (он не раскрывает, как присвоить .do * значение для .do c () запрос), который выглядит следующим образом:
db.collection("cities").doc("SF");
docRef.get().then(function(doc) {
if (doc.exists) {
console.log("Document data:", doc.data());
} else {
// doc.data() will be undefined in this case
console.log("No such document!");
}
в корне отличается от моей попытки в функции componentDidMount, а именно:
this.unsubscribe =
this.props.firebase.db
.collection('users')
// .doc(this.props.firebase.db.collection('users').doc(this.props.firebase.authUser.uid))
// .doc(this.props.firebase.db.collection('users').uid: this.props.firebase.auth().currentUser.uid )
.doc(this.props.authUser.uid)
.get()
.then(doc => {
this.setState({ user.name: doc.data().name });
// loading: false,
}else {
// doc.data() will be undefined in this case
console.log("Can't find this record");
}
);
}
Возможно, решение этого шага является подсказкой, которая поможет продвинуть его к результату. Может ли кто-нибудь найти лучшую документацию по пожарному хранилищу, чтобы показать, как получить запись коллекции пользователей, используя зарегистрированный пользовательский uid слушателя?
С этой целью я вижу в кодовой лаборатории FriendlyEats пример , что есть попытка присвоить do c .id значение поиска id в коде. Я не знаю, на каком языке написан этот код - но он действительно похож на то, что я пытаюсь сделать - я просто не понимаю, как перейти от этого примера к тому, с чем я знаю, как работать.
display: function(doc) {
var data = doc.data();
data['.id'] = doc.id;
data['go_to_restaurant'] = function() {
that.router.navigate('/restaurants/' + doc.id);
};