Tôi đang cố gắng tìm ra cách sử dụng trình nghe Firebase để dữ liệu của đám mây được làm mới với các cập nhật móc phản ứng.
Ban đầu, tôi đã thực hiện điều này bằng cách sử dụng một thành phần lớp với hàm thành phầnDidMount để lấy dữ liệu đầu tiên.
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,
});
}
Điều đó bị phá vỡ khi trang cập nhật, vì vậy tôi đang cố gắng tìm ra cách di chuyển người nghe để phản ứng móc.
Tôi đã cài đặt công cụ hook-firebase-hook - mặc dù tôi không thể tìm ra cách đọc hướng dẫn để có thể làm cho nó hoạt động.
Tôi có một thành phần chức năng như sau:
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);
Thành phần này được bọc trong một trình bao bọc authUser ở cấp tuyến đường như sau:
<Route path={ROUTES.DASHBOARD2} render={props => (
<AuthUserContext.Consumer>
{ authUser => (
<Dashboard2 authUser={authUser} {...props} />
)}
</AuthUserContext.Consumer>
)} />
Tôi có một tệp firebase.js, cắm vào Firestore như sau:
class Firebase {
constructor() {
app.initializeApp(config).firestore();
/* helpers */
this.fieldValue = app.firestore.FieldValue;
/* Firebase APIs */
this.auth = app.auth();
this.db = app.firestore();
}
Nó cũng định nghĩa một người nghe để biết khi nào authUser thay đổi:
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;
}
});
};
Sau đó, trong thiết lập bối cảnh firebase của tôi, tôi có:
import FirebaseContext, { withFirebase } from './Context';
import Firebase from '../../firebase';
export default Firebase;
export { FirebaseContext, withFirebase };
Bối cảnh được thiết lập trong trình bao bọc withFirebase như sau:
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;
Sau đó, trong HOCentent HOC của tôi, tôi có một nhà cung cấp ngữ cảnh như:
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;
Hiện tại - khi tôi thử điều này, tôi gặp lỗi trong thành phần Dashboard2 có nội dung:
Firebase 'không được xác định
Tôi đã thử firebase chữ thường và nhận được cùng một lỗi.
Tôi cũng đã thử firebase.firestore và Firebase.firestore. Tôi nhận được lỗi tương tự.
Tôi tự hỏi nếu tôi không thể sử dụng HOC của tôi với một thành phần chức năng?
Tôi đã thấy ứng dụng demo này và bài đăng trên blog này .
Theo lời khuyên trong blog, tôi đã tạo một firebase / contextReader.jsx mới với:
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
}
Sau đó, tôi cố gắng bọc App.jsx của mình trong trình đọc đó bằng:
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} />
Khi tôi thử điều này, tôi nhận được một lỗi cho biết:
LoạiError: _firebase__weBPACK_IMPORTED_MODULE_2 __. Default.auth không phải là một chức năng
Tôi đã thấy bài này xử lý lỗi đó và đã thử gỡ cài đặt và cài đặt lại sợi. Nó không có Gì Thay đổi.
Khi tôi nhìn vào ứng dụng demo , nó gợi ý rằng bối cảnh nên được tạo bằng phương pháp 'giao diện'. Tôi không thể thấy điều này đến từ đâu - tôi không thể tìm thấy tài liệu tham khảo để giải thích nó trong tài liệu.
Tôi không thể hiểu được các hướng dẫn ngoài việc thử những gì tôi đã làm để cắm cái này vào.
Tôi đã thấy bài đăng này cố gắng lắng nghe Firestore mà không sử dụng hook-firebase-hook. Các câu trả lời quay trở lại để cố gắng tìm ra cách sử dụng công cụ này.
Tôi đã đọc lời giải thích tuyệt vời này trong đó làm thế nào để chuyển từ HOC sang hook. Tôi bị mắc kẹt với cách tích hợp trình nghe firebase.
Tôi đã thấy bài đăng này cung cấp một ví dụ hữu ích cho cách suy nghĩ về việc này. Không chắc chắn nếu tôi nên cố gắng làm điều này trong thành phần authListenerDidMount - hoặc trong thành phần Bảng điều khiển đang cố gắng sử dụng nó.
ATTEMPT TIẾP THEO Tôi tìm thấy bài đăng này , đang cố gắng giải quyết vấn đề tương tự.
Khi tôi cố gắng thực hiện giải pháp được cung cấp bởi Shubham Khatri, tôi đã thiết lập cấu hình firebase như sau:
Nhà cung cấp ngữ cảnh có: nhập React, {useContext} từ 'Reac'; nhập Firebase từ '../../firebase';
const FirebaseContext = React.createContext();
export const FirebaseProvider = (props) => (
<FirebaseContext.Provider value={new Firebase()}>
{props.children}
</FirebaseContext.Provider>
);
Các hook bối cảnh sau đó có:
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;
Sau đó, trong tệp index.js, tôi gói Ứng dụng trong nhà cung cấp là:
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();
Sau đó, khi tôi cố gắng sử dụng trình nghe trong thành phần tôi có:
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;
Và tôi cố gắng sử dụng nó như một tuyến đường không có thành phần hoặc trình bao bọc auth:
<Route path={ROUTES.DASHBOARD2} component={Dashboard2} />
Khi tôi thử điều này, tôi nhận được một lỗi cho biết:
Lỗi nhập đã cố gắng: 'FirebaseContext' không được xuất từ '../Firebase/ContextHookProvider'.
Thông báo lỗi đó có ý nghĩa, bởi vì ContextHookProvider không xuất FirebaseContext - nó xuất FirebaseProvider - nhưng nếu tôi không thử nhập cái này trong Dashboard2 - thì tôi không thể truy cập nó trong chức năng cố gắng sử dụng nó.
Một tác dụng phụ của nỗ lực này là phương thức đăng ký của tôi không còn hoạt động. Bây giờ nó tạo ra một thông báo lỗi cho biết:
LoạiError: Không thể đọc thuộc tính 'doCreateUserWithEmailAndPassword' của null
Tôi sẽ giải quyết vấn đề này sau - nhưng phải có cách tìm ra cách sử dụng phản ứng với căn cứ hỏa lực không liên quan đến nhiều tháng của vòng lặp này thông qua hàng triệu con đường không hoạt động để có được thiết lập xác thực cơ bản. Có một bộ khởi động cho firebase (Firestore) hoạt động với móc phản ứng không?
Nỗ lực tiếp theo tôi đã cố gắng làm theo cách tiếp cận trong khóa học udemy này - nhưng nó chỉ hoạt động để tạo đầu vào biểu mẫu - không có người nghe để đặt xung quanh các tuyến đường để điều chỉnh với người dùng được xác thực.
Tôi đã cố gắng làm theo cách tiếp cận trong hướng dẫn youtube này - có repo này để làm việc. Nó chỉ ra cách sử dụng hook, nhưng không sử dụng ngữ cảnh.
ATTEMPT TIẾP THEO Tôi tìm thấy repo này dường như có một cách tiếp cận được cân nhắc kỹ lưỡng khi sử dụng móc với Firestore. Tuy nhiên, tôi không thể hiểu được mã.
Tôi đã nhân bản cái này - và cố gắng thêm tất cả các tệp công khai và sau đó khi tôi chạy nó - tôi thực sự không thể lấy mã để hoạt động. Tôi không chắc những gì còn thiếu trong hướng dẫn về cách chạy cái này để xem liệu có bài học nào trong mã có thể giúp giải quyết vấn đề này không.
TIẾP THEO TIẾP THEO
Tôi đã mua mẫu divjoy, được quảng cáo là đang được thiết lập cho căn cứ hỏa lực (nó không được thiết lập cho Firestore trong trường hợp bất kỳ ai khác đang coi đây là một tùy chọn).
Mẫu đó đề xuất một trình bao bọc xác thực khởi tạo cấu hình của ứng dụng - nhưng chỉ dành cho các phương thức xác thực - vì vậy nó cần phải được cấu trúc lại để cho phép nhà cung cấp ngữ cảnh khác thực hiện. Khi bạn thực hiện quá trình đó và sử dụng quy trình được hiển thị trong bài đăng này , những gì còn lại là một lỗi trong cuộc gọi lại sau:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Nó không biết căn cứ hỏa lực là gì. Đó là bởi vì nó được xác định trong nhà cung cấp bối cảnh firebase được nhập và định nghĩa (trong hàm useProvideAuth ()) là:
const firebase = useContext(FirebaseContext)
Không có cơ hội gọi lại, lỗi nói:
Sử dụng React HookEffect có một phụ thuộc bị thiếu: 'firebase'. Bao gồm nó hoặc loại bỏ mảng phụ thuộc
Hoặc, nếu tôi thử và thêm const đó vào cuộc gọi lại, tôi sẽ gặp lỗi:
React Hook "useContext" không thể được gọi trong cuộc gọi lại. React Hook phải được gọi trong thành phần chức năng React hoặc chức năng React Hook tùy chỉnh
TIẾP THEO TIẾP THEO
Tôi đã giảm tập tin cấu hình firebase của mình xuống chỉ còn các biến cấu hình (tôi sẽ viết các trình trợ giúp trong các nhà cung cấp ngữ cảnh cho từng bối cảnh tôi muốn sử dụng).
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;
Sau đó tôi có một nhà cung cấp bối cảnh xác thực như sau:
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];
};
Tôi cũng đã thực hiện một nhà cung cấp bối cảnh firebase như sau:
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>
)
}
Sau đó, trong index.js tôi gói ứng dụng trong nhà cung cấp firebase
ReactDom.render(
<FirebaseProvider>
<App />
</FirebaseProvider>,
document.getElementById("root"));
serviceWorker.unregister();
và trong danh sách các tuyến đường của tôi, tôi đã gói các tuyến có liên quan trong nhà cung cấp xác thực:
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;
Trong nỗ lực cụ thể này, tôi trở lại vấn đề được gắn cờ trước đó với lỗi này:
LoạiError: _firebase__weBPACK_IMPORTED_MODULE_2 __. Default.auth không phải là một chức năng
Nó chỉ ra dòng này của nhà cung cấp xác thực khi tạo ra vấn đề:
useEffect(() => {
const unsubscribe = firebase.auth().onAuthStateChanged(user => {
if (user) {
setUser(user);
} else {
setUser(false);
}
});
Tôi đã thử sử dụng chữ F viết hoa trong Firebase và nó cũng tạo ra lỗi tương tự.
Khi tôi thử lời khuyên của Tristan, tôi loại bỏ tất cả những điều đó và thử và xác định phương thức hủy đăng ký của mình là phương pháp không niêm yết (tôi không biết tại sao anh ta không sử dụng ngôn ngữ firebase - nhưng nếu cách tiếp cận của anh ta hiệu quả, tôi sẽ cố gắng hơn để tìm hiểu tại sao). Khi tôi cố gắng sử dụng giải pháp của mình, thông báo lỗi cho biết:
LoạiError: _util_contexts_Firebase__weBPACK_IMPORTED_MODULE_8 ___ mặc định (...) không phải là một chức năng
Câu trả lời cho bài đăng này đề nghị xóa () khỏi sau auth. Khi tôi thử điều đó, tôi nhận được một lỗi cho biết:
LoạiError: Không thể đọc thuộc tính 'onAuthStateChanged' không xác định
Tuy nhiên bài đăng này cho thấy một vấn đề với cách nhập căn cứ hỏa lực trong tệp xác thực.
Tôi đã nhập nó dưới dạng: nhập Firebase từ "../firebase";
Firebase là tên của lớp.
Các video mà Tristan đề xuất là bối cảnh hữu ích, nhưng tôi hiện đang ở tập 9 và vẫn chưa tìm thấy phần nào được cho là giúp giải quyết vấn đề này. Có ai biết nơi để tìm thấy điều đó?
TIẾP THEO TIẾP THEO Tiếp theo - và chỉ cố gắng giải quyết vấn đề bối cảnh - Tôi đã nhập cả createdContext và useContext và cố gắng sử dụng chúng như trong tài liệu này.
Tôi không thể vượt qua một lỗi cho biết:
Lỗi: Cuộc gọi hook không hợp lệ. Móc chỉ có thể được gọi bên trong cơ thể của một thành phần chức năng. Điều này có thể xảy ra vì một trong những lý do sau: ...
Tôi đã thông qua các đề xuất trong liên kết này để thử và giải quyết vấn đề này và không thể tìm ra nó. Tôi không có bất kỳ vấn đề nào trong hướng dẫn chụp rắc rối này.
Hiện tại - tuyên bố bối cảnh trông như sau:
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>
);
Tôi đã dành thời gian sử dụng khóa học udemy này để thử và tìm ra bối cảnh và móc phần tử cho vấn đề này - sau khi xem nó - khía cạnh duy nhất cho giải pháp được Tristan đề xuất dưới đây là phương thức createContext không được gọi chính xác trong bài đăng của anh ấy. nó cần phải là "React.createContext" nhưng nó vẫn không thể giải quyết vấn đề.
Tôi vẫn bị mắc kẹt.
Bất cứ ai cũng có thể thấy những gì đã đi lạc ở đây?
export
vào export const FirebaseContext
?