คุณจะรับรายละเอียด db ผู้ใช้ที่เกี่ยวข้องกับ authUser ใน Firestore ได้อย่างไร


10

ฉันกำลังพยายามหาวิธีรับชื่อผู้ใช้ซึ่งเป็นคุณลักษณะที่เก็บไว้ในคอลเลกชันผู้ใช้ซึ่งถูกรวมเข้ากับคุณลักษณะที่สร้างขึ้นโดยรูปแบบการรับรองความถูกต้องของ firebase

ฉันสามารถเข้าถึง authUser - ซึ่งให้ฐานข้อมูล firefield ที่ จำกัด แก่ฉันในเครื่องมือการตรวจสอบความถูกต้องแล้วฉันก็พยายามที่จะได้รับจากที่นั่นไปยังคอลเลกชันผู้ใช้ที่เกี่ยวข้อง (ซึ่งใช้ 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 (ซึ่งทำงานเพื่อให้ฉันไปยังแอตทริบิวต์การรับรองความถูกต้อง) - ไปยังคอลเลกชันผู้ใช้ที่มี ID ที่มี 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, อีเมล ฯลฯ ไม่ปรากฏว่าซ้อนอยู่ใต้คำนำหน้าเหล่านี้ แต่ถ้าฉันพยายาม:

 console.log(authUser.email)

ฉันได้รับข้อผิดพลาดที่แจ้งว่า:

TypeError: ไม่สามารถอ่าน 'อีเมล' ของ null ได้

การปรับปรุง: ฉันเพิ่งรู้ว่าในบันทึกของคอนโซลฉันต้องขยายเมนูแบบเลื่อนลงที่มีข้อความ:

Q {I: Array (0), l:

เพื่อดูคุณสมบัติอีเมล์ ไม่มีใครรู้ว่าสิ่งที่พูดพล่อยๆนี้หมายถึงอะไร ฉันไม่สามารถหากุญแจเพื่อค้นหาว่าฉันหมายถึงอะไรฉันควรจะอ้างอิงสิ่งเหล่านี้เพื่อไปยังแอตทริบิวต์ที่เกี่ยวข้องในตารางการรับรองความถูกต้องหรือไม่ บางทีถ้าฉันสามารถหาได้ - ฉันสามารถหาวิธีที่จะได้รับคอลเล็กชันผู้ใช้โดยใช้ uid จากคอลเลกชันการรับรองความถูกต้อง

มีใครใช้ปฏิกิริยาบนส่วนหน้ากับบริบทผู้บริโภคเพื่อค้นหาผู้ใช้ปัจจุบันคือใคร ถ้าเป็นเช่นนั้นคุณจะเข้าถึงคุณลักษณะของตนในรูปแบบการรับรองความถูกต้องได้อย่างไรและคุณเข้าถึงคุณลักษณะในคอลเลกชันผู้ใช้ที่เกี่ยวข้องได้อย่างไร (โดยที่ docId ในเอกสารผู้ใช้เป็น uid จากตารางการตรวจสอบสิทธิ์)

ความพยายามต่อไป

ความพยายามครั้งต่อไปให้ผลลัพธ์ที่แปลกมาก

ฉันมี 2 หน้าแยกต่างหากที่เป็นบริบทผู้บริโภค ความแตกต่างระหว่างพวกเขาคือหนึ่งคือฟังก์ชั่นและอื่น ๆ เป็นองค์ประกอบระดับ

ในองค์ประกอบของฟังก์ชั่นฉันสามารถแสดงผล {authUser.email} เมื่อฉันพยายามทำสิ่งเดียวกันในองค์ประกอบของคลาสฉันได้รับข้อผิดพลาดที่แจ้งว่า:

TypeError: ไม่สามารถอ่าน 'อีเมล' ของ null ได้

ข้อผิดพลาดนี้มาจากเซสชันเดียวกันกับผู้ใช้ที่เข้าสู่ระบบเดียวกัน

หมายเหตุ: ในขณะที่เอกสารฐานข้อมูล firebase บอกว่าคุณสมบัติผู้ใช้ปัจจุบันมีให้ใช้งานใน auth - ฉันไม่สามารถใช้งานได้เลย

องค์ประกอบฟังก์ชั่นของฉันมี:

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 ของผู้ใช้ที่ได้รับการรับรองความถูกต้องจากส่วนประกอบนี้ฉันสามารถส่งออกแอททริบิวต์อีเมลในการตรวจสอบสิทธิ์สำหรับผู้ใช้นี้

ในขณะที่เอกสารประกอบ 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 มีสตริงอยู่ในนั้น

ความพยายามนี้มี:

    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 (... ). รับ (... ) ข้อมูลไม่ใช่ฟังก์ชัน

เมื่อฉันลอง:

{ 



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

ข้อความแสดงข้อผิดพลาดแจ้งว่า:

คาดว่าจะได้รับมอบหมายหรือเรียกฟังก์ชั่นและแทนที่จะเห็นการแสดงออก

ฉันพร้อมที่จะล้มเลิกความพยายามที่จะหาวิธีที่จะทำให้คิวรีสแน็ปช็อตทำงาน - ถ้าฉันสามารถรับชื่อคอลเลกชันของผู้ใช้ที่จะแสดงบนหน้าจอ ใครสามารถช่วยในขั้นตอนนั้นได้บ้าง

ความพยายามต่อไป

ฉันพบโพสต์นี้ มันมีคำอธิบายที่ดีเกี่ยวกับสิ่งที่ต้องเกิดขึ้น แต่ฉันไม่สามารถนำไปใช้ได้ดังที่แสดงเนื่องจาก componentDidMount ไม่ทราบว่า authUser คืออะไร

ความพยายามในปัจจุบันของฉันมีดังนี้ - อย่างไรก็ตามตามที่เขียนไว้ในปัจจุบัน authUser เป็น wrapper ของค่าส่งคืน - และเซ็กเมนต์ componentDidMount ไม่ทราบว่า authUser คืออะไร

import React from 'react';
import {
    BrowserRouter as Router,
    Route,
    Link,
    Switch,
    useRouteMatch,
 } from 'react-router-dom';
import * as ROUTES from '../../constants/Routes';
import { compose } from 'recompose';
import { Divider, Layout, Card, Tabs, Typography, Menu, Breadcrumb, Icon } from 'antd';
import { withFirebase } from '../Firebase/Index';
import { AuthUserContext, withAuthorization, withEmailVerification } from '../Session/Index';




const { Title, Text } = Typography
const { TabPane } = Tabs;
const { Header, Content, Footer, Sider } = Layout;
const { SubMenu } = Menu;


class Dashboard extends React.Component {
  // state = {
  //   collapsed: false,
  //   loading: false,
  // };

  constructor(props) {
    super(props);

    this.state = {
      collapsed: false,
      loading: false,
      user: null,
      ...props.location.state,
    };
  }
  componentDidMount() {
    if (this.state.user) {
      return;
    }

    this.setState({ loading: true });

    this.unsubscribe = this.props.firebase
      .user(this.props.match.params.id)
      .onSnapshot(snapshot => {
        this.setState({
          user: snapshot.data(),
          loading: false,
        });
      });
  // }

//   firebase.firestore().collection("users")
//     .doc(this.state.uid)
//     .get()
//     .then(doc => {
//       this.setState({ post_user_name: doc.data().name });
//   });
// }

  this.props.firebase.db
    .collection('users')
    .doc(authUser.uid)
    .get()
    .then(doc => {
        this.setState({ user_name: doc.data().name });
        // loading: false,
      });  
    }                  

  componentWillUnmount() {
    this.unsubscribe && this.unsubscribe();
  }


  onCollapse = collapsed => {
    console.log(collapsed);
    this.setState({ collapsed });
  };

  render() {
    // const {  loading } = this.state;
    // const { user, loading } = this.state;
    // let match = useRouteMatch();
    // const dbUser = this.props.firebase.app.snapshot.data();
    // const user = Firebase.auth().currentUser;


    return (
    <AuthUserContext.Consumer>
      { authUser => (  

        <div>    

                <Header>

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


                  </Text>
                </Header>      

                      <Switch>

                      </Switch>    

        </div>
      )}
    </AuthUserContext.Consumer>  
    );
  }
}

export default withFirebase(Dashboard);

ความพยายามต่อไป

ถัดไปฉันพยายามปิดเส้นทางสำหรับแดชบอร์ดภายใน AuthContext.Consumer เพื่อให้ส่วนประกอบทั้งหมดสามารถใช้งานได้ - ดังนั้นให้ฉันเข้าถึงผู้ใช้ที่ล็อกอินในฟังก์ชั่น componentDidMount

ฉันเปลี่ยนเส้นทางเป็น:

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

และลบคอนซูมเมอร์ออกจากคำสั่งการเรนเดอร์องค์ประกอบแดชบอร์ด

จากนั้นใน componentDidMount บนองค์ประกอบ Dashboard ฉันพยายาม:

componentDidMount() {
    if (this.state.user) {
      return;
    }

    this.setState({ loading: true });

     this.unsubscribe =
     this.props.firebase.db
     .collection('users')
   //.doc(this.props.firebase.db.collection('users').doc(this.props.firebase.authUser.uid))
 .doc(this.props.firebase.db.collection('users').doc(this.props.authUser.uid))
     .get()
     .then(doc => {
         this.setState({ name: doc.data().name });
       loading: false,
      });  
  }                  

เมื่อฉันลองทำสิ่งนี้ฉันได้รับข้อผิดพลาดที่แจ้งว่า:

FirebaseError: Function CollectionReference.doc () ต้องการอาร์กิวเมนต์ตัวแรกที่ต้องเป็นสตริงที่ไม่ว่างเปล่า แต่มันเป็นวัตถุ DocumentReference แบบกำหนดเอง

ความพยายามครั้ง ต่อไปผู้คนด้านล่างดูเหมือนจะพบสิ่งที่มีประโยชน์ในโซลูชันแรกที่เสนอ ฉันไม่สามารถหาสิ่งที่มีประโยชน์ได้ แต่อ่านกลับผ่านคำแนะนำของฉันฉันดิ้นรนเพื่อดูว่าตัวอย่างในเอกสารประกอบ firebase (ไม่เปิดเผยวิธีการให้: 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!");
      }

ความแตกต่างกับความพยายามของฉันในฟังก์ชั่น 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");
      }

    );  
  }

