Firestore'da bir authUser ile ilgili kullanıcı db ayrıntılarını nasıl edinebilirsiniz?


10

Firebase kimlik doğrulama modeli tarafından oluşturulan özniteliklerle birleştirilen bir kullanıcı koleksiyonunda depolanan bir öznitelik olan bir kullanıcı adı almak nasıl anlamaya çalışıyorum.

Bana kimlik doğrulama aracında firebase topladığı sınırlı alanları veren authUser erişebilir ve sonra (aynı uid kullanan) ilgili kullanıcı koleksiyonuna oradan almaya çalışıyorum.

Ben bir tepki bağlam tüketici ile var:

import React from 'react';
const AuthUserContext = React.createContext(null);
export default AuthUserContext;

Sonra benim bileşeninde kullanmaya çalışıyorum:

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);

Benim firebase.js - Bence Kimlik Doğrulama modelinden authUser özniteliklerini kullanıcı toplama öznitelikleri ile aşağıdaki gibi birleştirmeye çalıştım:

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();
      }
    });

Kimlik Doğrulama koleksiyonundan aynı kullanıcı kimliğine sahip bir kimliğe sahip kullanıcı koleksiyonuna authUser'den (Kimlik Doğrulama özniteliklerine ulaşmak için çalışır) bir yol bulamıyorum.

Aynı soruna sahip gibi görünen ve cevabın ima ettiği şeyleri bulmaya çalıştığım bu yayını gördüm - ancak Kimlik Doğrulama koleksiyonundan kullanıcı koleksiyonuna ulaşmak için çalışan bir yol bulamıyorum authUser kullanıcı koleksiyonundaki özelliklere erişmeme izin vermiyorsa birleştirme işleminin benim için ne yaptığını bilmiyorum.

Bir kullanıcı bana bir kullanıcı vermek için firebase.js bir yardımcı kullanmaya çalıştı - ama bu da yardımcı gibi görünmüyor.

user = uid => this.db.doc(`users/${uid}`);
  users = () => this.db.collection('users');

Bir sonraki deneme

Daha fazla arka plan eklemek için aşağıdaki gibi authUser günlüğü (ama render değil) bir test bileşeni yaptık:

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;

Günlük, günlüklerde uid, e-posta vb. İçin ayrıntıları gösterir, ancak çoğu 1 veya 2 harfle ön sırada olan uzun bir öğe listesinin arasındadır (bu öneklerin her birini bulmak için bir anahtar bulamıyorum harfler anlamına gelir). Aşağıda çıkarılan örnek:

resim açıklamasını buraya girin

BU YORUMDA GÜNCELLEME:

Önceden, dedim: uid, e-posta vb alanları bu öneklerin altında yuvalanmış gibi görünmüyor, ancak şunu denerseniz:

 console.log(authUser.email)

, Bir hata mesajı alıyorum:

TypeError: null özelliği 'e-posta' okunamıyor

Güncelleme: Konsol günlüğünde etiketli bir açılır menüyü genişletmem gerektiğini fark ettim:

