auth is not a function - reactjs

I'm trying to do a simple login form, and Firebase auth give me this error
TypeError: firebase__WEBPACK_IMPORTED_MODULE_1_["default"].auth is
not a function. (In
'firebase__WEBPACK_IMPORTED_MODULE_1_["default"].auth()',
'firebase__WEBPACK_IMPORTED_MODULE_1_["default"].auth' is undefined)
Somebody have the solution?
import React, {useEffect, useState} from "react"
import app from '../firebase'
export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [currentUser, setCurrentUser] = useState(null);
useEffect(() => {
app.auth().onAuthStateChanged(setCurrentUser);
}, []);
return (
<AuthContext.Provider value={{currentUser}}>
{children}
</AuthContext.Provider>
)
}

const useAuth = () => useContext(AuthContext);
export { useAuth, AuthProvider };
add these two lines at the end also

Related

I can't create context with typescript react

if I use .js instead of .tsx there is no problem. but when I use typescript, it shows this error "Expected 1 arguments, but got 0.". what am I missing ?
context.tsx
import { createContext, useContext} from "react";
const MainContext = createContext();
export {
MainContext,
useContext
}
Layout.tsx
const LayoutComponent = ({children}: any) => {
const [email, setEmail] = useState("");
const data = {
email,
setEmail
}
return (
<MainContext.Provider value={data}>
<Header />
{children}
</MainContext.Provider>
);
}
use default value
import { createContext, useContext} from "react";
const ctx = createContext({ someData: true })
export const useCtx = () => useContext(ctx)
createContext needs a default value
const MainContext = createContext({});

Cannot destructure custom hook inside Context: TypeError: Cannot destructure property '' of 'Object(...)(...)' as it is null

I'll receive the following error:
TypeError: Cannot destructure property 'isAuthenticated' of 'Object(...)(...)' as it is null. When I try to use a function from a custom hook inside my AuthContext.
I have a function written in a custom hook (useWeb3.ts), like:
import { useContext } from "react";
import { useLocation, useNavigate } from "react-router-dom";
import Web3 from "web3";
import { AuthContext } from "../context/AuthContext";
import { FormatPublicKey } from "./utils/FormatPublicKey";
const useWeb3 = () => {
const { isAuthenticated, setIsAuthenticated, web3, setWeb3, setUserInfo } = useContext(AuthContext);
const getCurrentProvider = () => {
let provider;
if (window.ethereum) {
provider = window.ethereum;
} else if (window.web3) {
provider = window.web3.currentProvider;
} else {
console.log("Non-Ethereum browser detected. You should consider trying MetaMask!");
}
return provider;
};
return {
getCurrentProvider,
};
};
export default useWeb3;
And I want to call this function (getCurrentProvider) inside my context file, like:
import { createContext, useState } from "react";
import useWeb3 from "../components/useWeb3";
import { UserInfoProps } from "../types/UserInfoProps";
export const AuthContext = createContext<any>(null);
export const AuthContextProvider = (props: any) => {
const initializeState = JSON.parse(localStorage.getItem("userAccount")!);
const [isAuthenticated, setIsAuthenticated] = useState<boolean>(false);
const [isAuthenticating, setIsAuthenticating] = useState<boolean>(false);
const [authError, setAuthError] = useState<string>("");
const [provider, setProvider] = useState(null);
const [web3, setWeb3] = useState(null);
const [userInfo, setUserInfo] = useState<UserInfoProps | null>(initializeState || null);
const { getCurrentProvider } = useWeb3();
const providerValue = {
isAuthenticated,
setIsAuthenticated,
isAuthenticating,
setIsAuthenticating,
authError,
setAuthError,
provider,
setProvider,
web3,
setWeb3,
userInfo,
setUserInfo
};
return (
<AuthContext.Provider value={providerValue}>
{props.children}
</AuthContext.Provider>
);
};
The AuthContext is wrapped around App inside my index, see:
const root = ReactDOM.createRoot(document.getElementById("root") as HTMLElement);
root.render(
<React.StrictMode>
<AuthContextProvider>
<App />
</AuthContextProvider>
</React.StrictMode>
);
I already read some similar problems and that was solved by changing some imports/exports. But somehow I still receive the error. The error does come up as soon as I call this line of code : const { getCurrentProvider } = useWeb3(); inside the AuthContext.tsx
Thanks in advance

