React - why useContext returns undefined?
Take a look at these three components. Can some explain why Login component can't see the loginUser method from the authenticationService?
Everything seems right: passing context, imports and yet it returns undefined.
1. App component - in which I created AuthenticationContext and passed it to the Container using Provider.
import React, { useState, createContext } from 'react';
import Login from './Components/Login';
import Container from './Components/Container';
export const AuthenticationContext = createContext();
const App = () => {
// ...
const authenticationService = {
loginUser: (user) => {
setUser(user);
return true;
},
// ...
};
return (
<div>
<AuthenticationContext.Provider value={authenticationService}>
// ...
<Container />
</AuthenticationContext.Provider>
</div>
);
};
export default App;
2. Container component - in which I render Login component.
import React from 'react';
import Login from './Login';
const Container = () => {
return (
<div className="container" style={containerStyle}>
<Login />
</div>
);
};
export default Container;
3. Login component - here I want to use loginUser from App's authenticationService but it's undefined.
import React from 'react';
import { AuthenticationContext } from '../App';
// ...
const Login = () => {
const authenticationService = React.useContext(AuthenticationContext);
// ...
const handleLogin = () => {
if ((usernameRef.current.value = 'root123215' && passwordRef.current.value === 'root123215')) {
authenticationService.loginUser('root');
console.log('successful login');
} else {
console.log('login failed');
}
};
return (
<form onSubmit={handleLogin} style={loginStyle}>
<div>
<label>Username: </label>
<input type="text" ref={usernameRef} />
</div>
<div>
<label>Password: </label>
<input type="password" ref={passwordRef} />
</div>
<button type="submit">Login</button>
</form>
);
};
export default Login;
Look at your case, simple steps:
- App.js imports
Loginfrom'./Components/Login' - Login.js imports
AuthenticationContextfrom'../App' AuthenticationContextis created in App.js with:
export const AuthenticationContext = createContext();
//AuthenticationContextdoesn't exist in step 2 yet
Summary:
App imports Login and inside Login App is imported again - keep contexts in separated files.
Quick solution:
- put context into a separate file
Sometimes importing a lot of files creates a cycle that leads to errors.
When I put context from the App into a separate file - contexts.js (which is a good practice) it worked.