私は、Firebase Authenticationモデルによって作成された属性とマージされた、ユーザーコレクションに格納されている属性であるユーザー名を取得する方法を理解しようとしています。
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属性を取得するために機能する)から、Authenticationコレクションから同じuidのIDを持つユーザーコレクションに取得する方法が見つかりません。
私はこの投稿を見て、同じ問題があるようであり、答えが示唆しているはずのものを解決しようとしました-しかし、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、emailなどのフィールドはこれらのプレフィックスの下にネストされているようには見えませんが、私がしようとすると:
console.log(authUser.email)
、私は言うエラーが出ます:
TypeError:nullのプロパティ 'email'を読み取れません
更新: コンソールログで、ラベルが付いたドロップダウンメニューを展開する必要があることに気づきました。
Q {I:配列(0)、l:
email属性を確認します。この意味不明な表現が何を示唆しているのか誰か知っていますか?Q、I、またはlの意味を理解するためのキーが見つからないため、認証テーブルの関連する属性にアクセスするためにこれらを参照する必要があるかどうかを確認できません。多分それを理解することができれば-Authenticationコレクションのuidを使用してユーザーコレクションにアクセスする方法を見つけることができます。
現在のユーザーが誰であるかを確認するためにコンテキストコンシューマーを使用して、誰かがフロントエンドで反応を使用しましたか?その場合、認証モデルの属性にどのようにアクセスし、関連するユーザーコレクションの属性にどのようにアクセスしましたか(ユーザードキュメントのdocIdは認証テーブルのuidです)。
次の試み
次の試みは非常に奇妙な結果を生みました。
コンテキストコンシューマである2つの個別のページがあります。それらの違いは、1つは関数であり、もう1つはクラスコンポーネントであるということです。
関数コンポーネントでは、{authUser.email}をレンダリングできます。クラスコンポーネントで同じことを実行しようとすると、次のエラーが表示されます。
TypeError:nullのプロパティ 'email'を読み取れません
このエラーは、同じログインユーザーと同じセッションから発生しています。
注:firebaseのドキュメントでは、authで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;
ユーザードキュメントのdocIdが認証されたユーザーのuidと同じであるUserコレクション属性に到達できませんが、このコンポーネントから、このユーザーのauthコレクションのemail属性を出力できます。
ここでは、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;
次の試み
この試みで、データベースに存在することが確認できる値をコンソールログに記録しようとしていて、名前の値がdbに文字列が含まれている「undefined」として返されているのは本当に奇妙です。
この試みには、
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')。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(...)。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-expressionsが見られました
私が試したとき:
{
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>
)} />
ダッシュボードコンポーネントのrenderステートメントからコンシューマーを削除しました。
次に、ダッシュボードコンポーネントのcomponentDidMountで、私は試しました:
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.doc()では、最初の引数は空でない文字列型である必要がありますが、それは次のとおりです:カスタムDocumentReferenceオブジェクト
次の試み 以下の人々は、最初に提案された解決策で何か役立つものを見つけたようです。私はそれに役立つものを見つけることができませんでしたが、その提案を読み返して、Firebaseドキュメントの例を確認するのに苦労しています(.doc()リクエストに:uid値を与える方法は開示されていません) )、これは次のとおりです。
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を使用してユーザーコレクションレコードを取得する方法を示す、より優れたFirestoreのドキュメントを見つけられる人はいますか?
そのため、FriendlyEatsコードラボの例から、コード内のid検索値にdoc.idを指定しようとしていることがわかります。このコードがどの言語で書かれているかはわかりませんが、Imがやろうとしていることと似ています-その例から、操作方法がわかっているものに移動する方法がわかりません。
display: function(doc) {
var data = doc.data();
data['.id'] = doc.id;
data['go_to_restaurant'] = function() {
that.router.navigate('/restaurants/' + doc.id);
};