Q {I: Dizi (0), l:

e-posta özelliğini görmek için. Herkes bu nimetin ne anlama geldiğini biliyor mu? Kimlik Doğrulama tablosundaki ilgili özniteliklere ulaşmak için bunlara atıfta bulunup bulunmamam gerektiğini bilmek için Q, I veya l'in ne anlama geldiğini anlamak için bir anahtar bulamıyorum. Belki anlayabiliyorsam - Kimlik Doğrulama koleksiyonundan uid kullanarak kullanıcı koleksiyonuna ulaşmak için bir yol bulabilirim.

Mevcut kullanıcının kim olduğunu bulmak için bağlam tüketicisi ile kullanıcı ön tarafta tepki gösterdi mi? Öyleyse, Kimlik Doğrulama modelindeki özniteliklerine nasıl erişiyorsunuz ve ilgili Kullanıcı koleksiyonundaki özniteliklere nasıl eriştiniz (Kullanıcı belgesindeki docId, Kimlik Doğrulama tablosundan uid'dir)?

SONRAKİ GİRİŞ

Bir sonraki girişim çok garip bir sonuç doğurdu.

Bağlam tüketicisi olan 2 ayrı sayfam var. Aralarındaki fark, birinin bir işlev ve diğerinin bir sınıf bileşenidir.

Fonksiyon bileşeninde {authUser.email} oluşturabilirim. Sınıf bileşeninde aynı şeyi yapmaya çalıştığımda, şöyle bir hata alıyorum:

TypeError: null özelliği 'e-posta' okunamıyor

Bu hata, oturum açmış aynı kullanıcıyla aynı oturumdan geliyor.

Not: Firebase belgeleri, bir currentUser özelliğinin auth üzerinde kullanılabilir olduğunu söylese de - bunu hiç çalıştıramadım.

İşlev bileşenim şunları içerir:

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;

Kullanıcı belgesindeki docId'nin kimliği doğrulanmış kullanıcının uidiyle aynı olduğu Kullanıcı koleksiyonu özniteliklerine erişemesem de, bu bileşenden bu kullanıcının kimlik doğrulama koleksiyonundaki e-posta özniteliğini çıktılayabilirim.

Firebase belgeleri , kullanıcıları yönetmek ve buradaki özelliklere erişmek için bu tavsiyeyi sunarken, bu yaklaşımı tepki olarak uygulamak için bir yol bulamadım. Bunu yapmak için yapılan bir girişimin her varyasyonu, hem firebase.js dosyamda yardımcılar oluşturarak hem de bir bileşende sıfırdan başlamaya çalışarak ateş tabanına erişimde hatalar üretir. Ancak kullanıcıların bir listesini ve ilgili Kullanıcı toplama bilgilerini üretebilirim (authUser'ın kim olduğuna bağlı olarak bir kullanıcı alamıyorum).

Sınıf bileşenim:

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;

Benim AuthContext.Provider - var:

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;

SONRAKİ GİRİŞ

Gerçekten bu girişim ile, ben veritabanında var gördüğünüz değerleri günlüğü konsol çalışıyorum ve ad değeri db içinde bir dize vardır 'undefined' olarak döndürülüyor garip.

Bu girişimde şunlar var:

    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);

SONRAKİ GİRİŞ

Bu nedenle bu girişim beceriksizdir ve yukarıda kullanmaya çalıştığım yardımcıları veya anlık görüntü sorgularını kullanmaz, ancak kullanıcı toplama belgesi niteliklerini konsola aşağıdaki gibi günlüğe kaydedin:

{this.props.firebase.db.collection ('users'). doc (authUser.uid) .get ()

      .then(doc => {
          console.log(doc.data().name) 
      })

    } 

Ne yapamam jsx bu adı oluşturmak için bir yol bulmak

Çıktıyı gerçekten nasıl yazdırıyorsunuz?

Denediğimde:

{ 


this.props.firebase.db.collection('users').doc(authUser.uid).get().data().name

                }

Bir hata mesajı alıyorum:

TypeError: this.props.firebase.db.collection (...). Doc (...). Get (...). Veri bir işlev değildir

Denediğimde:

{ 



this.props.firebase.db.collection('users').doc(authUser.uid).get()
              .then(doc => {
                  console.log(doc.data().name), 
                  <p>doc.data().name</p>
              })
            } 

Bir hata mesajı alıyorum:

Satır 281: 23: Bir atama veya işlev çağrısı bekleniyordu ve bunun yerine kullanılmayan ifadeler olmayan bir ifade gördü

Denediğimde:

{ 


this.props.firebase.db.collection('users').doc(authUser.uid).get("name")
              .then(doc => {
                  console.log(doc.data().name), 
                  <p>doc.data().name</p>
              })
            }

Hata mesajı şunu söylüyor:

Bir ödev veya işlev çağrısı bekleniyordu ve bunun yerine bir ifade gördü

Anlık görüntü sorgularının nasıl çalışacağını öğrenmeye çalışmaktan vazgeçmeye hazırım - eğer ekranda işlemek için kullanıcı koleksiyonunun adını alabilirsem. Herkes bu adımda yardımcı olabilir mi?

SONRAKİ GİRİŞ

Bu gönderiyi buldum . Ne olması gerektiği konusunda iyi bir açıklaması var, ancak componentDidMount authUser ne olduğunu bilmiyor çünkü gösterildiği gibi uygulayamıyorum.

Şu anki denemem şu şekildedir - ancak, şu anda yazıldığı gibi, authUser dönüş değerinde bir paketleyicidir - ve componentDidMount segmenti authUser'ın ne olduğunu bilmiyor.

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);

SONRAKİ GİRİŞ

Daha sonra, tüm bileşenin kullanabilmesi için AuthContext.Consumer içindeki gösterge tablosu için güzergahı kaydırmayı denedim - böylece beni componentDidMount işlevinde oturum açmış kullanıcıya erişmesine izin verin.

Rotayı şu şekilde değiştirdim:

<Route path={ROUTES.DASHBOARD} render={props => (
          <AuthUserContext.Consumer>
             { authUser => ( 
                <Dashboard authUser={authUser} {...props} />  
             )}
          </AuthUserContext.Consumer>
        )} />

ve müşteriyi gösterge tablosu bileşeni oluşturma ifadesinden kaldırdı.

Sonra Pano bileşenindeki componentDidMount, denedim:

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,
      });  
  }                  

