Bulut firestore verileri tepki kanca güncellemeleri ile yenilenir, böylece bir Firebase dinleyici kullanmayı anlamaya çalışıyorum.
Başlangıçta, ben firestore veri almak için bir componentDidMount işlevi ile bir sınıf bileşeni kullanarak yaptı.
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,
});
}
Sayfa güncellendiğinde bu kesiliyor, bu yüzden kancaları tepki vermek için dinleyiciyi nasıl hareket ettireceğimizi anlamaya çalışıyorum.
Ben yüklemiş tepki-Firebase-kanca aracı - İşe onu elde edebilmek için talimatları okumak anlamaya olamaz rağmen.
Aşağıdaki gibi bir işlev bileşeni var:
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);
Bu bileşen, aşağıdaki gibi rota düzeyinde bir authUser sarmalayıcısına sarılır:
<Route path={ROUTES.DASHBOARD2} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard2 authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
Aşağıdaki gibi firestore içine takılan bir firebase.js dosyası var:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
/* helpers */
this.fieldValue = app.firestore.FieldValue;
/* Firebase APIs */
this.auth = app.auth();
this.db = app.firestore();
}
Ayrıca authUser öğesinin ne zaman değiştiğini bilmek için bir dinleyici tanımlar:
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;
}
});
};
Sonra benim firebase bağlam kurulumunda var:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase';
export default Firebase;
export { FirebaseContext, withFirebase };
Bağlam aşağıdaki gibi bir withFirebase paketinde kurulur:
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;
Daha sonra, withAuthentication HOC'de şu şekilde bir bağlam sağlayıcısı 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;
Şu anda - bunu denediğimde, Dashboard2 bileşeninde şöyle bir hata alıyorum:
Firebase 'tanımlanmadı
Küçük firebase denedim ve aynı hatayı aldım.
Ayrıca firebase.firestore ve Firebase.firestore'u denedim. Aynı hatayı alıyorum.
HOC'umu bir işlev bileşeniyle kullanıp kullanamayacağımı merak ediyorum.
Bu demo uygulamasını ve bu blog gönderisini gördüm .
Blogdaki önerileri takiben, aşağıdakilerle yeni bir firebase / contextReader.jsx yaptım:
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
}
Sonra App.jsx'imi şu okuyucuya sarmaya çalışıyorum:
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} />
Bunu denediğimde, şöyle bir hata alıyorum:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2 __. Default.auth bir işlev değil
Bu hatayla ilgili bu gönderiyi gördüm ve ipliği kaldırmayı ve yeniden yüklemeyi denedim. Fark yaratmıyor.
Demo uygulamasına baktığımda, bağlamın bir 'arayüz' yöntemi kullanılarak oluşturulması gerektiğini gösteriyor. Bunun nereden geldiğini göremiyorum - dokümantasyonda açıklamak için bir referans bulamıyorum.
Bunu takmak için ne yaptığımı denemek dışında talimatlar anlamıyorum.
Gördüğüm bu yazı girişimleri tepki-Firebase kancalarımız kullanmadan Firestore dinlemek için. Cevaplar bu aracın nasıl kullanılacağını anlamaya çalıştığına işaret ediyor.
HOC'lardan kancalara nasıl geçileceğine dair bu mükemmel açıklamayı okudum . Firebase dinleyicisini nasıl entegre edeceğime şaşırdım.
Bunu nasıl yapacağınızı düşünmek için yararlı bir örnek sağlayan bu gönderiyi gördüm . Bunu authListener componentDidMount - veya kullanmaya çalışan Dashboard bileşeninde yapmaya çalışıp çalışmadığımdan emin değilim.
SONRAKİ GİRİŞ Aynı sorunu çözmeye çalışan bu gönderiyi buldum .
Shubham Khatri tarafından sunulan çözümü uygulamaya çalıştığımda, firebase yapılandırmasını aşağıdaki gibi ayarladım:
Aşağıdakilere sahip bir bağlam sağlayıcısı: import React, 'tepki' den {useContext}; Firebase'i '../../firebase' den içe aktar;
const FirebaseContext = React.createContext();
export const FirebaseProvider = (props) => (
<FirebaseContext.Provider value={new Firebase()}>
{props.children}
</FirebaseContext.Provider>
);
Bağlam kancası daha sonra:
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;
Sonra index.js Ben App sağlayıcı sağlayıcı olarak sarın:
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();
Sonra, bileşende dinleyici kullanmaya çalıştığımda:
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;
Ve hiçbir bileşen veya yetkilendirme sarmalayıcı ile bir yol olarak kullanmaya çalışın:
<Route path={ROUTES.DASHBOARD2} component={Dashboard2} />
Bunu denediğimde, şöyle bir hata alıyorum:
İçe aktarma girişimi denendi: 'FirebaseContext', '../Firebase/ContextHookProvider' öğesinden dışa aktarılmaz.
ContextHookProvider FirebaseContext'i dışa aktarmadığından - FirebaseProvider'ı dışa aktardığından - ancak bunu Dashboard2'de içe aktarmaya çalışmazsam - kullanmaya çalıştığım işlevde erişemediğim için bu hata iletisi mantıklıdır.
Bu girişimin bir yan etkisi, kayıt yöntemimin artık çalışmamasıdır. Şimdi şöyle bir hata mesajı veriyor:
TypeError: null 'doCreateUserWithEmailAndPassword' özelliği okunamıyor
Bu sorunu daha sonra çözeceğim - ancak temel bir yetkilendirme ayarı elde etmek için çalışmayan milyonlarca yol boyunca bu döngünün aylarını içermeyen firebase ile reaksiyonun nasıl kullanılacağını anlamanın bir yolu olmalı. Tepki kancaları ile çalışan firebase (firestore) için bir başlangıç kiti var mı?
Bir sonraki girişim , bu udemy kursundaki yaklaşımı takip etmeye çalıştım - ancak sadece bir form girişi oluşturmak için çalışıyor - kimliği doğrulanmış kullanıcıyla uyum sağlamak için rotaların etrafına yerleştirilecek bir dinleyici yok.
Çalışmak için bu repo sahip bu youtube öğretici yaklaşım takip etmeye çalıştım . Kancaların nasıl kullanılacağını gösterir, ancak bağlamın nasıl kullanılacağını göstermez.
SONRAKİ ÇÖZÜM Firestore ile kanca kullanma konusunda iyi düşünülmüş bir yaklaşıma sahip gibi görünen bu repoyu buldum . Ancak, kodu anlamıyorum.
Bunu klonladım - ve tüm genel dosyaları eklemeye çalıştım ve sonra çalıştırdığımda - aslında kodu çalıştırmak için alamıyorum. Kodda bu sorunu çözmeye yardımcı olabilecek dersler olup olmadığını görmek için bu çalıştırmak için nasıl yönergeler eksik emin değilim.
SONRAKİ GİRİŞ
Firebase için kurulum olarak ilan edilen divjoy şablonunu satın aldım (başka bir seçenek olarak düşünüyorsa firestore için ayarlanmamıştır).
Bu şablon, uygulamanın yapılandırmasını başlatan bir kimlik doğrulama paketi önerir - ancak yalnızca kimlik doğrulama yöntemleri için - bu nedenle, Firestore için başka bir içerik sağlayıcısına izin vermek üzere yeniden yapılandırılması gerekir. Bu işlemle geçinip ve gösterilen işlemini kullandığınızda bu yazı , ne kaldı şu callback'inde bir hatadır:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Firebase'in ne olduğunu bilmiyor. Çünkü içe aktarılan ve (useProvideAuth () işlevinde) tanımlanmış olan firebase bağlam sağlayıcısında şu şekilde tanımlanır:
const firebase = useContext(FirebaseContext)
Geri arama şansı olmadan hata şöyle diyor:
React Hook useEffect'in bağımlılığı eksik: 'firebase'. Ya ekleyin ya da bağımlılık dizisini kaldırın
Veya, ben bu const geri aramaya eklemek denerseniz, bir hata mesajı alıyorum:
React Hook "useContext" bir geri arama içinde çağrılamaz. Reaksiyon Kancaları bir Reaksiyon işlevi bileşeninde veya özel bir Reaksiyon Kancası işlevinde çağrılmalıdır
SONRAKİ GİRİŞ
Firebase yapılandırma dosyamı yalnızca yapılandırma değişkenlerine indirdim (kullanmak istediğim her içerik için içerik sağlayıcılarına yardımcılar yazacağım).
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;
Sonra aşağıdaki gibi bir Auth içerik sağlayıcısı var:
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];
};
Ayrıca aşağıdaki gibi bir firebase içerik sağlayıcısı yaptım:
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>
)
}
Sonra, index.js'de uygulamayı firebase sağlayıcısına sararım
ReactDom.render(
<FirebaseProvider>
<App />
</FirebaseProvider>,
document.getElementById("root"));
serviceWorker.unregister();
ve güzergah listemde, kimlik doğrulaması sağlayıcısına ilgili güzergahları tamamladım:
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;
Bu özel denemede, bu hatayla daha önce işaretlenen soruna geri döndüm:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2 __. Default.auth bir işlev değil
Sorunu oluştururken kimlik doğrulama sağlayıcısının bu satırına işaret eder:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Firebase büyük harf F kullanmayı denedim ve aynı hatayı üretir.
Tristan'ın tavsiyelerini denediğimde, tüm bunları kaldırıyorum ve abonelikten çıkma yöntemimi liste dışı bir yöntem olarak tanımlamaya çalışıyorum (neden ateşbaz dilini kullanmadığını bilmiyorum - ama yaklaşımı işe yarasaysa daha çok denerdim nedenini bulmak için). Çözümünü kullanmaya çalıştığımda hata mesajı şöyle diyor:
TypeError: _util_contexts_Firebase__WEBPACK_IMPORTED_MODULE_8 ___ varsayılan (...) bir işlev değil
Cevabı bu yazı auth sonra gelen () çıkarmadan önerir. Bunu denediğimde, bir hata mesajı alıyorum:
TypeError: undefined öğesinin 'onAuthStateChanged' özelliği okunamıyor
Ancak bu yazı , ateş tabanının kimlik doğrulama dosyasına aktarılma biçimiyle ilgili bir sorun olduğunu gösterir.
Ben ithal var: "../firebase" ithal Firebase;
Firebase sınıfın adıdır.
Tristan'ın önerdiği videolar yararlı bir arka plan, ancak şu anda bölüm 9'dayım ve hala bu sorunu çözmeye yardımcı olması gereken kısmı bulamadım. Bunu nerede bulacağını bilen var mı?
SONRAKİ GİRİŞ Sonraki - ve sadece bağlam sorununu çözmeye çalışıyorum - Ben hem createContext hem de useContext ithal ve bu belgelerde gösterildiği gibi bunları kullanmaya çalıştım.
Bir hata iletisini geçemiyorum:
Hata: Geçersiz kanca çağrısı. Kancalar yalnızca bir işlev bileşeninin gövdesi içinde çağrılabilir. Bu, aşağıdaki nedenlerden biriyle olabilir: ...
Bu sorunu çözmek ve çözmek için bu bağlantıdaki önerilerden geçtim ve anlayamıyorum . Bu sorun giderme kılavuzunda gösterilen herhangi bir sorunum yok.
Şu anda - bağlam ifadesi aşağıdaki gibi görünüyor:
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>
);
Bu udemy dersini kullanarak bu problemin bağlamını ve kancalarını anlamaya çalışmak için zaman harcadım - onu izledikten sonra - aşağıda Tristan tarafından önerilen çözümün tek yönü, createContext yönteminin gönderisinde doğru şekilde çağrılmamasıdır. "React.createContext" olması gerekiyor, ancak yine de sorunu çözmeye yakın bir yere ulaşamıyor.
Hala sıkıştım.
Burada neyin ters gittiğini kimse görebiliyor mu?
export
için export const FirebaseContext
?