Nta
Nta

Reputation: 41

Calling only once two functions in useEffect

I try to call two functions in my useEffect hook

import React, { useState, useEffect } from "react";

export const LocalWeather = () => {
  const APP_KEY = "XXX";
  const [userPlace, setUserPlace] = useState([]);
  const [localWeather, setLocalWeather] = useState([]);

  async function getUserData() {
    await fetch("http://ip-api.com/json")
      .then((res) => res.json())
      .then((data) => {
        setUserPlace({
          country: data.country,
          city: data.city,
        });
        console.log(data);
      })
      .catch((err) => console.log(err));
  }

  async function getLocalWeather() {
    await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${userPlace.city}&appid=${APP_KEY}`
    )
      .then((res) => res.json())
      .then((data) => {
        setLocalWeather({
          temperature: Math.round(data.main.temp - 273.15),
        });
      })
      .catch((err) => console.log(err));
  }

  useEffect(() => {
    getUserData();
    getLocalWeather();
  });

  return (
    <div>
      <h3>
        Your current place is: {userPlace.country}, {userPlace.city}
      </h3>
      {localWeather.temperature ? (
        <h4>Temperature in your city is: {localWeather.temperature} &#8451;</h4>
      ) : null}
    </div>
  );
};

When I try to add [] to my use useEffect eslint automatically changes it into:

 useEffect(() => {
    getUserData();
    getLocalWeather();
  }, [getLocalWeather]);

What should I do to be able to call my both functions only on the first render?

Thank you for your help!

Upvotes: 1

Views: 10273

Answers (1)

Shubham Khatri
Shubham Khatri

Reputation: 281606

You can define useEffect with an empty dependency which will ensure that the functions only run once

useEffect(() => {
    getUserData();
    getLocalWeather();
  }, []);

However when you write it like above, eslint will complain regarding dependency. So either you can disable the warning like

useEffect(() => {
    getUserData();
    getLocalWeather();
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

Read more about it on this post: How to fix missing dependency warning when using useEffect React Hook?

Or else if the function getUserData and getLocalWeather are mean to only be used inside the useEffect then you can declare them within useEffect

useEffect(() => {
    async function getUserData() {
        await fetch("http://ip-api.com/json")
          .then((res) => res.json())
          .then((data) => {
            setUserPlace({
              country: data.country,
              city: data.city,
            });
            console.log(data);
          })
          .catch((err) => console.log(err));
      }

      async function getLocalWeather() {
        await fetch(
          `https://api.openweathermap.org/data/2.5/weather?q=${userPlace.city}&appid=${APP_KEY}`
        )
          .then((res) => res.json())
          .then((data) => {
            setLocalWeather({
              temperature: Math.round(data.main.temp - 273.15),
            });
          })
          .catch((err) => console.log(err));
      }

      getUserData();
      getLocalWeather();
  }, []);

However if for some reason you want to use them outside of useEffect too and also don't want to disable the warning, you can make use of useCallback for the functions and add them as a dependency

 const getUserData = useCallback(async function() {
  await fetch("http://ip-api.com/json")
    .then((res) => res.json())
    .then((data) => {
      setUserPlace({
        country: data.country,
        city: data.city,
      });
      console.log(data);
    })
    .catch((err) => console.log(err));
}, []);

const getLocalWeather = useCallback(async function getLocalWeather() {
    await fetch(
      `https://api.openweathermap.org/data/2.5/weather?q=${userPlace.city}&appid=${APP_KEY}`
    )
    .then((res) => res.json())
    .then((data) => {
      setLocalWeather({
        temperature: Math.round(data.main.temp - 273.15),
      });
    })
    .catch((err) => console.log(err));
}, []);


useEffect(() => {     
  getUserData();
  getLocalWeather();
}, [getUserData, getLocalWeather]);

Upvotes: 2

Related Questions