The error message gives it away, Cannot read property 'current' of null, the only place where current is called is in weather.current in the src of Card.Img, so we deduce that weather was null during the render.

The reason this happens is because the api call is asynchronus, it doesn't populate the state immediately, so the render happens first and tries to read .current from the initial weather state null.

Solution: in your render method, make sure not to read weather.current while weather is null.

You can for example use {weather && <Card>...</Card} to hide the whole card until the data is loaded and show a loading indicator, or you can use src={weather && weather.current.condition.icon} as a quick workaround.

const Weather = ({capital}) => {
  const [weather, setWeather] = useState(null);

  useEffect(() => {
    console.log("useEffect called");
    const getWeather = async () => {
      try {
        const res = await axios.get(
          `http://api.apixu.com/v1/current.json?key=53d601eb03d1412c9c004840192807&q=${capital}`,
        );
        setWeather(res.data);
      } catch (e) {
        console.log(e);
      }
    };
    getWeather();
  }, [capital]);
  console.log(weather);

  return (
    <Card style={{width: "18rem", marginTop: "25px"}}>
      <Card.Img variant="top" src={weather && weather.current.condition.icon} />

      <Card.Header style={{textAlign: "center", fontSize: "25px"}}>
        Weather in {capital}
      </Card.Header>
    </Card>
  );
};
Answer from Moe on Stack Overflow
Top answer
1 of 6
27

The error message gives it away, Cannot read property 'current' of null, the only place where current is called is in weather.current in the src of Card.Img, so we deduce that weather was null during the render.

The reason this happens is because the api call is asynchronus, it doesn't populate the state immediately, so the render happens first and tries to read .current from the initial weather state null.

Solution: in your render method, make sure not to read weather.current while weather is null.

You can for example use {weather && <Card>...</Card} to hide the whole card until the data is loaded and show a loading indicator, or you can use src={weather && weather.current.condition.icon} as a quick workaround.

const Weather = ({capital}) => {
  const [weather, setWeather] = useState(null);

  useEffect(() => {
    console.log("useEffect called");
    const getWeather = async () => {
      try {
        const res = await axios.get(
          `http://api.apixu.com/v1/current.json?key=53d601eb03d1412c9c004840192807&q=${capital}`,
        );
        setWeather(res.data);
      } catch (e) {
        console.log(e);
      }
    };
    getWeather();
  }, [capital]);
  console.log(weather);

  return (
    <Card style={{width: "18rem", marginTop: "25px"}}>
      <Card.Img variant="top" src={weather && weather.current.condition.icon} />

      <Card.Header style={{textAlign: "center", fontSize: "25px"}}>
        Weather in {capital}
      </Card.Header>
    </Card>
  );
};
2 of 6
3

I had the same puzzling issue one time

You can try adding a key prop on the component when it is created in the parent code

<yourcomponent key="some_unique_value" />

This is because in most cases, when your component is reused, based on the way it is created, it may usually re-render it with some changes instead of creating it again when you reuse it, Hence the useEffect is not going to be called. eg in SwitchRoute, loops, conditionals...

So adding a key will prevent this from happening. If it is in a loop, you need to make sure each element is unique, maybe by including the index i in the key if you can't find any better unique key.

🌐
React
react.dev › reference › react › useEffect
useEffect – React
If your Effect is doing something visual (for example, positioning a tooltip), and the delay is noticeable (for example, it flickers), replace useEffect with useLayoutEffect. If your Effect is caused by an interaction (like a click), React may run your Effect before the browser paints the updated screen. This ensures that the result of the Effect can be observed by the event system. Usually, this works as expected.
Discussions

