FirebaseConfig.js
// Import the functions you need from the SDKs you need
import { initializeApp } from "firebase/app";
import { getAnalytics } from "firebase/analytics";
import { getAuth } from "firebase/auth";
// TODO: Add SDKs for Firebase products that you want to use
// https://firebase.google.com/docs/web/setup#available-libraries
// Your web app's Firebase configuration
// For Firebase JS SDK v7.20.0 and later, measurementId is optional
const firebaseConfig = {
apiKey: process.env.REACT_APP_FIREBASE_API_KEY,
authDomain: process.env.REACT_APP_FIREBASE_AUTH_DOMAIN,
databaseURL: process.env.REACT_APP_FIREBASE_DATABASE_URL,
projectId: process.env.REACT_APP_FIREBASE_PROJECT_ID,
storageBucket: process.env.REACT_APP_FIREBASE_STORAGE_BUCKET,
messagingSenderId: process.env.REACT_APP_FIREBASE_MESSAGING_SENDER_ID,
appId: process.env.REACT_APP_FIREBASE_APP_ID,
measurementId: process.env.REACT_APP_FIREBASE_MEASUREMENT_ID,
};
// Initialize Firebase
const app = initializeApp(firebaseConfig);
export const analytics = getAnalytics(app);
export const auth = getAuth(app);
export default app;
AuthContext.js
import { createContext, useContext, useEffect, useState } from "react";
import {
signInWithEmailAndPassword,
signOut,
onAuthStateChanged,
} from "firebase/auth";
import { auth } from "../firebaseConfig";
const AuthContext = createContext();
export const AuthContextProvider = ({ children }) => {
const [user, setUser] = useState({});
const logIn = (email, password) => {
return signInWithEmailAndPassword(auth, email, password);
};
const logOut = () => {
return signOut(auth);
};
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
console.info(currentUser);
setUser(currentUser);
});
return () => {
unsubscribe();
};
}, []);
return (
<AuthContext.Provider value = {{ user, logIn, logOut }}>
{children}
</AuthContext.Provider>
);
};
export const UserAuth = () => {
return useContext(AuthContext);
};
Login.jsx (здесь появляется ошибка)
import React, { useState } from "react";
import { Link, useNavigate } from "react-router-dom";
import { UserAuth } from "../context/AuthContext";
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const navigate = useNavigate();
const { logIn } = UserAuth() | {};
const handleSubmit = async (e) => {
e.preventDefault();
setError("");
try {
await logIn(email, password);
navigate("/account");
} catch (e) {
setError(e.message); // <--- This is the line where the error happens
console.info(e.message);
}
};
return (
<div className = "max-w-[600px] mx-auto my-16 p-4">
<div>
<h1 className = "text-2xl font-bold py-2">Login to your Account</h1>
</div>
<form onSubmit = {handleSubmit}>
<div className = "flex flex-col py-2">
<label className = "py-2 font-medium">Email Address</label>
<input
input
onChange = {(e) => setEmail(e.target.value)}
className = "border p-2"
type = "email"
/>
</div>
<div className = "flex flex-col py-2">
<label className = "py-2 font-medium">Password</label>
<input
onChange = {(e) => setPassword(e.target.value)}
className = "border p-2"
type = "password"
/>
</div>
<button className = "border border-blue-500 bg-blue-600 hover:bg-blue-500 w-full p-4 my-12 text-white">
Log In
</button>
</form>
</div>
);
};
export default Login;
пакет.json
{
"name": "sa_react_firebase_database",
"version": "0.1.0",
"private": true,
"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"dotenv": "^16.4.5",
"firebase": "^10.12.2",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-router-dom": "^6.23.1",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"autoprefixer": "^10.4.19",
"postcss": "^8.4.38",
"tailwindcss": "^3.4.4"
}
}
Я использую React JS и Firebase Auth, чтобы попытаться создать простую систему аутентификации электронной почты, следуя видеоруководству здесь:
https://thewikihow.com/video_x62aBvnRCKw?si=YGSjcsdjz5Zsb6Y-
Однако я получаю сообщение об ошибке: «logIn не является функцией», что является ошибкой перехвата в handleSubmit в Login.jsx. Я попытался клонировать репозиторий из GitHub загрузчика видео, и их код работает нормально, несмотря на отсутствие логических различий в handleSubmit, поэтому я подозреваю, что проблема в другом.
Перед отправкой я просматривал похожие сообщения, но обнаружил, что ответы были либо расплывчатыми, либо не могли ответить на вопрос, заданный в этих сообщениях.
Надеюсь, мы сможем получить здесь некоторые конкретные ответы, чтобы будущим людям, которые будут использовать Google по этой проблеме, было легче настроить систему аутентификации Firebase.
Обновлено: Спасибо за ответ, проблема решена! Сначала я позволил «logIn» вернуть неопределенное значение, чтобы деструктуризация не завершилась неудачей, но это заставило React думать, что это не функция. Обертывание App.js в «AuthContextProvider» и последующее удаление неопределенного значения из «logIn» устранило проблему!