Bunu denediğimde, şöyle bir hata alıyorum:

FirebaseError: Function CollectionReference.doc (), ilk bağımsız değişkeninin boş olmayan dize türünde olmasını gerektirir, ancak şuydu: özel bir DocumentReference nesnesi

SONRAKİ GİRİŞ Aşağıdaki kişiler ilk önerilen çözümde yararlı bir şeyler bulmuş gibi görünüyor. İçinde yararlı bir şey bulamadım, ancak önerilerini tekrar okudum, Firebase belgelerindeki örneğin nasıl .doc () isteğine nasıl: uid değeri verileceğini açıklamıyor ), aşağıdaki gibidir:

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!");
      }

temel olarak componentDidMount işlevindeki denememden farklıdır:

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");
      }

    );  
  }

Belki bu adımı çözmek, bunu bir sonuca doğru ilerletmeye yardımcı olacak bir ipucudur. Herkes, giriş yapmış bir kullanıcı dinleyici uid'i kullanarak bir kullanıcı toplama kaydını nasıl alacağını göstermek için daha iyi bir yangın deposu belgesi bulabilir mi?

Bu amaçla, FriendlyEats kod laboratuarı örneğinden , koddaki id arama değerine doc.id verme girişimi olduğunu görebiliyorum. Bu kodun hangi dilde yazıldığını bilmiyorum - ama yapmaya çalıştığım şeye benziyor - bu örnekten nasıl çalışacağımı bildiğim bir şeye nasıl taşınacağımı göremiyorum.

display: function(doc) {
      var data = doc.data();
      data['.id'] = doc.id;
      data['go_to_restaurant'] = function() {
        that.router.navigate('/restaurants/' + doc.id);
      };

FYI terminolojiniz doğru değil ve bu sorunun okunmasını zorlaştırıyor. Firebase'de "tablo" diye bir şey yoktur. Firebase Yetkilendirmesinde yalnızca kullanıcılar var - "Kimlik Doğrulama tablosu" yok. Firestore'da bu koleksiyonların içinde koleksiyonlar ve belgeler var, ancak tablo yok. Nerede sıkışıp kaldığını ve gösterdiğiniz kodun beklediğiniz şekilde çalışmadığını anlamaya çalışıyorum, ama sadece birlikte eklemiyorum. Soruyu, dokümanları bulacağınız daha standart bir terminoloji kullanacak şekilde düzenlemeyi ve beklediğiniz gibi çalışmayan şeylerle ilgili daha net olmayı düşünün.
Doug Stevenson

Güzel - koleksiyonlar için tabloları değiştirmek mutlu. Mesele hala aynı.
Mel

Asıl mesele, gerçekten senin fikrini alamadım ve terminoloji yardımcı olmadı. Gösterdiğiniz kodda neyin işe yaramadığını daha ayrıntılı olarak açıklayabilir misiniz? Bir şey beklendiği gibi çalışmadı mı? Herhangi bir hata veya hata ayıklama günlükleri göstermek için?
Doug Stevenson

Hiç birşey çalışmıyor. AuthUser dinleyicisinden kullanıcı toplama ayrıntılarına erişmenin bir yolunu bulmayı bekliyorum. authUser, bağlam işleyicisinde ve yöntemdeki değişiklikleri dinleyen ilgili sınıf yönteminde tanımlanır. Kimlik doğrulama koleksiyonundaki öznitelikleri geçemiyorum - firestore'daki ilgili kullanıcı koleksiyonuna erişmeye çalışıyorum. Günlük yok. Sadece alanın tanımsız olduğunu belirten hata mesajları.
Mel

1
Basit bir görevle başlamayı, biraz tecrübe kazanmak için işe koyulmasını, sonra şimdi sahip olduğunuz gibi daha karmaşık sorunlara uygulamanızı öneririm. Belgelerde temelde yanlış bir şey yok (biliyorum, çünkü her zaman kullanıyorum ve aynı insanlara yardım ediyorum). Yığın Taşması konusunda yardım almak için, belirli bir sorunu, ideal olarak, herkesin sorunu yeniden oluşturmak için kullanabileceği bir MCVE'yi göstermeniz gerekecektir. Sadece "Çalışamıyorum" demek yeterli değildir. stackoverflow.com/help/minimal-reproducible-example
Doug Stevenson

Yanıtlar:


5

Sorunuzun son satırından users = () => this.db.collection('users');, kullanıcılara fazladan bilgi depoladığınız koleksiyonun çağrıldığını usersve bu koleksiyondaki bir kullanıcı belgesinin docId olarak userId (uid) kullandığını anlıyorum.

Aşağıdakiler hile yapmalıdır (denenmemiş):

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();
      }
    });