useEffect callback never called
I want to report a bug. My problem is that the callback function I pass to useEffect() is never called in my app. I uploaded a minimal app here that reproduces the issue. As you can see, I render a couple of nested components. After the ... More on github.com
🌐 github.com
16
October 11, 2019
Bug: useEffect not firing when depending on hook value
React version: 18.2.0 Steps To Reproduce Setup a hook which returns a ref.current value. Setup a useEffect which depends on hooks return value. Have some useState which causes re-renders. The useEf... More on github.com
🌐 github.com
2
August 21, 2023
UseEffect not working.
Because you are doing it wrong. More on reddit.com
🌐 r/nextjs
31
0
July 2, 2023
Bug: useEffect not triggering on [deps] change
I stumbled upon this issue which initially I thought is React bug, but upon further investigation React Query seems like the next best candidate. Minimal project is created to demonstrate the probl... More on github.com
🌐 github.com
26
September 2, 2021
Top answer
1 of 3
7

The component adds the event listener once: only on mount. At that time, it adds the handleScroll listener that is "captured" with that specific isHeaderMoved value at that specific point in time. Whenever the page is scrolled, the callback that will be called is the one with that initial isHeaderMoved value. The current code basically calls handleScroll with false over and over.

In short, you need to add isHeaderMoved as a dependency to the effect. You should also move the handleScroll listener inside the effect, so its dependencies can be tracked more properly by the hooks eslint plugin.

  useEffect(
    () => {
      const handleScroll = () => {
        if (window.pageYOffset > 0) {
          if (!isHeaderMoved) {
            setIsHeaderMoved(true)
          }
        } else if (isHeaderMoved) {
          setIsHeaderMoved(false)
        }
      }

      window.addEventListener("scroll", handleScroll)
      return () => {
        window.removeEventListener("scroll", handleScroll)
      }
    },
    [isHeaderMoved],
  )

Refer to these sections from Dan Abromov's posts on the subject (which have examples that can explain it better than I could):

  • https://overreacted.io/a-complete-guide-to-useeffect/#each-render-has-its-own-event-handlers
  • https://overreacted.io/a-complete-guide-to-useeffect/#each-render-has-its-own-effects
  • https://overreacted.io/a-complete-guide-to-useeffect/#moving-functions-inside-effects

It's worth going through the whole post to understand things fully, if you have the time.


From skyboxer's comment, it occurred to me that this would also work, but I'll keep all of the above for informational purposes.

  useEffect(() => {
    const handleScroll = () => {
      setIsHeaderMoved(window.pageYOffset > 0)
    }

    window.addEventListener("scroll", handleScroll)
    return () => {
      window.removeEventListener("scroll", handleScroll)
    }
  }, [])
2 of 3
1

I had the same annoying problem once

try adding a key prop on the component when it is created in the parent code

<yourcomponent key="some_unique_value" />

This is because in most cases, especially when your component is reused, it may usually re-render only with some changes instead of actually creating it again when you reuse it, based on the way it's created, Hence the useEffect is not going to be called. eg inside Switch, Router, loops, conditionals...

So adding a key will prevent this from happening. If it is in a loop, you need to make sure each element is unique, maybe by including the index i in the key if you can't find any better unique key.

🌐
DhiWise
dhiwise.com › post › how-to-fix-useeffect-not-triggering-in-your-react-project
Reasons Why UseEffect Is Not Triggering In Your React App
May 29, 2024 - Sometimes developers encounter a situation where the useEffect not triggering as expected. This can be due to several reasons, such as an incorrect dependency array or the absence of dependencies that should trigger the effect.
🌐
GitHub
github.com › facebook › react › issues › 17066
useEffect callback never called · Issue #17066 · facebook/react
October 11, 2019 - Don't conditionally render child components. Removing the message !== DEFAULT_MESSAGE check (main.tsx, line 20) causes the component trees to render correctly. Use useLayoutEffect() instead of useEffect().
Author   pschiffmann
🌐
GitHub
github.com › facebook › react › issues › 27256
Bug: useEffect not firing when depending on hook value · Issue #27256 · facebook/react
August 21, 2023 - React version: 18.2.0 Steps To Reproduce Setup a hook which returns a ref.current value. Setup a useEffect which depends on hooks return value. Have some useState which causes re-renders. The useEffect may not be called. Link to code exa...
Author   ThomasMorrison
🌐
Reddit
reddit.com › r/nextjs › useeffect not working.
r/nextjs on Reddit: UseEffect not working.
July 2, 2023 -