![Безумие обратных вызовов в javascript [JS]](https://i.imgur.com/WsjO6zJb.png)


Эта ошибка обычно возникает по одной из следующих причин:
Функция входа в систему предоставлена неправильно или недоступна из AuthContext. Поставщик AuthContext не оборачивает компонент входа в систему, поэтому компонент входа не имеет доступа к функции входа в систему. При использовании функции входа в систему может возникнуть опечатка или проблема с синтаксисом.
Пошаговое решение
AuthContextProvider должен охватывать компоненты, которым необходим доступ к функции входа в систему. Обычно вы помещаете все приложение или, по крайней мере, компоненты, требующие аутентификации, в AuthContextProvider.
Пример в App.js:
import React from 'react';
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import { AuthContextProvider } from './context/AuthContext';
import Login from './components/Login';
import Account from './components/Account'; // Example account page
function App() {
return (
<AuthContextProvider>
<Router>
<Routes>
<Route path = "/login" element = {<Login />} />
<Route path = "/account" element = {<Account />} /> {/* Example route */}
</Routes>
</Router>
</AuthContextProvider>
);
}
export default App;
В этой настройке AuthContextProvider оборачивает маршрутизатор, гарантируя, что все маршруты, включая вход в систему, имеют доступ к контексту.
Убедитесь, что вы правильно используете перехватчик UserAuth для доступа к функции входа в систему из контекста. {logIn} = UserAuth() || {} гарантирует, что даже если UserAuth вернет неопределенное значение, деструктуризация не завершится неудачей.
Пример в Login.jsx:
import React, { useState } from 'react';
import { Link, useNavigate } from 'react-router-dom';
import { UserAuth } from '../context/AuthContext';
const Login = () => {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const navigate = useNavigate();
const { logIn } = UserAuth() || {}; // Ensures logIn is safely destructured
const handleSubmit = async (e) => {
e.preventDefault();
setError("");
try {
await logIn(email, password);
navigate("/account");
} catch (e) {
setError(e.message);
console.info(e.message);
}
};
return (
<div className = "max-w-[600px] mx-auto my-16 p-4">
<div>
<h1 className = "text-2xl font-bold py-2">Login to your Account</h1>
</div>
<form onSubmit = {handleSubmit}>
<div className = "flex flex-col py-2">
<label className = "py-2 font-medium">Email Address</label>
<input
onChange = {(e) => setEmail(e.target.value)}
className = "border p-2"
type = "email"
/>
</div>
<div className = "flex flex-col py-2">
<label className = "py-2 font-medium">Password</label>
<input
onChange = {(e) => setPassword(e.target.value)}
className = "border p-2"
type = "password"
/>
</div>
<button className = "border border-blue-500 bg-blue-600 hover:bg-blue-500 w-full p-4 my-12 text-white">
Log In
</button>
</form>
</div>
);
};
export default Login;
Убедитесь, что AuthContext и функции, представленные в нем (logIn и logOut), правильно определены и не исключены по ошибке. Также убедитесь, что аутентификация правильно импортирована из firebaseConfig.js.
Пример AuthContext.js:
import { createContext, useContext, useEffect, useState } from "react";
import {
signInWithEmailAndPassword,
signOut,
onAuthStateChanged,
} from "firebase/auth";
import { auth } from "../firebaseConfig";
const AuthContext = createContext();
export const AuthContextProvider = ({ children }) => {
const [user, setUser] = useState({});
const logIn = (email, password) => {
return signInWithEmailAndPassword(auth, email, password);
};
const logOut = () => {
return signOut(auth);
};
useEffect(() => {
const unsubscribe = onAuthStateChanged(auth, (currentUser) => {
setUser(currentUser);
});
return () => {
unsubscribe();
};
}, []);
return (
<AuthContext.Provider value = {{ user, logIn, logOut }}>
{children}
</AuthContext.Provider>
);
};
export const UserAuth = () => {
return useContext(AuthContext);
};
Я надеюсь, что это помогает
В. App.js, я оборачиваю AuthProvider, который является контекстом... вокруг всей маршрутизации.
const App = () => {
const routing = useRoutes(Themeroutes);
// Warp with <AuthProvider> to make Context works
return (
<AuthProvider>
<div className = "dark">{routing}</div>
</AuthProvider>
);
};
Этот AuthProvider взят из AuthProvider.js.
const AuthProvider = ({ children }) => { xx
return (
<AuthContext.Provider
value = {{
createUser,
user,
loginUser,
logOut,
loading,
apartmentFromUser,
roleFromUser,
nameFromUser,
}}
>
{children}
</AuthContext.Provider>
export default AuthProvider;
Проблема решена, спасибо! Комбинация Решения 1+2 была тем ответом, который я искал. Сначала я позволил «logIn» вернуть неопределенное значение, чтобы деструктуризация не завершилась неудачей, но это заставило React думать, что это не функция. Обертывание App.js в <AuthContextProvider> и последующее удаление неопределенного значения из «logIn» устранило проблему! Решение 3 ни на что не повлияло, так как я тщательно проверил отсутствие орфографических ошибок.