When utilizing the RTK Query custom hook in Typescript, an error may occur stating "Invalid hook call. Hooks can only be called inside the body of a

While delving into next.js with rtkquery and typescript, I encountered an error in the useEffect hook within GoogleMapComponent.tsx. The React site pointed out that I was violating some rules of hooks usage, but this is a functional component being used inside another hook, not just a plain JavaScript function. I'm not sure how to resolve this issue. Any help would be appreciated. Thank you!

import React, {ReactElement, useEffect, useState} from 'react';
import GoogleMapReact from 'google-map-react';
import {useGetForecastQuery} from "../redux/slices/weather.slice";

export default function GoogleMap({coords}: { coords: { lat: number; lng: number } }) {
    const [point, setPoint] = useState([45, 55]);

    useEffect(() => {
        console.log(useGetForecastQuery({location: `${point[0]},${point[1]}`, alerts: 'no', aqi: 'no', days: 2}))
    }, [point])


    const style = {
        width: '450px',
        height: '450px'
    };

    const AnyReactComponent = ({text, lat, lng} : {text:string, lat:number, lng:number}): ReactElement => {
        return (
            <>
                {`${text}  ${lat}  ${lng}`}
            </>
        )
    }

    const onMapClick = ({
                          x,
                          y,
                          lat,
                          lng,
                          event
                      }: { x: number, y: number, lat: number, lng: number, event: any }) => {
        setPoint([lat, lng]);
    }
    return (
        <>
            <div style={style}>
                <GoogleMapReact
                    options={{
                        panControl: false,
                        mapTypeControl: true,
                        scrollwheel: true,
                    }}
                    onClick={onMapClick}
                    bootstrapURLKeys={{
                        key: process.env.NEXT_PUBLIC_REACT_APP_GOOGLE_MAPS_API_KEY!,
                        language: 'ua',
                        region: 'ua',
                    }}
                    layerTypes={['TrafficLayer', 'TransitLayer']}
                    defaultCenter={coords}
                    center={coords}
                    defaultZoom={1}
                    margin={[0, 0, 0, 0]}
                >
                    <AnyReactComponent text='Marker' lat={point[0]} lng={point[1]}/>
                </GoogleMapReact>
            </div>
            <div>
                Google Map
            </div>
        </>
    )
}

WeatherSlice.ts

// Need to use the React-specific entry point to allow generating React hooks
import { createApi, fetchBaseQuery } from '@reduxjs/toolkit/query/react'
import type RootForecast from '../../types/forecast.type'
import type {ForecastQueryOptions} from '../../types/query-options.type'
// Define a service using a base URL and expected endpoints

const api_key = process.env.NEXT_PUBLIC_WEATHER_API_KEY;

export const weatherApi = createApi({
    reducerPath: 'weatherApi',
    baseQuery: fetchBaseQuery({ baseUrl: 'https://api.weatherapi.com/v1/' }),
    endpoints: (builder) => ({
        getForecast: builder.query<RootForecast, ForecastQueryOptions>({
            query: (forecastQueryOptions: ForecastQueryOptions) => `forecast.json
            ?
            key=${api_key}&
            q=${forecastQueryOptions.location}&
            aqi=${forecastQueryOptions.aqi}&
            alerts=${forecastQueryOptions.alerts}`,
        }),
    }),
})

// Export hooks for usage in function components, which are
// auto-generated based on the defined endpoints
export const { useGetForecastQuery } = weatherApi

forecast.type.ts autogenerated from json

export interface Location {
    name: string;
    region: string;
    country: string;
    lat: number;
    lon: number;
    tz_id: string;
    localtime_epoch: number;
    localtime: string;
}

export interface Condition {
    text: string;
    icon: string;
    code: number;
}

