Home > Back-end >  RTK Query custom hook Typescript occurs Invalid hook call. Hooks can only be called inside of the bo
RTK Query custom hook Typescript occurs Invalid hook call. Hooks can only be called inside of the bo

Time:08-22

Just learning some nexts.js with rtkquery with typescript and occur this error in useEffect in
GoogleMapComponent.tsx, code below. React site said that i broke some rules of hooks using, but this is functional component, using inside another hook, not a plain js function. dont know what to do. thanks guys.

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
}

CodePudding user response:

You're using the useGetForecastQuery-hook inside another function (callback to useEffect in your case). That's not allowed with hook functions, hooks can only be called at top-level inside a component or hook function.

See: https://reactjs.org/docs/hooks-rules.html#only-call-hooks-at-the-top-level

  • Related