Bu nedenle, onAuthStateChanged()yöntemle belirlenen gözlemci içinde, kullanıcının oturum açtığını (yani oturum açtığını if (authUser) {}) tespit ettiğimizde,uid , userskoleksiyonda bu kullanıcıya karşılık gelen benzersiz belgeyi sorgulamak için (bkz. Bir belgeyi okuma ve get()yöntem).


Peki, onAuthUserListener'da tanımladığım şekilde bir sorun mu var? O zaman bu yöntemde yaptığınız değişiklikleri denerseniz, kullanıcı koleksiyonuna authUser'dan ulaşmak için ne yapmam gerekiyor?
Mel

"Yani onAuthUserListener tanımladığım şekilde yanlış bir şey var mı?" -> görebildiğim kadarıyla değil. "authUser kullanıcı koleksiyonuna ulaşmak için ne yapmam gerekiyor?" -> Doğru bir şekilde anlarsam, koleksiyonu değil, BİR belge almak istersiniz. Yanıttaki kod çalışmalıdır.
Renaud Tarnec

Ben authUser almak istiyorum - kod benim girişimi bir gelişme var mı? Aynı kullanıcı kimliğine sahip kullanıcı koleksiyonuna erişim sağlamak için authUser almak için çalışan bir yol bulamıyorum. Bu benim ilk adım olarak benim üzerinde nasıl geliştiği için - kod öneri anlamaya çalışıyorum. Lütfen hangi parçanın iyileştirme / düzeltme olduğunu belirleyebilir misiniz? Teşekkür ederim
Mel

Yaparsan ne olur this.auth.onAuthStateChanged(authUser => { if (authUser) {console.log(authUser.uid) })?
Renaud Tarnec

Tüm authUser özelliklerini (kimlik doğrulama toplama verileri) çıktı alabilirim. Kimlik olarak kullanıcı kimliğine sahip kullanıcı koleksiyonundaki ilgili belgeden kullanıcı verilerine ulaşamıyorum
Mel

1

Test etmeni istediğim bir teorim var.

İşleyicinizin next(authUser)içinde aradığınızda onAuthStateChanged, yürütme sırasında bir hatayla (örneğin cannot read property 'name' of undefined at ...) karşılaştığını düşünüyorum .

Kodunuzun beklendiği gibi çalışmamasının nedeni, aradığınız yer next(authUser) , içinde öyle then()bir Promise zincirinin. Bir Sözün içine atılan hatalar yakalanır ve Sözün reddedilmesine neden olur. Bir Söz reddedildiğinde, ekli hata işleyicilerini hatayla çağırır. Söz konusu Promise zincirinin şu anda böyle bir hata işleyicisi yok.

Seni kaybettiysem, bu blog gönderisini oku Promises çarpışma kursu için ve geri dönün.

Peki böyle bir durumdan kaçınmak için ne yapabiliriz? En basit olanı Promise işleyicisinin kapsamı next(authUser) dışında aramaktır then(). Bunu kullanarak yapabilirizwindow.setTimeout(function) .

Yani kodunuzda,

next(authUser)

ile

setTimeout(() => next(authUser))
// or setTimeout(() => next(authUser), 0) for the same result

Bu, Promise zinciri tarafından yakalanmak yerine hataları normal olarak atar.

Önemli olarak, userDocRef.get()başarısız olduğunda işleyen bir yakalama işleyiciniz yok . Sadece .catch(() => setTimeout(fallback))sonuna eklethen() böylece kodunuz hata veriyorsa yedek yöntemi kullanır.

Sonuç olarak:

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

Düzenlenmiş kod

Yukarıdaki açıklama, kodunuzu düzeltmenize izin vermelidir, ancak işte Firebasesınıfınızın çeşitli kullanım kolaylığı değişiklikleriyle versiyonum .

Kullanımı:

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
}

Sınıf tanımı:

// 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 ...
}

Bu sürümde, onUserDataListeneryöntemin aboneliği iptal işlevini döndürdüğünü unutmayın onAuthStateChanged. Bileşeninizin bağlantısı kesildiğinde, herhangi bir ilgili dinleyiciyi ayırmanız gerekir, böylece bellek sızıntısı olmaz veya kodun gerekmediğinde arka planda çalışmasını engellemelisiniz.

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();
  }
}

