Я пытаюсь понять, как использовать прослушиватель Firebase, чтобы данные облачного пожарного хранилища обновлялись с помощью обновлений активных перехватчиков.
Изначально я сделал это, используя компонент класса с функцией componentDidMount для получения данных о хранилище.
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,
});
}
Это ломается при обновлении страницы, поэтому я пытаюсь выяснить, как переместите слушателя, чтобы реагировать на ловушки.
Я установил инструмент response-firebase-hooks - хотя я не могу понять, как прочитать инструкции, чтобы заставить его работать .
У меня есть функциональный компонент следующим образом:
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);
Этот компонент упакован в оболочку authUser на уровне маршрута следующим образом:
<Route path={ROUTES.DASHBOARD2} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard2 authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
У меня есть файл firebase. js, который подключается к firestore следующим образом:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
/* helpers */
this.fieldValue = app.firestore.FieldValue;
/* Firebase APIs */
this.auth = app.auth();
this.db = app.firestore();
}
Он также определяет слушателя, который будет знать, когда изменяется authUser:
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;
}
});
};
Затем, в моей firebase У меня есть контекстная настройка:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase';
export default Firebase;
export { FirebaseContext, withFirebase };
Контекст настраивается в оболочке withFirebase следующим образом:
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;
Затем в моем withAuthentication HO C у меня есть поставщик контекста как :
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;
В настоящее время - когда я пытаюсь Я получаю сообщение об ошибке в компоненте Dashboard2, которое гласит:
Firebase 'не определено
Я попытался использовать нижний регистр Firebase и получил ту же ошибку.
Я также пробовал firebase.firestore и Firebase.firestore. Я получаю ту же ошибку.
Мне интересно, не могу ли я использовать свой HO C с функциональным компонентом?
Я видел это демонстрационное приложение и это сообщение в блоге .
Следуя совету в блоге, я создал новый firebase / contextReader.jsx с:
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
}
Затем я пытаюсь обернуть мой App.jsx в этот читатель с помощью:
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} />
Когда я пытаюсь это сделать, я получаю сообщение об ошибке:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2 __. Default.auth не является функцией
Я видел это сообщение имеет дело с этой ошибкой и попытался удалить и переустановить пряжу. Это не имеет значения.
Когда я смотрю на демонстрационное приложение , оно предлагает создать контекст с использованием метода 'interface'. Я не вижу, откуда это исходит - я не могу найти ссылку, чтобы объяснить это в документации.
Я не могу понять смысл инструкций, кроме как попробовать то, что я сделал, чтобы подключить this in.
Я видел этот пост , который пытается прослушать firestore без использования активных-firebase-hooks. Ответы указывают на попытку выяснить, как использовать этот инструмент.
Я прочитал это превосходное объяснение , в котором рассказывается, как перейти от HOC к хукам. Я застрял с тем, как интегрировать слушатель Firebase.
Я видел этот пост , который предоставляет полезный пример того, как думать об этом. Не уверен, стоит ли мне пытаться сделать это в компоненте authListenerDidMount - или в компоненте Dashboard, который пытается его использовать.
СЛЕДУЮЩАЯ ПОПЫТКА Я нашел этот пост , который пытается решить ту же проблему.
Когда я пытаюсь реализовать решение, предлагаемое Шубхамом Кхатри, я настраивал конфигурацию firebase следующим образом:
Поставщик контекста с: import React, {useContext} из 'Reaction'; импортировать Firebase из '../../firebase';
const FirebaseContext = React.createContext();
export const FirebaseProvider = (props) => (
<FirebaseContext.Provider value={new Firebase()}>
{props.children}
</FirebaseContext.Provider>
);
Хук контекста тогда имеет:
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;
Затем в индексе. js Я обертываю приложение в провайдер как:
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();
Затем, когда я пытаюсь использовать слушатель в компоненте, который у меня есть:
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;
И я пытаюсь использовать его как маршрут без компонентов или auth wrapper:
<Route path={ROUTES.DASHBOARD2} component={Dashboard2} />
Когда я пытаюсь это сделать, я получаю сообщение об ошибке:
Попытка ошибки импорта: «FirebaseContext» не экспортируется из «../Firebase/». ContextHookProvider '.
Это сообщение об ошибке имеет смысл, потому что ContextHookProvider не экспортирует FirebaseContext - он экспортирует FirebaseProvider - но если я не пытаюсь импортировать его в Dashboard2 - тогда я не могу получить к нему доступ в функции, которая пытается его использовать.
Одним из побочных эффектов этой попытки является то, что мой метод регистрации больше не работает. Теперь генерируется сообщение об ошибке:
TypeError: Невозможно прочитать свойство 'doCreateUserWithEmailAndPassword' со значением null
Я решу эту проблему позже, но должна быть способ выяснить, как использовать реакцию с firebase, которая не включает месяцы этого l oop через миллионы путей, которые не работают, чтобы получить базовую c настройку аутентификации. Есть ли стартовый набор для firebase (firestore), который работает с реактивными крючками?
Следующая попытка Я пытался следовать подходу в этом курсе udemy - но это только работает для генерации ввода формы - нет слушателя, который бы разбирал маршруты для настройки с аутентифицированным пользователем.
Я пытался следовать подходу в этом руководстве по YouTube - которое имеет это репо для работы с. Он показывает, как использовать хуки, но не как использовать контекст.
СЛЕДУЮЩАЯ ПОПЫТКА Я нашел это репозиторий , который, кажется, имеет хорошо продуманный подход к использованию хуков с пожарным. Тем не менее, я не могу понять код.
Я клонировал это - и попытался добавить все файлы publi c, а затем, когда я его запустил - я не могу заставить код работать. Я не уверен, чего не хватает в инструкциях о том, как заставить это работать, чтобы увидеть, есть ли уроки в коде, которые могут помочь решить эту проблему.
СЛЕДУЮЩАЯ ПОПЫТКА
Я купил шаблон divjoy, который объявлен как установка для firebase (это не установка для firestore в случае, если кто-то еще рассматривает это как вариант).
Этот шаблон предлагает аутентификацию Оболочка, которая инициализирует конфигурацию приложения - но только для методов auth - поэтому ее необходимо реструктурировать, чтобы позволить другому провайдеру контекста для firestore. Когда вы запутываетесь в этом процессе и используете процесс, показанный в этом посте , то остается ошибка в следующем обратном вызове:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Он не знает, что такое Firebase. Это потому, что он определен в поставщике контекста firebase, который импортируется и определяется (в функции useProvideAuth ()) как:
const firebase = useContext(FirebaseContext)
Без шансов на обратный вызов, ошибка говорит:
React Hook useEffect отсутствует зависимость: 'firebase'. Либо включите его, либо удалите массив зависимостей
Или, если я попытаюсь добавить это const в обратный вызов, я получу сообщение об ошибке:
React Hook "useContext "не может быть вызвано внутри обратного вызова. React Hooks должны вызываться в компоненте функции React или в пользовательской функции React Hook
СЛЕДУЮЩАЯ ПОПЫТКА
Я сократил файл конфигурации Firebase до простой конфигурации переменные (я напишу помощники в провайдерах контекста для каждого контекста, который я хочу использовать).
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;
Затем у меня будет провайдер контекста аутентификации следующим образом:
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];
};
Я также сделал провайдер контекста firebase выглядит следующим образом:
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>
)
}
Затем в index. js Я обертываю приложение в провайдере firebase
ReactDom.render(
<FirebaseProvider>
<App />
</FirebaseProvider>,
document.getElementById("root"));
serviceWorker.unregister();
и в моем списке маршрутов я завернул соответствующие маршруты в поставщике аутентификации:
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;
В этой конкретной попытке я возвращаюсь к проблеме, отмеченной ранее с этой ошибкой:
TypeError: _firebase__WEBPACK_IMPORTED_MODULE_2 __. default. auth не является функцией
Она указывает на эту строку поставщика аутентификации как создающую проблему:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Я попытался использовать заглавную букву F в Firebase, и она генерирует то же самое Эрро т.
Когда я пользуюсь советом Тристана, я удаляю все эти вещи и пытаюсь определить свой метод отказа от подписки как метод отсутствия доступа (я не знаю, почему он не использует язык Firebase - но если его подход сработал, я ' буду стараться выяснить почему). Когда я пытаюсь использовать его решение, появляется сообщение об ошибке:
TypeError: _util_contexts_Firebase__WEBPACK_IMPORTED_MODULE_8 ___ default (...) не является функцией
Ответ это post предлагает удалить () после auth. Когда я пытаюсь это сделать, я получаю сообщение об ошибке:
TypeError: Невозможно прочитать свойство 'onAuthStateChanged' из неопределенного
Однако этот пост предлагает проблема с тем, как firebase импортируется в файл аутентификации.
У меня он импортирован как: импорт Firebase из "../firebase";
Firebase - это имя класса.
Видео, рекомендованные Тристаном, являются полезным фоном, но я в настоящее время нахожусь в эпизоде 9 и все еще не нашел ту часть, которая должна помочь решить эту проблему. Кто-нибудь знает, где это найти?
СЛЕДУЮЩАЯ ПОПЫТКА Далее - и пытаясь решить только проблему контекста - я импортировал оба createContext и useContext и попытался использовать их, как показано в этой документации .
Я не могу передать ошибку, которая говорит:
Ошибка: недопустимый вызов ловушки. Хуки могут быть вызваны только внутри тела компонента функции. Это может произойти по одной из следующих причин: ...
Я прошел через предложения в по этой ссылке , чтобы попытаться решить эту проблему, и не могу ее решить. У меня нет проблем, показанных в этом руководстве по устранению неполадок.
В настоящее время - контекстное утверждение выглядит следующим образом:
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>
);
Я потратил время, используя этот курс udemy чтобы попытаться выяснить контекст и подключить элемент к этой проблеме - после просмотра - единственным аспектом решения, предложенного Тристаном ниже, является то, что метод createContext не вызывается правильно в его посте. это должен быть «React.createContext», но он все еще не подходит для решения проблемы.
Я все еще застрял.
Может кто-нибудь увидеть, что здесь не так?