export interface Current {
    last_updated_epoch: number;
    last_updated: string;
    temp_c: number;
    temp_f: number;
    is_day: number;
    condition: Condition;
    wind_mph: number;
    wind_kph: number;
    wind_degree: number;
    wind_dir: string;
    pressure_mb: number;
    pressure_in: number;
    precip_mm: number;
    precip_in: number;
    humidity: number;
    cloud: number;
    feelslike_c: number;
    feelslike_f: number;
    vis_km: number;
    vis_miles: number;
    uv: number;
    gust_mph: number;
    gust_kph: number;
}

export interface Condition2 {
    text: string;
    icon: string;
    code: number;
}

export interface Day {
    maxtemp_c: number;
    maxtemp_f: number;
    mintemp_c: number;
    mintemp_f: number;
    avgtemp_c: number;
    avgtemp_f: number;
    maxwind_mph: number;
    maxwind_kph: number;
    totalprecip_mm: number;
    totalprecip_in: number;
    avgvis_km: number;
    avgvis_miles: number;
    avghumidity: number;
    daily_will_it_rain: number;
    daily_chance_of_rain: number;
    daily_will_it_snow: number;
    daily_chance_of_snow: number;
    condition: Condition2;
    uv: number;
}

export interface Astro {
    sunrise: string;
    sunset: string;
    moonrise: string;
    moonset: string;
    moon_phase: string;
    moon_illumination: string;
}

export interface Condition3 {
    text: string;
    icon: string;
    code: number;
}

export interface Hour {
    time_epoch: number;
    time: string;
    temp_c: number;
    temp_f: number;
    is_day: number;
    condition: Condition3;
    wind_mph: number;
    wind_kph: number;
    wind_degree: number;
    wind_dir: string;
    pressure_mb: number;
    pressure_in: number;
    precip_mm: number;
    precip_in: number;
    humidity: number;
    cloud: number;
    feelslike_c: number;
    feelslike_f: number;
    windchill_c: number;
    windchill_f: number;
    heatindex_c: number;
    heatindex_f: number;
    dewpoint_c: number;
    dewpoint_f: number;
    will_it_rain: number;
    chance_of_rain: number;
    will_it_snow: number;
    chance_of_snow: number;
    vis_km: number;
    vis_miles: number;
    gust_mph: number;
    gust_kph: number;
    uv: number;
}

export interface Forecastday {
    date: string;
    date_epoch: number;
    day: Day;
    astro: Astro;
    hour: Hour[];
}

export interface Forecast {
    forecastday: Forecastday[];
}

export default interface RootForecast {
    location: Location;
    current: Current;
    forecast: Forecast;
}

and query-options.type.ts

export interface ForecastQueryOptions {
    location: string,
    days: number,
    aqi: string,
    alerts: string
}

Answer №1

It seems like you have included the useGetForecastQuery hook within another function, specifically as a callback inside the useEffect function in your code. However, this is not permitted with hook functions as they can only be called at the top-level inside a component or hook function.

To learn more about this rule, please refer to: https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for running a JavaScript function that is returned in an AJAX response