บางทีการแก้ไขขั้นตอนนั้นเป็นเงื่อนงำที่จะช่วยในการย้ายไปสู่ผลลัพธ์ ทุกคนสามารถหาเอกสาร firestore ที่ดีกว่าเพื่อแสดงวิธีการรับบันทึกการรวบรวมผู้ใช้โดยใช้ฟังผู้ใช้ uid?

ด้วยเหตุนี้ฉันสามารถดูได้จากตัวอย่างการทดลองรหัส 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);
      };

FYI คำศัพท์ของคุณไม่ถูกต้องและทำให้คำถามนี้อ่านยาก ไม่มีสิ่งใดใน Firebase ที่เรียกว่า "ตาราง" ใน Firebase Auth มีเพียงผู้ใช้เท่านั้น - ไม่มี "ตารางการรับรองความถูกต้อง" ใน Firestore มีคอลเล็กชันและเอกสารภายในคอลเล็กชันเหล่านั้น แต่ไม่มีตาราง ฉันกำลังพยายามหาจุดที่คุณติดอยู่และวิธีที่รหัสที่คุณแสดงไม่ทำงานตามที่คุณคาดหวัง แต่ฉันไม่ได้ประกอบเข้าด้วยกัน ลองพิจารณาแก้ไขคำถามเพื่อใช้คำศัพท์มาตรฐานที่คุณพบเอกสารและชัดเจนยิ่งขึ้นเกี่ยวกับสิ่งที่ไม่ทำงานตามที่คุณคาดหวัง
Doug Stevenson

ดี - มีความสุขที่จะทดแทนตารางสำหรับคอลเลกชัน ประเด็นยังคงเหมือนเดิม
Mel

ประเด็นหลักของฉันคือฉันไม่สามารถเข้าใจประเด็นของคุณได้และคำศัพท์ไม่ได้ช่วยอะไร คุณช่วยอธิบายรายละเอียดเพิ่มเติมว่าอะไรไม่ทำงานในรหัสที่คุณแสดง สิ่งที่ไม่ทำงานตามที่คาดไว้หรือไม่ ข้อผิดพลาดใด ๆ หรือบันทึกการดีบักเพื่อแสดง?
Doug Stevenson

ไม่มีอะไรทำงาน ฉันคาดหวังว่าจะหาวิธีในการเข้าถึงรายละเอียดการรวบรวมผู้ใช้จากผู้ฟัง authUser authUser มีการกำหนดไว้ในตัวจัดการบริบทและวิธีการเรียนที่เกี่ยวข้องที่รับฟังการเปลี่ยนแปลงในวิธีการ ฉันไม่สามารถรับคุณลักษณะในคอลเลกชันการรับรองความถูกต้องที่ผ่านมา - ฉันพยายามเข้าถึงคอลเลกชันผู้ใช้ที่เกี่ยวข้องในครั้งแรก ไม่มีบันทึก เพียงข้อความผิดพลาดที่บอกว่าเขตข้อมูลไม่ได้กำหนด
Mel

1
ฉันขอแนะนำให้เริ่มต้นด้วยงานง่าย ๆ ใช้งานเพื่อให้ได้รับประสบการณ์แล้วนำไปใช้กับปัญหาที่ซับซ้อนกว่าเช่นที่คุณมีอยู่ตอนนี้ ไม่มีอะไรผิดปกติเกี่ยวกับเอกสาร (ฉันรู้ว่าเพราะฉันใช้มันตลอดเวลาและฉันช่วยคนที่เหมือนกัน) ในการรับความช่วยเหลือเกี่ยวกับ Stack Overflow คุณจะต้องแสดงปัญหาเฉพาะโดยเฉพาะ MCVE ที่ทุกคนสามารถใช้เพื่อทำให้เกิดปัญหาอีกครั้ง เพียงแค่พูดว่า "ฉันไม่สามารถทำงานได้" ไม่เพียงพอ stackoverflow.com/help/minimal-reproducible-example
Doug Stevenson

คำตอบ:


5

ฉันเข้าใจจากบรรทัดสุดท้ายของคำถามของคุณ ( 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()วิธีการเมื่อเราตรวจพบว่าผู้ใช้ลงชื่อเข้าใช้ (เช่นในif (authUser) {}) เราจะใช้มันuidเพื่อสืบค้นเอกสารเฉพาะที่สอดคล้องกับผู้ใช้รายนี้ในusersคอลเล็กชัน (ดูอ่านหนึ่งเอกสารและเอกสารของget()วิธี).


มีบางอย่างผิดปกติกับวิธีที่ฉันได้กำหนดไว้ใน AuthUserListener หรือไม่ ถ้าฉันลองทำการแก้ไขวิธีการของคุณฉันควรทำอย่างไรเพื่อไปที่การรวบรวมผู้ใช้จาก authUser
Mel

"ดังนั้นมีบางอย่างผิดปกติกับวิธีที่ฉันกำหนดไว้บนผู้ใช้ UserListener" -> ไม่ใช่จากสิ่งที่ฉันเห็น "ฉันควรทำอย่างไรเพื่อไปยังคอลเล็กชันผู้ใช้จาก authUser" -> ถ้าฉันเข้าใจถูกต้องคุณต้องการได้รับเอกสารหนึ่งฉบับไม่ใช่ของสะสม รหัสในคำตอบควรใช้งานได้
Renaud Tarnec

ฉันต้องการรับ authUser - รหัสของคุณเป็นการปรับปรุงในความพยายามของฉัน? ฉันไม่สามารถหาวิธีที่ใช้งาน authUser เพื่อให้ฉันสามารถเข้าถึงคอลเลกชันผู้ใช้ที่มี uid เดียวกันได้ ฉันกำลังพยายามที่จะเข้าใจข้อเสนอแนะของคุณสำหรับวิธีการที่ปรับปรุงในฉันเป็นขั้นตอนแรก กรุณาคุณสามารถระบุว่าบิตของมันคือการปรับปรุง / แก้ไข? ขอบคุณ
เมล

จะเกิดอะไรขึ้นถ้าคุณทำthis.auth.onAuthStateChanged(authUser => { if (authUser) {console.log(authUser.uid) })?
Renaud Tarnec

ฉันสามารถส่งออกคุณสมบัติ authUser ทั้งหมด (ข้อมูลการรวบรวมการรับรองความถูกต้อง) ฉันไม่สามารถเข้าถึงข้อมูลผู้ใช้จากเอกสารที่เกี่ยวข้องในการรวบรวมผู้ใช้ที่มี uid เป็น id
Mel

1

ฉันมีทฤษฎีที่ฉันต้องการให้คุณทดสอบ

ฉันคิดว่าเมื่อคุณโทรnext(authUser)เข้าไปในonAuthStateChangedตัวจัดการของคุณในระหว่างการดำเนินการมันพบข้อผิดพลาด (เช่นcannot read property 'name' of undefined at ...)

สาเหตุที่รหัสของคุณไม่ทำงานตามที่คาดไว้เป็นเพราะที่ที่คุณโทรnext(authUser)มันอยู่ในthen()ห่วงโซ่ของสัญญา ข้อผิดพลาดใด ๆ ที่เกิดขึ้นภายในสัญญาจะถูกตรวจจับและทำให้สัญญาถูกปฏิเสธ เมื่อสัญญาถูกปฏิเสธก็จะเรียกมันว่ามันจัดการข้อผิดพลาดที่แนบมากับข้อผิดพลาด ห่วงโซ่สัญญาที่มีปัญหาในขณะนี้ไม่มีเครื่องมือจัดการข้อผิดพลาด

ถ้าฉันทำคุณทำหายให้อ่านโพสต์บล็อกนี้เพื่อดูหลักสูตรความผิดพลาดของสัญญาแล้วกลับมา

แล้วเราจะทำอย่างไรเพื่อหลีกเลี่ยงสถานการณ์เช่นนี้? ที่ง่ายที่สุดคือการโทรnext(authUser) ออกนอกthen()ขอบเขตของตัวจัดการสัญญา window.setTimeout(function)เราสามารถทำได้โดยใช้

ดังนั้นในรหัสของคุณคุณจะแทนที่

next(authUser)

กับ

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

การทำเช่นนี้จะทำให้เกิดข้อผิดพลาดตามปกติแทนที่จะเป็นห่วงโซ่สัญญา

ที่สำคัญคุณยังไม่มีตัวจัดการ catch ที่จัดการเมื่อuserDocRef.get()ล้มเหลว ดังนั้นเพียงแค่เพิ่ม.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();
  }
}

ขอบคุณ! ฉันจะลองคืนนี้ ฉันตื่นเต้นที่จะเรียนรู้เกี่ยวกับวิธีนี้ทั้งสอง ฉันจะกลับมาพร้อมข้อเสนอแนะในไม่ช้า
Mel

สวัสดีแซม - ขอบคุณที่ให้คำแนะนำนี้ ฉันใช้เวลาอ่านเอกสารที่คุณเชื่อมโยงและฉันก็ใช้เวลาไม่นาน ในขณะที่ฉันขอบคุณสำหรับความช่วยเหลือ - นี่ไม่ได้แก้ปัญหาของฉัน เมื่อฉันพยายามเข้าถึงแอ็ตทริบิวต์การรวบรวมผู้ใช้ฉันยังคงได้รับข้อผิดพลาดที่แจ้งว่า: TypeError: ไม่สามารถอ่านคุณสมบัติ 'ผู้ใช้' ที่ไม่ได้กำหนด
Mel

@Mel เมื่อคุณเรียกใช้รหัสเดิมคุณได้รับแจ้งจาก TypeError หรือไม่ นี่เป็นครั้งแรกที่คุณพูดถึงมัน ซึ่งหมายความว่ารหัสนี้เป็นหน้าที่ของการโยนข้อผิดพลาดนอกขอบเขตของสัญญา คุณสามารถให้การส่งออกของconsole.log(snapshot.data())?
samthecodingman