Changing user's info in Context api using React useState Hooks

I am trying to use Context API to store the user's info after he is logged in, but the setAuth, when I try to set the data says that function "setAuth is not a function"
import { createContext, useState } from "react";
const AuthContext = createContext({});
export const AuthProvider = ({ children }) => {
const [auth, setAuth] = useState(null);
return (
<AuthContext.Provider value={(auth, setAuth)}>
{children}
</AuthContext.Provider>
);
};
export default AuthContext;
Login view
const { user, setAuth } = useContext(AuthContext);
//formik on submit function
onSubmit: (values) => {
setAuth(values); // setAuth is not a function
<AuthContext.Provider value={auth, setAuth}>
{children}
</AuthContext.Provider>
Remove the brackets.
Also, check if LoginView is inside AuthProvider

Invalid element type when using Context to pass down Auth details

I'm currently attempting to build an 'AuthContext' so I can use it in various screens and pass the data down.
I thought I'd built it right.. But when I try to call one of the functions in my Provider, it's throwing a component exception, stating 'element type is invalid: expected a string or a class/function but got undefined'.
Here is the context file:
import React, { useState, useContext } from 'react';
import { navigate } from '../navigationRef';
import { Magic } from '#magic-sdk/react-native';
const m = new Magic('api key');
export const AuthContext = React.createContext();
export const AuthProvider = ({ children }) => {
const [user, setUser] = useState([]);
const userSignedIn = async () => {
// Call Magic logged in
const loggedIn = await m.user.isLoggedIn();
// If user logged in, save details to user, and redirect to dashboard
if (loggedIn === true) {
const { issuer, email } = await m.user.getMetaData();
setUser([issuer, email])
navigate('authorisedFlow')
// If user not logged in, redirect to login flow
} else {
navigate('loginFlow')
}
};
const signIn = () => {
};
const signUp = () => {
};
const logOut = () => {
};
return (
<AuthContext.Provider value={{ user, userSignedIn, signIn, signUp, logOut }}>
{ children }
</AuthContext.Provider>
)
}
And here is the component which is attempting to use the context:
import React, { useContext, useEffect } from 'react';
import { View, StyleSheet, ActivityIndicator } from 'react-native';
import AuthContext from '../context/AuthContext';
const LoadingScreen = ({ navigation }) => {
const { userSignedIn } = useContext(AuthContext)
useEffect(() => {
userSignedIn()
}, [])
return (
<View style={styles.mainView}>
<ActivityIndicator style={styles.indicator} />
</View>
)
}
And finally, here is my app.js file (cut most of it out due to length, but wanted to show Provider):
import { Provider as AuthProvider } from './src/context/AuthContext';
const App = createAppContainer(switchNavigator)
export default () => {
return (
<AuthProvider>
<App />
</AuthProvider>
)
};
Can anyone see what's going wrong here?
You exported your AuthContext as a named-export ... but you're importing a default-export
import AuthContext from '../context/AuthContext'; // <--- Here
const LoadingScreen = ({ navigation }) => {};
Instead...
import { AuthContext} from '../context/AuthContext';
Same goes for this one as well...
import { Provider as AuthProvider } from './src/context/AuthContext';
Which should be
import { AuthContext: { Provider as AuthProvider } } from './src/context/AuthContext';
OR
import { AuthContext } from './src/context/AuthContext';
return (
<AuthContext.Provider>
<App />
</AuthContext.Provider>
)

Test component with context and react hook

I have a simple Dashboard component that relies on React context to manage auth. It contains a custom hook useAuth to extract the current user as well as the auth related functions: login, logout, etc.
This is the Context file: AuthContext.js:
import React, { createContext, useContext, useState, useEffect } from "react";
import { auth } from "../config/firebase";
const AuthContext = createContext();
export function useAuth() {
return useContext(AuthContext);
}
export function AuthProvider({ children }) {
const [currentUser, setCurrentUser] = useState();
const [loading, setLoading] = useState(true);
function signup(email, password) {
return auth.createUserWithEmailAndPassword(email, password);
}
function login(email, password) {
return auth.signInWithEmailAndPassword(email, password);
}
function logout() {
return auth.signOut();
}
useEffect(() => {
const unsubscribe = auth.onAuthStateChanged((user) => {
setCurrentUser(user);
setLoading(false);
});
return unsubscribe;
}, []);
const value = {
currentUser,
signup,
login,
logout,
};
return (
<AuthContext.Provider value={value}>
{!loading && children}
</AuthContext.Provider>
);
}
This is the Dashboard.js component:
import React, { useState } from "react";
import { useHistory } from "react-router-dom";
import { useAuth } from "../context/AuthContext";
export default function Dashboard() {
const { currentUser, logout } = useAuth();
const [error, setError] = useState("");
const history = useHistory();
const handleLogout = async () => {
setError("");
try {
await logout();
history.push("/login");
} catch (e) {
setError(e.message);
}
};
return (
<div>
{error && <p>{error}</p>}
<h1>This is the Dashboard</h1>
<h5>Email: {currentUser.email}</h5>
<button onClick={handleLogout} type="button">
Logout
</button>
</div>
);
}
As recommened by React Testing Library I have created a test-utils.js file:
import React, { createContext } from "react";
import { render } from "#testing-library/react";
import { BrowserRouter as Router } from "react-router-dom";
const AuthContext = createContext();
const currentUser = {
email: "abc#abc.com",
};
const signup = jest.fn();
const login = jest.fn();
const logout = jest.fn();
const AllTheProviders = ({ children }) => {
return (
<Router>
<AuthContext.Provider value={{ currentUser, signup, login, logout }}>
{children}
</AuthContext.Provider>
</Router>
);
};
const customRender = (ui, options) => {
render(ui, { wrapper: AllTheProviders, ...options });
};
export * from "#testing-library/react";
export { customRender as render };
However, when running Dashboard.test.js I get error
TypeError: Cannot destructure property 'currentUser' of '((cov_5mwatn2cf(...).s[0]++) , (0 , _AuthContext.useAuth)(...))' as it is undefined.
4 |
5 | export default function Dashboard() {
> 6 | const { currentUser, logout } = useAuth();
| ^
7 | const [error, setError] = useState("");
8 | const history = useHistory();
import React from "react";
import Dashboard from "./Dashboard";
import { act, render, screen } from "../config/test-utils-dva";
beforeEach(async () => {
await act(async () => {
render(<Dashboard />);
});
});
test("displays dashboard", () => {
expect(screen.getByText(/dashboard/i)).toBeInTheDocument();
});
I think it is because Dashboard component is trying to use useAuth from AuthContext.js, how can I force the rendered Dashboard component to use the mocked data that I am sending in the test-utils.jsfile?
Instead of creating a new context, use the AuthContext from context/AuthContext for <AuthContext.Provider>, as that's the context that the hook uses.
So, in AuthContext.js, export the context instance:
export const AuthContext = createContext();
Then, in your test-util.js file, instead of again calling createContext (which will create a completely separate context instance - the contexts are not the same even if they are stored in a variable with the same name!), just import the previously exported instance:
import { AuthContext } from "../context/AuthContext";
const AllTheProviders = ({ children }) => {
return (
<Router>
<AuthContext.Provider value={{ currentUser, signup, login, logout }}>
{children}
</AuthContext.Provider>
</Router>
);
};

Resources