reactjsroutes

I'm getting the error 'ReferenceError: useState is not defined'


The developer tools compiler is currently giving me this error:

ReferenceError: useState is not defined

With this block of code, I'm trying to retrieve multiple players name and picture from an NFL Api. Then display this information as cards that people can click on the name taking them to each individual player's page.

This is the code for the component I'm working with:

import { Link } from "react-router-dom";
import _navbar from "../NavBar/navbar";
import styles from './card.module.css';

export default function _quarterbacksPage() {
    const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417];

    const options = {
        method: 'GET',
        headers: {
            'x-rapidapi-key': 'secretkey',
            'x-rapidapi-host': 'nfl-api-data.p.rapidapi.com'
        }
    };
    for (let i = 0; i < quarterbacks.length; i++){
            const [img, setImg] = useState();
            const [name, setName] = useState();
    
        
            const imageUrl = "https://nfl-api-data.p.rapidapi.com/nfl-ath-img?id=" + quarterbacks[i];
            const fetchImage = async () => {
            fetch(imageUrl, options)
            .then(response => response.json())
            .then(response => {
                const data = response.image.href;
                new Blob([data], {type: 'image/png' });  
                setImg(data);
                
            })
          };
    
    
            const FullNameUrl = 'https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=' + quarterbacks[i];
            const fetchFullName = async () => {
                fetch(FullNameUrl, options)
                .then(response => response.json())
                .then(response => {
                    const data = response.athlete.fullName;
                    setName(data);
                
                })
            };
    
        useEffect(() => {
            fetchImage();
            fetchFullName();
        }, []);
    }


    return (
        <>
            <div>
                <_navbar />
                {quarterbacks.map((quarterback) => (
                    <>
                        <img className={styles.cardImage} src={img} alt="profile picture"></img>
                        <Link key={quarterback} to={`/quarterbacks/${quarterback}`}>
                            <h2 className={styles.cardTitle}>{name}</h2>
                        </Link>
                    </>
                ))}
            
            </div>
        </>
    );
}

This block of code is what I used for all my routes:

import React from 'react'
import ReactDOM from 'react-dom/client'
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

import AnalyticsNow from'./pages/analyticsNow.jsx';
import _quarterbackPage from './pages/quarterback.jsx';
import _quarterbacksPage from './pages/quarterbacks.jsx';
import _runningbackPage from './pages/runningback.jsx';
import _runningbacksPage from './pages/runningbacks.jsx';
import _defensePage from './pages/defense.jsx';
import _defensesPage from './pages/defenses.jsx';
import _specialTeamsPage from './pages/specialteams.jsx';
import _SpecialTeamPage from './pages/specialteam.jsx';
import _tightendPage from './pages/tightend.jsx';
import _tightendsPage from './pages/tightends.jsx';
import _widereceiverPage from './pages/widereceiver.jsx';
import _widereceiversPage from './pages/widereceivers.jsx';
import _notFoundPage from './pages/notFound.jsx';


import './index.css'

const router = createBrowserRouter([{
  path: '/',
  element: <AnalyticsNow />,
  errorElement: <_notFoundPage />
  },
  {
    path: '/quarterbacks',
    element: <_quarterbacksPage />

  },
  {
    path: '/quarterbacks/:quarterbackId',
    element: <_quarterbackPage />,
  },
  {
    path: '/runningbacks',
    element: <_runningbacksPage />

  },
  {
    path: '/runningbacks/:runningbackId',
    element: <_runningbackPage />,
  },
  {
    path: '/defenses',
    element: <_defensesPage />

  },
  {
    path: '/defenses/:defenseId',
    element: <_defensePage />,
  },
  {
    path: '/specialteams',
    element: <_specialTeamsPage />

  },
  {
    path: '/specialteams/:specialteamId',
    element: <_SpecialTeamPage />,
  },
  {
    path: '/tightends',
    element: <_tightendsPage />

  },
  {
    path: '/tightends/:tightendId',
    element: <_tightendPage />,
  },
  {
    path: '/widereceivers',
    element: <_widereceiversPage />

  },
  {
    path: '/widereceivers/:widereceiverId',
    element: <_widereceiverPage />,
  },

]);

