Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Some insight on React behavior would be appreciated. Issue with custom hook

I have a small react example that is puzzling me.

You can run the code at codesanbox

The code is very simple, there is a component TestComponent that displays ‘wowzers’, and calls a custom hook useCustomHook.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

useCustomHook does three things. It declares a useState [list, set_list], then a useEffect based on list to inform when there is a change, and then a 1 second timer that will update the list.

What I expected was that the useEffect would initially run and then a second later it would run again when the list is updated. However, it updates every second. Not only this, but the useCustomHook is being re-entered from TestComponent starting the process all over again, and this happens repeatedly.

Can someone explain please why, when the list is updated with set_list in the timer callback that this causes TestComponent to call useCustomHook again (and again)

I thought I understood that principles of using react and have developed numerous but small applications. This simple example is really throwing me off. Any help would be appreciated.

The code in index.js is a follows.

import { useState, useEffect } from "react";
import React from "react";
import ReactDOM from "react-dom";

const useCustomHook = () => {
  const [list, set_list] = useState([]);
  useEffect(() => console.log("useEffect", "list updated"), [list]);
  setTimeout(() => set_list(() => []), 1000);
};

const TestComponent = () => {
  const hook = useCustomHook();
  return <span>wowzers</span>;
};

class App extends React.Component {
  render() {
    return <TestComponent />;
  }
}

ReactDOM.render(<App />, document.getElementById("root"));

>Solution :

setTimeout is right in the hook body… each time the hook is called it runs the entire body. The timeout is enqueueing a state update which triggers a rerender. Rerenders run all the hooks again.

const useCustomHook = () => {
  const [list, set_list] = useState([]);

  useEffect(() => console.log("useEffect", "list updated"), [list]);

  setTimeout(() => set_list(() => []), 1000); // <-- unintentional side-effect!
};

What I expected was that the useEffect would initially run and then a
second later it would run again when the list is updated.

Place the setTimeout in a mounting useEffect, i.e. empty dependency array, so it runs exactly once after the initial mounting render cycle.

const useCustomHook = () => {
  const [list, set_list] = useState([]);

  useEffect(() => console.log("useEffect", "list updated"), [list]);

  useEffect(() => {
    setTimeout(() => set_list(() => []), 1000);
  }, []);
};

Edit some-insight-on-react-behavior-would-be-appreciated-issue-with-custom-hook

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading