Saya mencoba mencari cara menggunakan pendengar Firebase agar data cloud firestore di-refresh dengan pembaruan kait reaksi.
Awalnya, saya membuat ini menggunakan komponen kelas dengan fungsi componentDidMount untuk mendapatkan data firestore.
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,
});
}
Itu rusak ketika halaman diperbarui, jadi saya mencoba mencari cara untuk memindahkan pendengar untuk bereaksi.
Saya telah menginstal alat react-firebase-hooks - walaupun saya tidak tahu cara membaca instruksi untuk membuatnya berfungsi.
Saya memiliki komponen fungsi sebagai berikut:
import React, { useState, useEffect } from 'react';
import { useDocument } from 'react-firebase-hooks/firestore';
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, withAuthentication } from '../Session/Index';
function Dashboard2(authUser) {
const FirestoreDocument = () => {
const [value, loading, error] = useDocument(
Firebase.db.doc(authUser.uid),
//firebase.db.doc(authUser.uid),
//firebase.firestore.doc(authUser.uid),
{
snapshotListenOptions: { includeMetadataChanges: true },
}
);
return (
<div>
<p>
{error && <strong>Error: {JSON.stringify(error)}</strong>}
{loading && <span>Document: Loading...</span>}
{value && <span>Document: {JSON.stringify(value.data())}</span>}
</p>
</div>
);
}
}
export default withAuthentication(Dashboard2);
Komponen ini dibungkus pembungkus pengguna otomatis pada tingkat rute sebagai berikut:
<Route path={ROUTES.DASHBOARD2} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard2 authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
Saya memiliki file firebase.js, yang dihubungkan ke firestore sebagai berikut:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
/* helpers */
this.fieldValue = app.firestore.FieldValue;
/* Firebase APIs */
this.auth = app.auth();
this.db = app.firestore();
}
Itu juga mendefinisikan pendengar untuk mengetahui kapan authUser berubah:
onAuthUserListener(next, fallback) {
// onUserDataListener(next, fallback) {
return this.auth.onAuthStateChanged(authUser => {
if (authUser) {
this.user(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('An error occured -> ', err.code ? err.code + ': ' + err.message : (err.message || err));
setTimeout(fallback, 0); // escapes this Promise's error handler
});
};
if (!authUser) {
// user not logged in, call fallback handler
fallback();
return;
}
});
};
Kemudian, dalam pengaturan konteks firebase saya, saya memiliki:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase';
export default Firebase;
export { FirebaseContext, withFirebase };
Konteksnya diatur dalam pembungkus withFirebase sebagai berikut:
import React from 'react';
const FirebaseContext = React.createContext(null);
export const withFirebase = Component => props => (
<FirebaseContext.Consumer>
{firebase => <Component {...props} firebase={firebase} />}
</FirebaseContext.Consumer>
);
export default FirebaseContext;
Kemudian, dalam HOC withAuthentication saya, saya memiliki penyedia konteks sebagai:
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;
Saat ini - ketika saya mencoba ini, saya mendapatkan kesalahan dalam komponen Dashboard2 yang mengatakan:
Firebase 'tidak ditentukan
Saya mencoba firebase huruf kecil dan mendapatkan kesalahan yang sama.
Saya juga mencoba firebase.firestore dan Firebase.firestore. Saya mendapatkan kesalahan yang sama.
Saya ingin tahu apakah saya tidak dapat menggunakan HOC saya dengan komponen fungsi?
Saya telah melihat aplikasi demo ini dan posting blog ini .
Mengikuti saran di blog, saya membuat firebase / contextReader.jsx baru dengan:
import React, { useEffect, useContext } from 'react';
import Firebase from '../../firebase';
export const userContext = React.createContext({
user: null,
})
export const useSession = () => {
const { user } = useContext(userContext)
return user
}
export const useAuth = () => {
const [state, setState] = React.useState(() =>
{ const user = firebase.auth().currentUser
return { initializing: !user, user, }
}
);
function onChange(user) {
setState({ initializing: false, user })
}
React.useEffect(() => {
// listen for auth state changes
const unsubscribe = firebase.auth().onAuthStateChanged(onChange)
// unsubscribe to the listener when unmounting
return () => unsubscribe()
}, [])
return state
}
Lalu saya mencoba untuk membungkus App.jsx di pembaca itu dengan:
function App() {
const { initializing, user } = useAuth()
if (initializing) {
return <div>Loading</div>
}
// )
// }
// const App = () => (
return (
<userContext.Provider value={{ user }}>
<Router>
<Navigation />
<Route path={ROUTES.LANDING} exact component={StandardLanding} />
Ketika saya mencoba ini, saya mendapatkan kesalahan yang mengatakan:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2 __. Default.auth bukan fungsi
Saya telah melihat posting ini berurusan dengan kesalahan itu dan telah mencoba mencopot dan menginstal ulang utas. Tidak ada bedanya.
Ketika saya melihat aplikasi demo , itu menunjukkan bahwa konteks harus dibuat menggunakan metode 'antarmuka'. Saya tidak bisa melihat dari mana ini berasal - saya tidak dapat menemukan referensi untuk menjelaskannya di dokumentasi.
Saya tidak dapat memahami instruksi selain mencoba apa yang telah saya lakukan untuk menyambungkan ini.
Saya telah melihat posting ini yang mencoba mendengarkan firestore tanpa menggunakan hook-react-firebase. Jawabannya mengarah pada upaya mencari tahu cara menggunakan alat ini.
Saya telah membaca penjelasan yang luar biasa ini yang membahas cara berpindah dari HOC ke kait. Saya terjebak dengan cara mengintegrasikan pendengar firebase.
Saya telah melihat posting ini yang memberikan contoh bermanfaat untuk bagaimana berpikir tentang melakukan ini. Tidak yakin apakah saya harus mencoba melakukan ini di authListener componentDidMount - atau di komponen Dashboard yang mencoba menggunakannya.
PERIKSA BERIKUTNYA Saya menemukan posting ini , yang mencoba untuk memecahkan masalah yang sama.
Ketika saya mencoba menerapkan solusi yang ditawarkan oleh Shubham Khatri, saya mengatur konfigurasi firebase sebagai berikut:
Penyedia konteks dengan: import React, {useContext} dari 'react'; impor Firebase dari '../../firebase';
const FirebaseContext = React.createContext();
export const FirebaseProvider = (props) => (
<FirebaseContext.Provider value={new Firebase()}>
{props.children}
</FirebaseContext.Provider>
);
Pengait konteks kemudian memiliki:
import React, { useEffect, useContext, useState } from 'react';
const useFirebaseAuthentication = (firebase) => {
const [authUser, setAuthUser] = useState(null);
useEffect(() =>{
const unlisten =
firebase.auth.onAuthStateChanged(
authUser => {
authUser
? setAuthUser(authUser)
: setAuthUser(null);
},
);
return () => {
unlisten();
}
});
return authUser
}
export default useFirebaseAuthentication;
Kemudian di index.js saya membungkus Aplikasi di penyedia sebagai:
import React from 'react';
import ReactDOM from 'react-dom';
import App from './components/App/Index';
import {FirebaseProvider} from './components/Firebase/ContextHookProvider';
import * as serviceWorker from './serviceWorker';
ReactDOM.render(
<FirebaseProvider>
<App />
</FirebaseProvider>,
document.getElementById('root')
);
serviceWorker.unregister();
Kemudian, ketika saya mencoba menggunakan pendengar dalam komponen yang saya miliki:
import React, {useContext} from 'react';
import { FirebaseContext } from '../Firebase/ContextHookProvider';
import useFirebaseAuthentication from '../Firebase/ContextHook';
const Dashboard2 = (props) => {
const firebase = useContext(FirebaseContext);
const authUser =
useFirebaseAuthentication(firebase);
return (
<div>authUser.email</div>
)
}
export default Dashboard2;
Dan saya mencoba menggunakannya sebagai rute tanpa komponen atau pembungkus auth:
<Route path={ROUTES.DASHBOARD2} component={Dashboard2} />
Ketika saya mencoba ini, saya mendapatkan kesalahan yang mengatakan:
Mencoba impor kesalahan: 'FirebaseContext' tidak diekspor dari '../Firebase/ContextHookProvider'.
Pesan kesalahan itu masuk akal, karena ContextHookProvider tidak mengekspor FirebaseContext - ini mengekspor FirebaseProvider - tetapi jika saya tidak mencoba mengimpor ini di Dashboard2 - maka saya tidak dapat mengaksesnya dalam fungsi yang mencoba menggunakannya.
Salah satu efek samping dari upaya ini adalah metode pendaftaran saya tidak lagi berfungsi. Sekarang menghasilkan pesan kesalahan yang mengatakan:
TypeError: Tidak dapat membaca properti 'doCreateUserWithEmailAndPassword' dari nol
Saya akan memecahkan masalah ini nanti- tetapi harus ada cara untuk mencari tahu bagaimana menggunakan bereaksi dengan firebase yang tidak melibatkan berbulan-bulan dari loop ini melalui jutaan jalan yang tidak bekerja untuk mendapatkan pengaturan auth dasar. Apakah ada starter kit untuk firebase (firestore) yang berfungsi dengan kait reaksi?
Upaya berikutnya saya mencoba mengikuti pendekatan dalam kursus udemy ini - tetapi hanya berfungsi untuk menghasilkan input formulir - tidak ada pendengar untuk menyiasati rute untuk menyesuaikan dengan pengguna yang diautentikasi.
Saya mencoba mengikuti pendekatan dalam tutorial youtube ini - yang membuat repo ini berfungsi. Ini menunjukkan cara menggunakan kait, tetapi tidak bagaimana menggunakan konteks.
PERIKSA BERIKUTNYA Saya menemukan repo ini yang tampaknya memiliki pendekatan yang dipikirkan dengan baik untuk menggunakan kait dengan firestore. Namun, saya tidak dapat memahami kode tersebut.
Saya mengkloning ini - dan mencoba untuk menambahkan semua file publik dan kemudian ketika saya menjalankannya - saya benar-benar tidak bisa mendapatkan kode untuk beroperasi. Saya tidak yakin apa yang tidak ada dalam instruksi untuk menjalankannya untuk melihat apakah ada pelajaran dalam kode yang dapat membantu menyelesaikan masalah ini.
PERIKSAAN BERIKUTNYA
Saya membeli template divjoy, yang diiklankan sebagai setup untuk firebase (ini bukan setup untuk firestore jika ada orang lain yang mempertimbangkan ini sebagai opsi).
Templat itu mengusulkan pembungkus autis yang menginisialisasi konfigurasi aplikasi - tetapi hanya untuk metode auth - sehingga perlu direstrukturisasi untuk memungkinkan penyedia konteks lain untuk firestore. Ketika Anda mengacaukan proses itu dan menggunakan proses yang ditunjukkan dalam posting ini , apa yang tersisa adalah kesalahan dalam panggilan balik berikut:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Tidak tahu apa itu firebase. Itu karena itu didefinisikan dalam penyedia konteks firebase yang diimpor dan didefinisikan (dalam fungsi useProvideAuth ()) sebagai:
const firebase = useContext(FirebaseContext)
Tanpa peluang untuk callback, kesalahan mengatakan:
Bereaksi Hook useEffect memiliki ketergantungan yang hilang: 'firebase'. Baik sertakan atau hapus larik ketergantungan
Atau, jika saya mencoba dan menambahkan const ke callback, saya mendapatkan kesalahan yang mengatakan:
React Hook "useContext" tidak dapat dipanggil di dalam panggilan balik. React Hooks harus dipanggil dalam komponen fungsi Bereaksi atau fungsi React Hook kustom
PERIKSAAN BERIKUTNYA
Saya telah mengurangi file konfigurasi firebase saya menjadi hanya variabel konfigurasi (Saya akan menulis helpers di penyedia konteks untuk setiap konteks yang ingin saya gunakan).
import firebase from 'firebase/app';
import 'firebase/auth';
import 'firebase/firestore';
const devConfig = {
apiKey: process.env.REACT_APP_DEV_API_KEY,
authDomain: process.env.REACT_APP_DEV_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_DEV_DATABASE_URL,
projectId: process.env.REACT_APP_DEV_PROJECT_ID,
storageBucket: process.env.REACT_APP_DEV_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_DEV_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_DEV_APP_ID
};
const prodConfig = {
apiKey: process.env.REACT_APP_PROD_API_KEY,
authDomain: process.env.REACT_APP_PROD_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_PROD_DATABASE_URL,
projectId: process.env.REACT_APP_PROD_PROJECT_ID,
storageBucket: process.env.REACT_APP_PROD_STORAGE_BUCKET,
messagingSenderId:
process.env.REACT_APP_PROD_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_PROD_APP_ID
};
const config =
process.env.NODE_ENV === 'production' ? prodConfig : devConfig;
class Firebase {
constructor() {
firebase.initializeApp(config);
this.firebase = firebase;
this.firestore = firebase.firestore();
this.auth = firebase.auth();
}
};
export default Firebase;
Saya kemudian memiliki penyedia konteks auth sebagai berikut:
import React, { useState, useEffect, useContext, createContext } from "react";
import Firebase from "../firebase";
const authContext = createContext();
// Provider component that wraps app and makes auth object ...
// ... available to any child component that calls useAuth().
export function ProvideAuth({ children }) {
const auth = useProvideAuth();
return <authContext.Provider value={auth}>{children}</authContext.Provider>;
}
// Hook for child components to get the auth object ...
// ... and update when it changes.
export const useAuth = () => {
return useContext(authContext);
};
// Provider hook that creates auth object and handles state
function useProvideAuth() {
const [user, setUser] = useState(null);
const signup = (email, password) => {
return Firebase
.auth()
.createUserWithEmailAndPassword(email, password)
.then(response => {
setUser(response.user);
return response.user;
});
};
const signin = (email, password) => {
return Firebase
.auth()
.signInWithEmailAndPassword(email, password)
.then(response => {
setUser(response.user);
return response.user;
});
};
const signout = () => {
return Firebase
.auth()
.signOut()
.then(() => {
setUser(false);
});
};
const sendPasswordResetEmail = email => {
return Firebase
.auth()
.sendPasswordResetEmail(email)
.then(() => {
return true;
});
};
const confirmPasswordReset = (password, code) => {
// Get code from query string object
const resetCode = code || getFromQueryString("oobCode");
return Firebase
.auth()
.confirmPasswordReset(resetCode, password)
.then(() => {
return true;
});
};
// Subscribe to user on mount
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
// Subscription unsubscribe function
return () => unsubscribe();
}, []);
return {
user,
signup,
signin,
signout,
sendPasswordResetEmail,
confirmPasswordReset
};
}
const getFromQueryString = key => {
return queryString.parse(window.location.search)[key];
};
Saya juga membuat penyedia konteks firebase sebagai berikut:
import React, { createContext } from 'react';
import Firebase from "../../firebase";
const FirebaseContext = createContext(null)
export { FirebaseContext }
export default ({ children }) => {
return (
<FirebaseContext.Provider value={ Firebase }>
{ children }
</FirebaseContext.Provider>
)
}
Lalu, di index.js saya membungkus aplikasi di penyedia firebase
ReactDom.render(
<FirebaseProvider>
<App />
</FirebaseProvider>,
document.getElementById("root"));
serviceWorker.unregister();
dan dalam daftar rute saya, saya telah membungkus rute yang relevan di penyedia auth:
import React from "react";
import IndexPage from "./index";
import { Switch, Route, Router } from "./../util/router.js";
import { ProvideAuth } from "./../util/auth.js";
function App(props) {
return (
<ProvideAuth>
<Router>
<Switch>
<Route exact path="/" component={IndexPage} />
<Route
component={({ location }) => {
return (
<div
style={{
padding: "50px",
width: "100%",
textAlign: "center"
}}
>
The page <code>{location.pathname}</code> could not be found.
</div>
);
}}
/>
</Switch>
</Router>
</ProvideAuth>
);
}
export default App;
Pada upaya khusus ini, saya kembali ke masalah yang ditandai sebelumnya dengan kesalahan ini:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2 __. Default.auth bukan fungsi
Ini menunjuk ke baris penyedia auth ini sebagai penyebab masalah:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Saya telah mencoba menggunakan huruf kapital F di Firebase dan menghasilkan kesalahan yang sama.
Ketika saya mencoba saran Tristan, saya menghapus semua hal itu dan mencoba dan mendefinisikan metode berhenti berlangganan saya sebagai metode yang tidak terdaftar (saya tidak tahu mengapa dia tidak menggunakan bahasa firebase - tetapi jika pendekatannya berhasil, saya akan berusaha lebih keras untuk mencari tahu mengapa). Ketika saya mencoba menggunakan solusinya, pesan kesalahan mengatakan:
TypeError: _util_contexts_Firebase__WEBPACK_IMPORTED_MODULE_8 ___ default (...) bukan fungsi
Jawaban untuk posting ini menyarankan untuk menghapus () dari setelah auth. Ketika saya mencoba itu, saya mendapatkan kesalahan yang mengatakan:
TypeError: Tidak dapat membaca properti 'onAuthStateChanged' dari undefined
Namun posting ini menyarankan masalah dengan cara firebase diimpor dalam file auth.
Saya telah mengimpor sebagai: impor Firebase dari "../firebase";
Firebase adalah nama kelas.
Video yang direkomendasikan Tristan adalah latar belakang yang membantu, tetapi saya saat ini ada di episode 9 dan masih belum menemukan bagian yang seharusnya membantu menyelesaikan masalah ini. Adakah yang tahu di mana menemukannya?
PERIKSA BERIKUTNYA Berikutnya - dan mencoba menyelesaikan masalah konteks saja - Saya telah mengimpor kedua createContext dan useContext dan mencoba menggunakannya seperti yang ditunjukkan dalam dokumentasi ini.
Saya tidak bisa menerima kesalahan yang mengatakan:
Kesalahan: Panggilan kait tidak valid. Kait hanya dapat disebut bagian dalam tubuh komponen fungsi. Ini bisa terjadi karena salah satu alasan berikut: ...
Saya telah melalui saran-saran dalam tautan ini untuk mencoba dan memecahkan masalah ini dan tidak dapat mengetahuinya. Saya tidak memiliki masalah yang ditunjukkan dalam panduan pemecahan masalah ini.
Saat ini - pernyataan konteks terlihat sebagai berikut:
import React, { useContext } from 'react';
import Firebase from "../../firebase";
export const FirebaseContext = React.createContext();
export const useFirebase = useContext(FirebaseContext);
export const FirebaseProvider = props => (
<FirebaseContext.Provider value={new Firebase()}>
{props.children}
</FirebaseContext.Provider>
);
Saya menghabiskan waktu menggunakan kursus ini untuk mencoba dan mencari tahu konteks dan elemen kait untuk masalah ini - setelah menontonnya - satu-satunya aspek untuk solusi yang diusulkan oleh Tristan di bawah ini adalah bahwa metode createContext tidak dipanggil dengan benar dalam posnya. itu harus "React.createContext" tetapi masih belum bisa menyelesaikan masalah.
Saya masih terjebak.
Adakah yang bisa melihat apa yang salah di sini?
export
ke export const FirebaseContext
?