Я намагаюся розібратися, як отримати ім’я користувача, який є атрибутом, що зберігається в колекції користувачів, який був об'єднаний з атрибутами, створеними моделлю аутентифікації 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);
У своєму firebase.js - я думаю, що я намагався об'єднати атрибути authUser з моделі автентифікації з атрибутами колекції користувачів таким чином:
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) - до колекції користувачів, яка має ідентифікатор з тим самим uid з колекції Authentication.
Я бачив цю публікацію , яка, схоже, має ту саму проблему, і спробувала розібратися, на що натякає відповідь, - але я не можу знайти спосіб, який би перейшов із колекції аутентифікації до колекції користувача і я не знаю, що злиття робить для мене, якщо воно не дає мені доступу до атрибутів колекції користувачів від authUser.
Я намагався використовувати помічник у своєму firebase.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, електронної пошти тощо у журналах, але він є серед довгого списку елементів - багато з яких мають збір із 1 або 2 літер (я не можу знайти ключ, щоб дізнатися, що означає кожен з цих префіксів букви означають). Приклад, витягнутий нижче:
ОНОВЛЕННЯ НА ЦІЙ КОМЕНТАР:
Раніше я говорив: поля для uid, електронної пошти тощо не здаються вкладеними під цими префіксами, але якщо я спробую:
console.log(authUser.email)
, Я отримую помилку, яка говорить:
TypeError: Неможливо прочитати властивість 'email' з null
Оновлення: я щойно зрозумів, що в журналі консолі я повинен розгорнути випадаюче меню, яке позначене:
Q {I: масив (0), л:
щоб побачити атрибут електронної пошти. Хтось знає, на що на це натякає цей вереск? Я не можу знайти ключ, щоб зрозуміти, що означає Q, я чи я, щоб знати, чи повинен я посилатися на ці речі, щоб потрапити на відповідні атрибути в таблиці автентифікації. Можливо, якщо я можу це зрозуміти - я можу знайти спосіб потрапити до колекції користувачів за допомогою uid з колекції Authentication.
Хтось із реагуючих реагував на передній частині, щоб споживач контексту дізнався, хто такий поточний користувач? Якщо так, то як ви отримуєте доступ до їх атрибутів на моделі автентифікації та як ви отримали доступ до атрибутів у відповідній колекції користувача (де docId у документі користувача є uid з таблиці автентифікації)?
НАСЛІДЧИЙ НАСТУП
Наступна спроба дала дуже дивний результат.
У мене є дві окремі сторінки, які є споживачами контексту. Різниця між ними полягає в тому, що одна є функцією, а інша - складовою класу.
У компоненті функції я можу відтворити {authUser.email}. Коли я намагаюся зробити те ж саме в компоненті класу, я отримую помилку, яка говорить:
TypeError: Неможливо прочитати властивість 'email' з null
Ця помилка надходить з одного сеансу з тим самим авторизованим користувачем.
Примітка. Хоча в документації на базу даних говориться про те, що властивість 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 автентифікованого користувача, з цього компонента я можу вивести атрибут електронної пошти в колекцію auth для цього користувача.
Хоча документація Firebase надає цю пораду щодо управління користувачами та доступу до атрибутів тут, я не знайшов способу реалізувати цей підхід в реагуванні. Кожна варіація спроби зробити це, як створення помічників у моєму firebase.js, так і намагання почати з нуля в компоненті створює помилки в доступі до firebase. Однак я можу створити список користувачів та пов’язану з ними інформацію про колекцію користувачів (я не можу отримати користувача на основі того, хто є користувачем).
Мій компонент класу:
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;
НАСЛІДЧИЙ НАСТУП
Це дійсно дивно, що за допомогою цієї спроби я намагаюся консолювати журнал значень, які я можу бачити, що існують у базі даних, і значення імені повертається як "невизначене", де в db є рядок.
Ця спроба:
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 ('користувачі'). doc (authUser.uid) .get ()
.then(doc => {
console.log(doc.data().name)
})
}
Що я не можу зробити, хоча знайти спосіб видати це ім’я в jsx
Як ви насправді друкуєте вихід?
Коли я намагаюся:
{
this.props.firebase.db.collection('users').doc(authUser.uid).get().data().name
}
Я отримую помилку, яка говорить:
TypeError: this.props.firebase.db.collection (...). Doc (...). Get (...) Дані не є функцією
Коли я намагаюся:
{
this.props.firebase.db.collection('users').doc(authUser.uid).get()
.then(doc => {
console.log(doc.data().name),
<p>doc.data().name</p>
})
}
Я отримую помилку, яка говорить:
Рядок 281: 23: Очікується призначення або виклик функції, а замість цього з'явився вираз "невикористані" вирази
Коли я намагаюся:
{
this.props.firebase.db.collection('users').doc(authUser.uid).get("name")
.then(doc => {
console.log(doc.data().name),
<p>doc.data().name</p>
})
}
Повідомлення про помилку говорить:
Очікували виклик призначення чи функції та замість цього бачили вираз
Я готовий відмовитись від спроб дізнатися, як змусити працювати запити знімків - якщо я можу просто отримати ім’я колекції користувачів для відображення на екрані. Хтось може допомогти в цьому кроці?
НАСЛІДЧИЙ НАСТУП
Я знайшов цю посаду . У ньому є чітке пояснення того, що має відбутися, але я не можу реалізувати це, як показано, оскільки компонентDidMount не знає, що таке authUser.
Моя поточна спроба полягає в наступному - однак, як написано в даний час, authUser є обгорткою повернутого значення - і сегмент компонентаDidMount не знає, що таке 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, щоб цілий компонент міг ним користуватися - тим самим дозволяючи мені отримати доступ до зареєстрованого користувача у функції компонентаDidMount.
Я змінив маршрут на:
<Route path={ROUTES.DASHBOARD} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
та вилучив споживача із заяви про надання візуальної частини панелі інструментів.
Потім у компоненті компонент DidMount на панелі інструментів я спробував:
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: Function CollectionReference.doc () вимагає, щоб його перший аргумент був нетиповим рядком типу, але це: спеціальний об'єкт DocumentReference
НАЙКРАЩА УВАГА Люди внизу, здається, знайдуть щось корисне в першому запропонованому рішенні. Я не зміг знайти в ньому нічого корисного, але читаючи його пропозиції, я намагаюся бачити, як приклад в документації на базу даних (він не розкриває, як надати: uid значення запиту .doc () ), що полягає в наступному:
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!");
}
принципово відрізняється від моєї спроби у функції компонентаDidMount, а саме:
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");
}
);
}
Можливо, вирішити цей крок - це підказка, яка допоможе досягти цього до результату. Чи може хтось знайти кращу документацію firestore, щоб показати, як отримати запис про колекцію користувачів, використовуючи зареєстрований користувальницький номер користувача?
З цією метою я бачу з прикладу лабораторії коду FriendlyEats, що в коді є спроба надати doc.id значенню пошуку id. Я не знаю, на якій мові написаний цей код - але він схожий на те, що я намагаюся зробити - я просто не бачу, як перейти з цього прикладу до чогось, з чим я знаю, як працювати.
display: function(doc) {
var data = doc.data();
data['.id'] = doc.id;
data['go_to_restaurant'] = function() {
that.router.navigate('/restaurants/' + doc.id);
};