I am new to nextJS and learning it. Can anybody tell me why UseEffect is not working in my components even though I used 'use client' directive.''

Here is the code.

'use client'

import Link from 'next/link';
import { useRouter } from 'next/navigation'
import React, { useEffect } from 'react'

const NotFound = () => {
  const router = useRouter();

  useEffect(() => {
    console.log('useefoefoiewhf ran1');
    setTimeout(()=>{
      router.push('/')
    },3000)
  }, [])
  
  return (
    <div className='not-found'>
        <h1>Ooooops.....</h1>
        <h2>That page cannot be found.</h2>
        <p>Go back to the <Link href={'/'}>Homepage.</Link>
        </p>
    </div> 
  )
}

export default NotFound;

Find elsewhere
🌐
freeCodeCamp
freecodecamp.org › news › most-common-react-useeffect-problems-and-how-to-fix-them
React.useEffect Hook – Common Problems and How to Fix Them
October 14, 2021 - Nice! Everything looks and works as expected. But wait... what is this? ... React Hook useEffect has a missing dependency: 'user'. Either include it or remove the dependency array.
🌐
GitHub
github.com › tannerlinsley › react-query › issues › 2628
Bug: useEffect not triggering on [deps] change · Issue #2628 · TanStack/query
September 2, 2021 - The problem is that one state change gets swallowed by useEffect. It can be seen if you click on a button and watch the console, useEffect is not triggered even though UI updates correctly aka rerender is triggered.
Author   Tosheen
🌐
Reddit
reddit.com › r/react › useeffect not running properly
useEffect not running properly : r/react
August 30, 2023 - I have to select it twice although I can see the username value changing in the first attempt only ... const [value, setValue] = useState(0); useEffect(() => { const myApiCall = async () => { const data = await apiCall(); // handle data }; myApiCall(); }, [value]);
🌐
Overreacted
overreacted.io › a-complete-guide-to-useeffect
A Complete Guide to useEffect — overreacted
You might be thinking: “Come on Dan, we all know that useEffect is like componentDidMount and componentDidUpdate combined, you can’t keep beating that drum!” Yet this doesn’t work even with componentDidUpdate:
🌐
GitHub
github.com › rrousselGit › flutter_hooks › issues › 153
useEffect hook not working properly. · Issue #153 · rrousselGit/flutter_hooks
July 12, 2020 - There was an error while loading. Please reload this page. ... In React, useEffect hook works after first build. Bu in flutter_hooks, useEffect works before first render. That's why, make an operation with context object on useEffect(() { //operation using context }, []) makes following error: Cannot listen to inherited widgets inside HookState.initState.
Author   alirashid18
Top answer
1 of 4
6

The useEffect hook is guaranteed to run at least once at the end of the initial render.

getData is an async function and the useEffect callback code is not waiting for it to resolve. Easy solution is to chain from the implicitly returned Promise from getData and access the resolved value to update the arrData state. Make sure to remove the state from the useEffect's dependency array so that you don't create a render loop.

The getData implementation could be clean/tightened up by just returning the fetch result, no need to save into a temp variable first.

async function getData() {
  return await fetch(".....")
    .then((res) => res.json());
}

useEffect(() => {
  console.log("if it works, this line should be shown");
  getData().then((data) => {
    setArrData(data);
  });
}, []); // <-- empty dependency so effect called once on mount

Additionally, since arrData is initially undefined, arrData[0] is likely to throw an error. You may want to provide valid initial state, and a fallback value in case the first element is undefined, so you don't attempt to access properties of an undefined object.

const [arrData, setArrData] = useState([]);

...

const data = arrData[0] || {}; // data is at least an object

return (
  <GifCompoment 
    id={data.id}
    name={data.name}
    activeTimeTo={data.activeTimeTo}
    activeTimeFrom={data.activeTimeFrom}
    requiredPoints={data.requiredPoints}
    imageUrl={data.imageUrl}
  />
);
2 of 4
1

You should call state setter insede of Promise

function App() {
    const [arrData, setArrData] = useState();

    function getData() {
        fetch("/api/hidden")
            .then((res) => res.json())
            .then((data) => setArrData(data));
    }

    useEffect(() => {
        console.log("if it works, this line should be shown");
        getData();
    }, []);

    return ...
}
🌐
Coder
coder.earth › post › react-hooks-oops-part-3-an-effect-does-not-run-again-when-its-dependencies-change
React hooks... Oops! Part 3 - an effect doesn't run again when its dependencies change | Łukasz Makuch
Previously it worked only because the component was re-rendered due to the local state update. To make it even more clear, let's try to bring back the You typed: ... message, but this time it won't be done correctly: function App() { // This fragment stays the same: const inputRef = useRef(); const inputValue = inputRef.current ? inputRef.current.value : ""; useEffect( () => console.log("an effect of", inputValue), [inputValue] ); return ( <div> {/* We try to render the current value of the input: */} You typed: {inputValue} <br /> <input type="text" ref={inputRef} /> </div> ); }
🌐
Dave Ceddia
daveceddia.com › useeffect-hook-examples
How the useEffect Hook Works (with Examples)
October 22, 2020 - With the empty array being passed, useEffect will hang on to the first function you pass it, which in turn will hang on to references to all the (maybe stale) variables that were used inside it. The entire point of the dependency array is to give you a way to tell React “Hey, one of my variables changed! Re-create that closure!” · If you get a warning, you need to fix it. Take all the variables it’s complaining about, and put them in the array. Usually that works fine.
🌐
Reddit
reddit.com › r/react › function specified in useeffect hook doesn't run
r/react on Reddit: Function specified in useEffect hook doesn't run
October 14, 2021 -

Hello,

I have a functional object which has three variables managed by the useState hook. These are categories, activeCategories and shownGames. For now I need something simple - run a function when categories update. I am using useEffect hook but it doesn't seem to work.

This is the code for the needed parts - https://pastie.io/uyakqz.js

I use JSON.stringify to check for the category updates (found that solution on StackOverflow). The issue is that the function specified in the useEffect hook doesn't run (it only runs when I load my page). Any help is appreciated!

🌐
Medium
medium.com › @joabi › react-interview-why-those-useeffect-hooks-are-not-working-as-expected-03aaf79df4a5
React Interview: Why those useEffect hooks are not working as expected? | by Julie J. | Medium
November 3, 2023 - In React’s useEffect hook, specifying a dependency array is not always required, but it can be crucial for controlling when the effect runs and ensuring that your component behaves as expected or if it is running infinite loop.
🌐
Reacttraining
reacttraining.com › blog › useEffect-is-not-the-new-componentDidMount
useEffect(fn, []) is not the new componentDidMount()
January 31, 2020 - I think the setInterval example is a great way to understand the capturing nature of useEffect, although it's worth pointing out that there is another API for setting state where we pass a function instead of the value. React will call the function with the existing state (just like the Class-based setState does): ... Now since our effect is not closing over the count value it doesn't need to be added to the dependency array and we're not closing over it so therefore it is not "captured" as the original value when the effect function was made.
🌐
React
react.dev › learn › you-might-not-need-an-effect
You Might Not Need an Effect – React
In general, whenever you have to resort to writing Effects, keep an eye out for when you can extract a piece of functionality into a custom Hook with a more declarative and purpose-built API like useData above. The fewer raw useEffect calls you have in your components, the easier you will find ...