Teşekkür ederim! Bunu bu gece deneyeceğim. Bunu her iki şekilde de öğrenmek beni heyecanlandırıyor. Kısa süre içinde geri bildirim ile geri döneceğim.
Mel

Merhaba Sam - Bu öneriyi sunduğunuz için teşekkür ederiz. Bağladığınız belgeleri okumak için biraz zaman ayırdım ve bu konuda birkaç şey yaptım. Yardım için minnettarım - bu benim sorunumu çözmedi. Kullanıcı toplama özniteliklerine erişmeye çalıştığımda, hala bir hata alıyorum: TypeError: undefined 'kullanıcı' özelliği okunamıyor
Mel

@Mel Orijinal kodu çalıştırdığınızda, TypeError hakkında bilgilendirildiniz mi? İlk defa bahsetmiştin. Bu, kodun hatayı Promise kapsamının dışına atma işi yaptığı anlamına gelir. Çıktı sağlayabilir console.log(snapshot.data())?
samthecodingman

Bunu denedim - hata mesajı diyor ki: TypeError: snapshot.data bir işlev değil
Mel

Onu hareket ettirmeye çalışacağım - belki de bunu iyi bir yere kaydetmeye çalışmıyorum
Mel

0

Senin içinde AuthContext.Provideruygulanması, SDK'nın erişmek onAuthStateChanged doğrudan dinleyicinin:

componentDidMount() {
  this.listener = this.props.firebase.auth.onAuthStateChanged(
    authUser => {
      authUser
        ? this.setState({ authUser })
        : this.setState({ authUser: null });
    }
  );
}

Bu onAuthUserListener, yardımcı sınıfınızdan kullanılacak şekilde değiştirilmelidir :

componentDidMount() {
  this.listener = this.props.firebase.onAuthUserListener(
    /* next()     */ (authUserWithData) => this.setState({authUser: authUserWithData}),
    /* fallback() */ () => this.setState({authUser: null})
  );
}

Çok sayıda rastgele özellikle dolu günlük iletileri ile ilgili olarak, bunun nedeni firebase.Usernesnenin hem genel bir API'sı hem de derlendiğinde küçültülen bir dizi özel özellik ve yöntem içeren bir uygulaması olmasıdır. Bu minimize edilmiş özellikler ve yöntemler açıkça numaralandırılamaz olarak işaretlenmediğinden, herhangi bir günlük çıktısına dahil edilirler. Bunun yerine yalnızca gerçekten yararlı olan parçaları günlüğe kaydetmek istiyorsanız, nesneyi aşağıdakileri kullanarak yapılandırabilir ve yeniden yapılandırabilirsiniz:

// 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));

Bana yardım etmeye çalıştığın için @samthecodingman teşekkürler. Buna bir göz attım. Amacım authUser uid okumak için böylece o kullanıcı için ilgili kullanıcı toplama özniteliklerini almak için kullanabilirsiniz (kullanıcı koleksiyonunda adı firebase auth koleksiyonunda displayName daha fazla - bu yüzden denemiyorum Kimlik Doğrulama tablosunun özelliklerini okuyun
Mel

Dinleyici componentDidMount işlevinde önerilen değişiklik bir hata atmadı - ancak çalışmadı. Bu dinleyiciyi kullanarak gösterge paneli bileşeninde authUser değerini günlüğe kaydetmeye çalıştığında - authUser tanımlı değil diyerek bir hata alıyorum. AuthContext.Provider için componentDidMount kullandığım şekilde kullandığımda bu hatayı almıyorum. Günlük iletilerindeki rastgele özellikler hakkında bilgi için teşekkürler.
Mel

@Mel Can Eğer son satırı onaylamak Dashboarddosyanın olduğu export default withAuthentication(Dashboard);(ve withFirebase)
samthecodingman

Onaylanmış. withFirebase, Authentication'a dahil edilmiştir - bu nedenle bu HOC aracılığıyla alınır.
Mel

@Mel Slack'e gönderdiğim mesajları kontrol edebilir misin
samthecodingman

0

Başka biri benzer şekilde sıkışmışsa, çözümü burada buldum: Firebase & React: CollectionReference.doc () argüman tipi

Sayfa yenilemesinde çalışmaz (yine de uid'in boş olduğuna dair bir hata atar) ancak useEffect'in tepki kancaları, componentDidMount işlevini Mount ve Update'in bir kombinasyonuyla değiştirmelidir. Bir sonraki deniyorum.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.