Home > Mobile >  Invalid hook call Hooks can only be called inside of the body of a function component for useFocusEf
Invalid hook call Hooks can only be called inside of the body of a function component for useFocusEf

Time:10-01

React navigation V6 documentation shows examples of using useCallback inside useFocusEffect. However when I use the same code, I encounter invalid-hook-call.

link: https://reactnavigation.org/docs/use-focus-effect/

import {ActivityIndicator, FlatList, Text, View} from 'react-native';
import React, {useState, useEffect} from 'react';
import {Button} from '@rneui/base';
import {Link} from '@react-navigation/native';
import {useSelector} from 'react-redux';
import {useFocusEffect} from '@react-navigation/native';

import ListContainer from '../../components/ListContainer';
import {icons} from '../../constants';
import {ImageLoader} from '../../components/ImageLoader';
import styles from './styles';
import {API_KEY} from '../../constants/key';
import {date, year, month} from '../../constants/date';

const Home = () => {
  const [data, setData] = useState();
  const [forecastData, setForecastData] = useState([]);

  const longVal = useSelector(state => state.geo.longitude);
  const latVal = useSelector(state => state.geo.latitude);
  console.log('Am i render ? Home Screen');

  const renderItem = ({item}) => {
    return (
      <ListContainer
        imgSrc={require('../../assets/icons/sample-weather.png')}
        degree={item.main.temp}
        humidity={item.main.humidity}
      />
    );
  };

  const fetchWeatherData = async () => {
    const requestOptions = {
      method: 'GET',
      headers: {'Content-Type': 'application/json'},
    };
    try {
      await fetch(
        // weather API

        `https://api.openweathermap.org/data/2.5/weather?lat=${latVal}&lon=${longVal}&appid=${API_KEY}`,
        requestOptions,
      )
        .then(response => response.json())
        .then(response => {
          console.log(response);
          setData(response);
        });
    } catch (err) {
      console.log(err);
    }
  };

  const fetchForecastData = async () => {
    const requestOptions = {
      method: 'GET',
      headers: {'Content-Type': 'application/json'},
    };
    try {
      await fetch(
        // forecast API

        `https://api.openweathermap.org/data/2.5/forecast?lat=${latVal}&lon=${longVal}&appid=${API_KEY}`,
        requestOptions,
      )
        .then(response => response.json())
        .then(response => {
          setForecastData(response.list);
        });
    } catch (err) {
      console.log(err);
    }
  };

  useFocusEffect(() => {
    React.useCallback(() => {
      console.log(latVal, longVal);
      fetchWeatherData();
      fetchForecastData();
    }, [latVal]);
  });

  // useEffect(() => {
  //   console.log(latVal, longVal);
  //   fetchWeatherData();
  //   fetchForecastData();
  // }, [latVal]);

  if (latVal && longVal) {
    return (
      <View style={styles.containerMain}>
        <View style={styles.upperContainer}>
          <Text style={styles.mainText}>
            {data?.name}, {data?.sys?.country}
          </Text>
          <Text style={styles.dateText}>
            {month} {date}, {year}
          </Text>
          <View style={styles.btnContainer}>
            <Button
              title="Forecast"
              buttonStyle={styles.btnStyle}
              containerStyle={styles.containerOne}
              onPress={() => {}}
            />
            <Button
              title="Air quality"
              buttonStyle={styles.btnTwoStyle}
              containerStyle={styles.containerOne}
              onPress={() => {}}
            />
          </View>
          <ImageLoader source={icons.weatherSample} style={styles.imageStyle} />
        </View>

        <View style={styles.upperBottomContainer}>
          <View>
            <Text style={styles.tempTextStyle}>Temp</Text>
            <Text style={styles.degreeStyle}>
              {data ? (
                parseInt(data?.main?.temp - 273.15)
              ) : (
                <ActivityIndicator size={'small'} />
              )}
              &deg;
            </Text>
          </View>
          <View>
            <Text style={styles.tempTextStyle}>{data?.weather[0]?.main}</Text>
            <Text style={styles.degreeStyle}>
              {data ? (
                data?.main?.pressure
              ) : (
                <ActivityIndicator size={'small'} />
              )}
              km/h
            </Text>
          </View>
          <View>
            <Text style={styles.tempTextStyle}>Humidity</Text>
            <Text style={styles.degreeStyle}>
              {data ? (
                data?.main?.humidity
              ) : (
                <ActivityIndicator size={'small'} />
              )}
              %
            </Text>
          </View>
        </View>

        <View style={styles.bottomContainer}>
          <View style={styles.bottomTopContainer}>
            <Text style={styles.bottomContainerText}>Upcoming Days</Text>
            <Text style={styles.bottomContainerTextTwo}>
              <Link to={{screen: 'Forecast'}}>View full report</Link>
            </Text>
          </View>
          <View style={styles.flatListContainer}>
            <FlatList
              data={forecastData}
              renderItem={renderItem}
              // keyExtractor={item => item.id}
              horizontal={true}
              showsHorizontalScrollIndicator={false}
            />
          </View>
        </View>
      </View>
    );
  } else {
    return <View style={styles.containerMain}></View>;
  }
};

