'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:

enter image description here

Then when I click the sign in button will always appear me this:

enter image description here

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:

  1. 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.

  2. 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