'Failed prop type: The prop `setToken` is marked as required in `Login`, but its value is `undefined`
So, I'm new at React and I was making a WebApp using the API made by me that is full functional. I wanted to use token in sign in as the API is also prepared. Went to check a tutorial but it wont work because of the setToken. I have no idea if is because of the fetch or anything else.
This is the error that appears when loading the page:
Then when I click the sign in button will always appear me this:
import React, { useContext, useState } from 'react';
import {BrowserRouter as Router, Routes, Route} from 'react-router-dom';
import './App.css';
import ListGlucoseRecords from './screens/glucoseRecords/listGlucoseRecords';
import ListInsulineRecords from './screens/insulineRecords/listInsulineRecords';
import DashboardComp from './screens/dashboard/dashboardComp';
import ClientList from './screens/users/clientList';
import Login from './screens/login/Login';
import SignUp from './screens/signUp/SignUp';
function App() {
const [token, setToken] = useState([]);
if(!token) {
return <Login setToken={setToken} />
}
return (
<Router>
<Routes>
<Route path='/dashboard' element={<DashboardComp/>}/>
<Route path='/users' element={<ClientList/>}/>
<Route path='/glucose' element={<ListGlucoseRecords/>}/>
<Route path='/insuline' element={<ListInsulineRecords/>}/>
<Route path='/' element={<Login/>}/>
<Route path='/signUp' element={<SignUp/>}/>
</Routes>
</Router>
);
}
export default App;
import React, { useState } from 'react';
import './Login.css';
import logo from '../../images/HealthControl.png';
import { Link } from 'react-router-dom';
import { URL } from '../../components/apiURL';
import axios from 'axios';
import PropTypes from 'prop-types';
async function loginUser(credentials) {
return fetch(`${URL}/user/login`, {
method: 'POST',
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify(credentials)
})
.then(data => data.json())
}
export default function Login({ setToken }) {
const [email, setEmail] = useState([]);
const [password, setPassword] = useState([]);
const handleSubmit = async e => {
e.preventDefault();
const token = await loginUser({
email,
password
});
setToken(token);
}
return (
<body>
<div class="Login">
<div class="columns is-vcentered">
<div class="login column is-4 ">
<section class="section">
<div class="has-text-centered">
<img class="login-logo has-background-primary" src={logo} alt="Logo" />
</div>
<form onSubmit={handleSubmit}>
<div class="field">
<label class="label">Username</label>
<div class="control has-icons-right">
<input class="input" type="text" onChange={e => setEmail(e.target.value)}></input>
<span class="icon is-small is-right">
<i class="fa fa-user"></i>
</span>
</div>
</div>
<div class="field">
<label class="label">Password</label>
<div class="control has-icons-right">
<input class="input" type="password" onChange={e => setPassword(e.target.value)}></input>
<span class="icon is-small is-right">
<i class="fa fa-key"></i>
</span>
</div>
</div>
<div class="has-text-centered">
<button type="submit" class="button is-vcentered is-primary is-outlined">Login</button>
</div>
</form>
<div class="has-text-centered">
<Link to='/signUp' className="nav-links">
<a> Don't you have an account? Sign up now!</a>
</Link>
</div>
</section>
</div>
<div id="particles-js" class="interactive-bg column is-8">
</div>
</div>
</div>
</body>
);
};
Login.propTypes = {
setToken: PropTypes.func.isRequired
};
Solution 1:[1]
It's not clear what you want to do exactly but I think there are a couple of issues in your code:
You're using useContext and passing in an empty array. This hook expects a context object created via React.createContext. Also, the idea with context is that you wrap your components in a context provider so any children can access that context. This way they can access state without having to pass down properties. But you're not using a context provider, you're passing down setToken anyway.
Login requires setToken, but on this line
<Route path='/' element={}/>
you're not passing it down. So you get errors because setToken is undefined inside Login and it is a required property.
What I think you want to do is:
Use useState instead of useContext. Don't define the initial value of token, so the if (!token) is true initially, and false after you call setToken.
const App = () => { const [token, setToken] = useState(); if (!token) { return <Login setToken={setToken} />; } return ( <Router> <Routes> <Route path="/login" element={<Login setToken={setToken} />} />{" "} </Routes> </Router> ); };
Even this would be a bit weird because after logging in you'd show the login page again, as this is the default route. Probably not what you want to do. I suggest you think well about the solution before you start coding.
Solution 2:[2]
This is caused because you have used useContext to create a state, you should instead use useState.
useState takes in initial state value returns stateful value and a function to update it.useContext takes in Context returns value that is returned by Context.Provider
more about useContext
const [token, setToken] = useState(/* initial state value */);
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | MartaGalve |
| Solution 2 |