export default Home;
 

Error: Invalid hook call. Hooks can only be called inside of the body of a function component. This could happen for one of the following reasons:

There are three common reasons you might be seeing it:

You might have mismatching versions of React and React DOM. You might be breaking the Rules of Hooks. You might have more than one copy of React in the same app. Hooks can only be called inside the body of a function component, as I understand. However, why is the above example from documentation not working?

my package.json

{
  "name": "Project",
  "version": "0.0.1",
  "private": true,
  "scripts": {
    "android": "react-native run-android",
    "ios": "react-native run-ios",
    "start": "react-native start",
    "test": "jest",
    "lint": "eslint ."
  },
  "dependencies": {
    "@react-native-async-storage/async-storage": "^1.17.10",
    "@react-native-community/geolocation": "^3.0.1",
    "@react-native-firebase/app": "^15.6.0",
    "@react-native-firebase/auth": "^15.6.0",
    "@react-navigation/bottom-tabs": "^6.4.0",
    "@react-navigation/material-bottom-tabs": "^6.2.4",
    "@react-navigation/native": "^6.0.13",
    "@react-navigation/native-stack": "^6.9.0",
    "@reduxjs/toolkit": "^1.8.5",
    "@rneui/base": "^4.0.0-rc.6",
    "@rneui/themed": "^4.0.0-rc.6",
    "axios": "^0.27.2",
    "moment": "^2.29.4",
    "react": "18.1.0",
    "react-native": "0.70.1",
    "react-native-geolocation-service": "^5.3.1",
    "react-native-google-places-autocomplete": "^2.4.1",
    "react-native-linear-gradient": "^2.6.2",
    "react-native-modal-selector": "^2.1.1",
    "react-native-paper": "^4.12.4",
    "react-native-safe-area-context": "^4.3.4",
    "react-native-screens": "^3.17.0",
    "react-native-vector-icons": "^9.2.0",
    "react-redux": "^8.0.4",
    "redux": "^4.2.0",
    "redux-persist": "^6.0.0",
    "redux-thunk": "^2.4.1"
  },
  "devDependencies": {
    "@babel/core": "^7.12.9",
    "@babel/runtime": "^7.12.5",
    "@react-native-community/eslint-config": "^2.0.0",
    "babel-jest": "^26.6.3",
    "eslint": "^7.32.0",
    "jest": "^26.6.3",
    "metro-react-native-babel-preset": "^0.72.1",
    "react-test-renderer": "18.1.0"
  },
  "jest": {
    "preset": "react-native"
  }
}

CodePudding user response:

Here's the first part of the example from the link:

useFocusEffect(
    React.useCallback(() => {

Here is your version:

  useFocusEffect(() => {
    React.useCallback(() => {

Your version nests the useCallback into an anonymous function. Once it's nested like this, it's no longer "inside of the body of a function component". It's inside the body of an anonymous function. This causes it to violate the Rules of Hooks.

  • Related