I am facing an issue with executing a function after a successful Ajax request in my jQuery code. Here is the snippet of my code: $.ajax({ type: "POST", url: "https://www.example.com/create_chat.php", data: dataString, beforeSe ...

What is the best way to hide the next/previous tabs once the jQuery dataTable has been set up using jSON data

Setting up a jQuery table using JSON data. Despite knowing that there will only be one row, the next/previous tabs are still displayed after the table. Is there a way to remove them? Here is the code for the table: table = $("#retrievedTable").dataTabl ...

Seamlessly adaptive HTML5 video playback

Has anyone figured out how to make an HTML5 video in an absolutely positioned <video> element resize to fit the window width and height without ever getting cropped? Many solutions I've come across rely on using the <iframe> tag, which is ...

Differences between functions in Angular services and components: which one to use?

Our Angular application is made up of excel-like grids, with 20 components each containing a unique grid. Every component includes a save() function that handles adding, editing, and deleting items. The save() function is quite large and resides in each c ...

The issue of Angular JQuery Datepicker failing to set the MinDate upon initialization

In my AngularJS project, I am using JQuery UI's Datepicker for the Date From and Date To fields. I have successfully bound the value to the model using a directive, and I have also implemented logic in the OnSelect function to ensure that the Date To ...

When attempting to access API>19 on my Android device, I encountered an error in my Interface to Java that stated: "TypeError: Android.method is not a function."

Having my minimum API set to 16, everything seems to be working fine. However, debugging has become quite a challenge. I've read that after API 19, the Chrome debugger can be used. But when it comes to interfacing with Java code, I encounter the error ...

Nothing is being sent in the Ajax request to PHP

I am experiencing an issue with my AJAX post to PHP as the PHP code is indicating that the post is empty. Strangely, there are no error messages displayed by PHP or in the console. The alert(data) statement at the end of the code retrieves all the HTML con ...

How to declare a variable using new String() and s = '' in Typescript/Javascript

What is the correct way to declare an array of characters or a string in JavaScript? Is there a distinction between an array of characters and a string? let operators = new String(); or let operators = ''; ...

Error encountered when attempting to locate the file declaration for module 'jwt-decode'

Currently, I am utilizing the Visual Studio 2017 template for my Angular project and encountering an issue when attempting to import the 'jwt-decode' module after adding it to package.json. The error (mentioned in the title of my post) arises aft ...

Adjust dimensions of an image retrieved from a URL

Is there a way to adjust the size of the image displayed here?: var picture = new Image(); picture.src = 'http://www.example.com/images/logo.png'; picture.width = 200; //trying to change the width of the image $('canvas').css({ ...

Clicking on a span will allow you to alter the text within a paragraph located in a

I am hoping to update a paragraph of text with new content when a faux 'link' (span) at the bottom of the page is clicked. This is what I have so far <body> <p> This is the paragraph that should be changed after clicking on the sp ...

Buefy: Secure the header of the table in place while allowing the rows to scroll freely

How can I make the header of the table component stay fixed while allowing only the rows to scroll? ...

How to Troubleshoot jQuery AJAX Not Sending JSON Data

I've been attempting to make an ajax request, but it keeps returning with an error response. $('form#contactForm button.submit').click(function () { var contactName = $('#contactForm #contactName').val(); ...

Issue with Achieving Two-Way Binding in Angular 1.5 Component when using $ctrl

I am struggling with customizing some products using a component in my index.html. Ultimately, I need to calculate the total of selected products within the main controller "planosVoz" using two-way binding on the svaTotal property in the component control ...

Display an image using a modal window and Ajax XMLHttpRequest

I was tasked with creating a button that can load various types of content (text, images, videos, etc) into a modal popup window using Ajax without any frameworks. So far, I've been successful with text but have run into issues with loading images. De ...

AngularJS directive not registering event after model update

Within my angularjs application, I have implemented an element directive that is equipped with an event listener. This listener is designed to respond to a broadcast event from the controller. app.directive('listItem', function(){ return { ...

Multiple keyup events being triggered repeatedly

Currently, I am developing an Angular 4 application. Within my component's HTML, there is a textbox where users can input text. As soon as the user starts typing, I want to trigger an API call to retrieve some data. The current issue I am facing is t ...

Why is req.body coming back as undefined?

I recently installed body-parser using npm, included it in my project with Express, but I'm still encountering the issue of req.body being undefined. If anyone can identify what's causing this problem, please share your insights as I suspect it m ...

When returning to the homepage from a different route, React Components will re-render and trigger a new API call

Is there a specific reason causing the re-rendering of this component? As far as I know, React preserves the previous page when navigating to another page using the LINK tag. Visit the live link: Thethirdfront.vercel.app www.github.com/saurabhje/Truly-Tru ...

What is the best way to utilize Enquire.js for dynamically adding and removing CSS classes?

I'm looking to dynamically add and remove a css class based on a media query using Enquire.js but I could use some guidance on utilizing the functions properly. Here's what I envision in pseudo code: if (screens max-width > 480px){ #thumb.r ...