useEffect hook not working right? Here are a couple of things you can check.

You can’t figure out why the UI is not updating as it should, and you’ve tried console.log and F12 and are still none the wiser. Wouldn’t it be nice if you could get past this and build and show off beautiful apps instead.

This list of common misunderstandings and how to over come them will probably (hopefully!) help fix your problem.

useEffect uses some advance JavaScript and programming concepts. But, despite being advanced, they are well within the reach of any React developer, with a little bit of time and practice. Let’s fix it!

Modifying State Directly

If you modify state directly (mutate it) then it can cause problems with re-rendering, but not always.

It can cause problems if you render any pure components in React. Pure components will assume that the props passed to them won’t be mutated. They make this assumption so that React can make object comparisons more quickly.

Although you can get away with it often, as a rule it is best not to modify state directly, and instead update the state to a brand new object.

There is a lot more on this subject in this blog post: Why Not To Modify React State Directly

Using an object or value from an older render

The code in a functional component gets called on every single render. This means a new “scope” is created, and all the variables exist in that scope.

When you use a variable from the component’s function in the useEffect callback, it will be the variable “for that scope”, or in other words “for that render”. If you are not careful you might be looking at data from an older render.

For example, if you create an object, such as an array for example inside your functional component, and then refer to this inside your useEffect callback, you will always be referring to the one that was created when the hook was created. The hook might cause things to happen later on, but you will still be referring to the same object.

This may or may not be what you want, but it’s important to understand what is happening here.

I have created an example below. It has an App component and a TimeComponent embedded inside it. Clicking the button update the time passed to the TimeComponent.

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

import "./styles.css";

export default function App() {
  const [time, setTime] = useState(new Date());

  return (
    <div>
      <TimeComponent time={time} />
      <button
        onClick={() => {
          setTime(new Date());
        }}
      >
        Update
      </button>
    </div>
  );
}

function TimeComponent(props) {
  useEffect(() => {
    setInterval(() => {
      console.log(props.time);
    }, 1000);
  }, []);
  return <div>{props.time.toString()}</div>;
}

There is a useEffect in the TimeComponent that runs when the component firsts renders, because it passes an empty array for the dependencies argument. It sets up a timer to log the value of time every second.

However even though clicking the button updates the value of the time prop, the value logged from useEffect remains the same!

This is because it refers to the first time that created when the component was first rendered.

And this is all because of scopes – and it a React “thing”. It’s a feature of JavaScript itself. It can catch you out in function components and hooks, so it’s good to understand it.

Posted by Martin Capodici

.

Leave a Comment

Your email address will not be published. Required fields are marked *