ReactDOM.createRoot(document.getElementById('root')).render(
  <React.StrictMode>
    <RouterProvider router={router} />
  </React.StrictMode>,
)

The code worked with zero errors when like this for displaying a single card:

import { Link } from "react-router-dom";
import _navbar from "../NavBar/navbar";
import styles from './card.module.css';


export default function _quarterbacksPage() {

     const options = {
        method: 'GET',
           headers: {
             'x-rapidapi-key': 'secretkey',
             'x-rapidapi-host': 'nfl-api-data.p.rapidapi.com'
            }
       };
     const [img, setImg] = useState();
     const [name, setName] = useState();
    
        
     const imageUrl = "https://nfl-api-data.p.rapidapi.com/nfl-ath-img?id=3139477";
            const fetchImage = async () => {
            fetch(imageUrl, options)
            .then(response => response.json())
            .then(response => {
                const data = response.image.href;
                new Blob([data], {type: 'image/png' });  
                setImg(data);
                
            })
          };
    
    
            const FullNameUrl = 'https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=3139477';
            const fetchFullName = async () => {
                fetch(FullNameUrl, options)
                .then(response => response.json())
                .then(response => {
                    const data = response.athlete.fullName;
                    setName(data);
                
                })
            };
    
        useEffect(() => {
            fetchImage();
            fetchFullName();
        }, []);


    return (
        <>
            <div>
                <_navbar />
                
                <img className={styles.cardImage} src={img} alt="profile picture"></img>
                <h2 className={styles.cardTitle}>{name</h2>
                                                      
            </div>
        </>
    );
}

Solution

  • I can see an issue in your code that you haven’t imported useState in the file. Same for useEffect. Any hook that you are using should be imported on the top as follows:

    import { useState, useEffect } from 'react';
    

    Another major issue is that you are using React hook inside loop. React documentation says hooks should be used at the top of a component and hooks can be called from React functions (not from regular JavaScript functions).

    You can refer this Rules of Hooks documentation by React to find all rules related to hooks: https://react.dev/reference/rules#rules-of-hooks

    In your case, you can refer this part of documentation as well. It specifically says that don’t use hooks inside conditions, JavaScript functions and loops: https://react.dev/reference/rules/rules-of-hooks#only-call-hooks-from-react-functions

    Solution for your problem:

    Your code is working with single card. You can create a new component name _quarterbacksPages in same folder where _quarterbacksPage is located. Then declare quarterbacks and map through quarterbacks. Import _quarterbacksPage component on top and pass quarterback to component as follows: New component named _quarterbacksPages:

    import React from 'react';
    import _quarterbacksPage from './_quarterbacksPage';
        
    export default function _quarterbacksPages() {
    const quarterbacks = [3139477, 4241479, 3918298, 3915511, 2577417];
    
    return (
     <>
       {
         quarterbacks.map((qb) => (
           <_quarterbacksPage key={qb} quarterback={qb} />
         ))
       }
     </>
     )
    }
    

    Modified _quarterbacksPage component:

    Your code for _quarterbacksPage component is perfectly fine. Just make little change in that. Get id from props of the component which you using for imageUrl and FullNameUrl.

    export default function _quarterbacksPage({ quarterback }) {
    // code inside function is same that you wrote for single card
    }
    

    Here quarterback is that id which you are using in url. We passed this from parent component which is _quarterbacksPages.

    Now just change urls in _quarterbacksPage component as follows:

    // for imageUrl
    const imageUrl = `https://nfl-api-data.p.rapidapi.com/nfl-ath-img?id=${quarterback}`;
    // for FullNameUrl
    const FullNameUrl = `https://nfl-api-data.p.rapidapi.com/nfl-ath-fullinfo?id=${quarterback}`;
    

    Now only thing in pending that you are using _quarterbacksPage inside createBrowserRouter. Instead of that, use _quarterbacksPages. Your code will work perfectly fine.