ฉันพยายามนี้ - ข้อความผิดพลาดพูดว่า: TypeError: snapshot.data ไม่ใช่ฟังก์ชั่น
Mel

ฉันจะพยายามเคลื่อนย้ายไปรอบ ๆ - บางทีฉันอาจไม่พยายามบันทึกสิ่งนี้ในจุดที่ดี
Mel

0

ในAuthContext.Providerการนำไปใช้ของคุณคุณเข้าถึงonAuthStateChanged ผู้ฟังของ SDK โดยตรง:

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วัตถุมีทั้งpublic APIและการใช้งานที่มีคุณสมบัติส่วนตัวและวิธีการต่าง ๆ ที่ถูกย่อให้เล็กลงเมื่อรวบรวม เนื่องจากคุณสมบัติและวิธีการที่ย่อเล็กสุดเหล่านี้ไม่ได้ถูกทำเครื่องหมายอย่างชัดเจนว่าไม่สามารถนับได้จึงรวมอยู่ในเอาต์พุตบันทึกใด ๆ หากคุณต้องการบันทึกเฉพาะส่วนที่มีประโยชน์จริง ๆ คุณสามารถ destruct และปรับโครงสร้างวัตถุโดยใช้:

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

ขอบคุณ @ samthecodingman ที่พยายามช่วยเหลือฉันต่อไป ฉันได้ดูที่นี้ วัตถุประสงค์ของฉันคือการอ่าน uid ของ authUser เพื่อที่ฉันจะได้ใช้มันเพื่อรับคุณสมบัติของคอลเลกชันผู้ใช้ที่เกี่ยวข้องสำหรับผู้ใช้นั้น (ชื่อในคอลเลกชันผู้ใช้มีมากกว่า displayName ในคอลเลกชัน autbase firebase - ดังนั้นฉันไม่พยายาม อ่านคุณสมบัติของตารางการรับรองความถูกต้อง
Mel

การเปลี่ยนแปลงที่แนะนำในฟังก์ชั่น componentDidMount ไม่ทำให้เกิดข้อผิดพลาด - แต่มันไม่ทำงาน เมื่อพยายามบันทึกค่าของ authUser ในส่วนประกอบแดชบอร์ดโดยใช้ฟังนี้ - ฉันได้รับข้อผิดพลาดว่า authUser ไม่ได้ถูกกำหนด ฉันไม่ได้รับข้อผิดพลาดนี้เมื่อฉันใช้ componentDidMount สำหรับ AuthContext.Provider ตามที่ฉันได้กำหนดไว้ ขอบคุณสำหรับข้อมูลเกี่ยวกับคุณสมบัติแบบสุ่มในข้อความบันทึก
Mel

@Mel คุณสามารถยืนยันได้ว่าบรรทัดสุดท้ายของDashboardไฟล์ของคุณคือexport default withAuthentication(Dashboard);(และไม่ใช่withFirebase)
samthecodingman

ได้รับการยืนยัน withFirebase ถูกรวมเข้ากับ withAuthentication - ดังนั้นจึงรับผ่าน HOC นั้น
Mel

@Mel คุณสามารถตรวจสอบข้อความที่ฉันส่งให้คุณใน Slack
samthecodingman

0

หากคนอื่นติดขัดฉันพบวิธีแก้ปัญหาที่นี่: Firebase & React: CollectionReference.doc () ประเภทอาร์กิวเมนต์

มันไม่ทำงานในการรีเฟรชหน้า (ยังคงโยนข้อผิดพลาดที่ uid เป็นโมฆะ) แต่ตอบสนอง hooks เพื่อ useEffect ควรแทนที่ฟังก์ชั่น componentDidMount ด้วยการรวมกันของ Mount และ Update ฉันกำลังลองสิ่งต่อไป

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.