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 (인증 속성으로 연결되도록 작동)에서 인증 콜렉션과 동일한 uid를 가진 사용자 콜렉션으로 이동하는 방법을 찾을 수 없습니다.
나는 이 게시물 을 보았습니다. 이 게시물 은 같은 문제가있는 것으로 보이며 대답이 암시 해야하는 것을 해결하려고 시도했지만 인증 컬렉션에서 사용자 컬렉션으로 가져 오는 방법을 찾지 못하는 것 같습니다. 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의 속성 ‘이메일’을 읽을 수 없습니다
업데이트 :
방금 콘솔 로그에서 레이블이 지정된 드롭 다운 메뉴를 확장해야한다는 것을 깨달았습니다.
Q {I : 배열 (0), l :
이메일 속성을 확인하십시오. 이 혼란스러운 점을 아는 사람이 있습니까? 인증 테이블의 관련 속성을 얻기 위해 이러한 것들을 참조해야하는지 알기 위해 Q, I 또는 l의 의미를 알아내는 열쇠를 찾을 수 없습니다. 어쩌면 내가 알아낼 수 있다면 Authentication 컬렉션의 uid를 사용하여 사용자 컬렉션에 액세스하는 방법을 찾을 수 있습니다.
현재 사용자가 누구인지 알아 내기 위해 컨텍스트 소비자와 함께 프런트 엔드에서 반응 한 사람이 있습니까? 그렇다면 인증 모델에서 해당 속성에 어떻게 액세스하고 관련 사용자 콜렉션 (사용자 문서의 docId가 인증 테이블의 uid 임)의 속성에 어떻게 액세스 했습니까?
다음 공격
다음 시도는 매우 이상한 결과를 낳았습니다.
컨텍스트 소비자 인 2 개의 개별 페이지가 있습니다. 차이점은 하나는 함수이고 다른 하나는 클래스 구성 요소입니다.
함수 구성 요소에서 {authUser.email}을 렌더링 할 수 있습니다. 클래스 구성 요소에서 동일한 작업을 수행하려고하면 다음과 같은 오류가 발생합니다.
TypeError : null의 속성 ‘이메일’을 읽을 수 없습니다
이 오류는 동일한 로그인 사용자와 동일한 세션에서 발생합니다.
참고 : 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 collection 속성을 얻을 수 없지만이 사용자의 auth collection에 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;
다음 공격
이 시도로 데이터베이스에 존재하는 값을 콘솔 로그에 기록하려고하는데 name 값이 ‘정의되지 않음’으로 반환되고 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 ( ‘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>
})
}
다음과 같은 오류가 발생합니다.
Line 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>
})
}
오류 메시지는 다음과 같습니다.
할당 또는 함수 호출을 예상하고 대신 표현식을 보았습니다.
화면에 렌더링 할 사용자 모음의 이름을 얻을 수 있다면 스냅 샷 쿼리를 작동시키는 방법을 찾으려고 포기할 준비가되었습니다. 누구든지 그 단계를 도울 수 있습니까?
다음 공격
이 게시물을 찾았 습니다 . 어떤 일이 발생해야하는지에 대한 좋은 설명이 있지만 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>
)} />
대시 보드 구성 요소 렌더링 문에서 소비자를 제거했습니다.
그런 다음 Dashboard 구성 요소의 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 : Function 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를 제공하려는 시도가 있음을 알 수 있습니다. 이 코드가 어떤 언어로 작성되었는지는 알지 못합니다. 그러나 시도하고있는 것과 비슷해 보입니다. 예제에서 작업 방법을 알고있는 것으로 이동하는 방법을 볼 수 없습니다.
display: function(doc) {
var data = doc.data();
data['.id'] = doc.id;
data['go_to_restaurant'] = function() {
that.router.navigate('/restaurants/' + doc.id);
};
답변
질문의 마지막 줄 ( users = () => this.db.collection('users');
)에서 사용자에 대한 추가 정보를 저장하는 컬렉션이 호출 users
되고이 컬렉션의 사용자 문서가 userId (uid)를 docId로 사용한다는 것을 알고 있습니다.
다음은 트릭을 수행해야합니다 (예상되지 않음).
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.db.collection('users').doc(authUser.uid)
.get()
.then(snapshot => {
const userData = snapshot.data();
console.log(userData);
//Do whatever you need with userData
//i.e. merging it with authUser
//......
next(authUser);
});
} else {
fallback();
}
});
따라서 onAuthStateChanged()
메소드를 통해 설정된 옵저버 내에서 사용자가 로그인 한 것을 감지하면 (예 : in if (authUser) {}
) 콜렉션 uid
에서이 사용자에 해당하는 고유 문서를 쿼리하는 데 사용합니다 users
( 하나의 문서 읽기 및 문서 참조 ). get()
방법).
답변
시험해보고 싶은 이론이 있습니다.
핸들러 next(authUser)
내부에서 호출 할 때 onAuthStateChanged
실행 중에 오류 (예 :)가 발생 한다고 생각합니다 cannot read property 'name' of undefined at ...
.
코드가 예상대로 작동하지 않는 이유는 호출하는 곳이 Promise 체인 next(authUser)
내부에 있기 때문 then()
입니다. 약속 내에서 발생하는 모든 오류가 발생하여 약속이 거부됩니다. 약속이 거부되면 오류가있는 첨부 된 오류 처리기를 호출합니다. 해당 Promise 체인에는 현재 이러한 오류 처리기가 없습니다.
내가 당신을 잃어버린 경우 , Promises crash course에 대한 이 블로그 게시물 을 읽은 다음 다시 오십시오.
그런 상황을 피하기 위해 어떻게해야합니까? 가장 간단한 방법은 Promise 핸들러 범위 next(authUser)
밖에서 호출하는 것 then()
입니다. 우리는 이것을 사용하여 이것을 할 수 있습니다 window.setTimeout(function)
.
따라서 코드에서
next(authUser)
와
setTimeout(() => next(authUser))
// or setTimeout(() => next(authUser), 0) for the same result
이는 Promise 체인에 걸리지 않고 정상적인 오류를 발생시킵니다.
중요한 것은 userDocRef.get()
실패 했을 때 처리하는 catch 처리기가 없다는 것 입니다. 따라서 오류가 발생하면 코드가 대체 방법을 사용하도록 .catch(() => setTimeout(fallback))
끝에 추가 then()
하십시오.
그래서 우리는 다음과 같이 끝납니다.
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 = {
...dbUser, // CHANGED: Moved dbUser to beginning so it doesn't override other info
uid: authUser.uid,
email: authUser.email,
emailVerified: authUser.emailVerified,
providerData: authUser.providerData
};
setTimeout(() => next(authUser), 0); // invoke callback outside of Promise
})
.catch((err) => setTimeout(() => fallback(), 0)); // invoke callback outside of Promise
편집 된 코드
위의 설명을 사용하면 코드를 수정할 수 있지만 다음은 Firebase
사용하기 쉬운 다양한 버전의 클래스입니다.
용법:
import FirebaseHelper from './FirebaseHelper.js';
const fb = new FirebaseHelper();
fb.onUserDataListener(userData => {
// do something - user is logged in!
}, () => {
// do something - user isn't logged in or an error occurred
}
클래스 정의 :
// granular Firebase namespace import
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
const config = { /* firebase config goes here */ };
export default class FirebaseHelper { // renamed from `Firebase` to prevent confusion
constructor() {
/* init SDK if needed */
if (firebase.apps.length == 0) { firebase.initializeApp(config); }
/* helpers */
this.fieldValue = app.firestore.FieldValue;
/* Firebase APIs */
this.auth = firebase.auth();
this.db = firebase.firestore();
}
getUserDocRef(uid) { // renamed from `user`
return this.db.doc(`users/${uid}`);
}
getUsersColRef() { // renamed from `users`
return this.db.collection('users');
}
/**
* Attaches listeners to user information events.
* @param {function} next - event callback that receives user data objects
* @param {function} fallback - event callback that is called on errors or when user not logged in
*
* @returns {function} unsubscribe function for this listener
*/
onUserDataListener(next, fallback) {
return this.auth.onAuthStateChanged(authUser => {
if (!authUser) {
// user not logged in, call fallback handler
fallback();
return;
}
this.getUserDocRef(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('Error while getting user document -> ', err.code ? err.code + ': ' + err.message : (err.message || err));
setTimeout(fallback, 0); // escapes this Promise's error handler
});
});
}
// ... other methods ...
}
이 버전에서이 onUserDataListener
메소드는에서 구독 취소 기능을 반환합니다 onAuthStateChanged
. 구성 요소가 마운트 해제되면 메모리 누수가 발생하지 않거나 필요하지 않은 백그라운드에서 코드가 깨지지 않도록 관련 리스너를 분리해야합니다.
class SomeComponent {
constructor() {
this._unsubscribe = fb.onUserDataListener(userData => {
// do something - user is logged in!
}, () => {
// do something - user isn't logged in or an error occurred
};
}
// later
componentWillUnmount() {
this._unsubscribe();
}
}
답변
당신에 AuthContext.Provider
구현, 당신은 SDK의 액세스 onAuthStateChanged
직접 수신기를 :
componentDidMount() {
this.listener = this.props.firebase.auth.onAuthStateChanged(
authUser => {
authUser
? this.setState({ authUser })
: this.setState({ authUser: null });
}
);
}
onAuthUserListener
도우미 클래스에서 를 사용하도록 변경해야합니다 .
componentDidMount() {
this.listener = this.props.firebase.onAuthUserListener(
/* next() */ (authUserWithData) => this.setState({authUser: authUserWithData}),
/* fallback() */ () => this.setState({authUser: null})
);
}
많은 임의의 속성으로 채워진 로그 메시지와 관련하여 이는 firebase.User
개체에 공개 API 와 컴파일 할 때 최소화되는 여러 개인 속성 및 메서드가 포함 된 구현 이 있기 때문 입니다. 이러한 축소 된 속성과 메서드는 명시 적으로 열거 할 수없는 것으로 표시되지 않으므로 모든 로그 출력에 포함됩니다. 실제로 유용한 부분 만 기록하려는 경우 다음을 사용하여 오브젝트를 구조화하고 재구성 할 수 있습니다.
// Extracts public properties of firebase.User objects
// see https://firebase.google.com/docs/reference/js/firebase.User#properties
function extractPublicProps(user) {
let {displayName, email, emailVerified, isAnonymous, metadata, phoneNumber, photoURL, providerData, providerId, refreshToken, tenantId, uid} = user;
return {displayName, email, emailVerified, isAnonymous, metadata, phoneNumber, photoURL, providerData, providerId, refreshToken, tenantId, uid}
}
function extractUsefulProps(user) {
let {displayName, email, emailVerified, isAnonymous, phoneNumber, photoURL, uid} = user;
return {displayName, email, emailVerified, isAnonymous, phoneNumber, photoURL, uid}
}
let authUser = firebase.auth().currentUser;
console.log(authUser);
console.log(extractPublicProps(authUser));
console.log(extractUsefulProps(authUser));
답변
다른 사람이 비슷하게 붙어 있으면 여기에서 해결책을 찾았습니다 .Firebase & React : CollectionReference.doc () 인수 유형
페이지 새로 고침에서는 작동하지 않지만 (여전히 uid가 null이라는 오류가 발생 함) useEffect에 대한 후크는 componentDidMount 함수를 Mount 및 Update의 조합으로 바꿔야합니다. 다음에 시도하고 있습니다.