skip to Main Content

In the DisplayName component, the state keeps updating even though there is no change in state. console.log("Rendered") and console.log(value) keeps printing. I can’t understand, can someone help me on this. Below is the Code

import React, { useRef, useState, useEffect, useMemo } from "react";
import './App.css';
import FComponent from "./FComponent";

function App() {
  const [name, setName] = useState("am");
  const [counter, setCounter] = useState(1);

  const result = useMemo(() => {
    return factorial(counter)
  }, [counter])

  console.log("result")

  const displayName = () => {
    return {name};
  }

  return (
    <div className="App">
      <h1>Factorial of {counter} is: {result}
      </h1>
      <div>
        <button onClick={() => setCounter(counter - 1)}>Decrement</button>
        <button onClick={() => setCounter(counter + 1)}>Increment</button>
      </div>
      <hr></hr>
      <div>
        <div>
          <label>Enter Name</label>
        </div>
        <input
          type="text"
          value={name}
          onChange={(e) => setName(e.target.value)}
        >
        </input>
        <hr></hr>
        <DisplayName displayName={displayName} />
      </div>
    </div>
  );
}


const DisplayName = ({ displayName }) => {
  console.log("Rendered")

  const [value, setValue] = useState("");
  console.log(value);

  useEffect(() => {
    setValue(displayName());
  })
  return (<p>{`My name is ${value}`}</p>)
}

function factorial(n) {

  if (n < 0) {
    return -1
  }
  if (n === 0) {
    return 1
  }
  return n * factorial(n - 1)
}

function ten() {
  return new Date().toString()
}

export default App;

I expected that in DisplayName component, the state named value should only update once via the useEffect from "" to {"am"}. Now once it’s updated to {"am"} it should stop updating

2

Answers


  1. Every time App renders, this is a new function instance:

    const displayName = () => {
      return {name};
    }
    

    So the props change here:

    <DisplayName displayName={displayName} />
    

    Which causes that component to re-render with the new props.

    You can use useCallback to retain the same function reference unless a dependency changes:

    const displayName = useCallback(() => {
      return {name};
    }, [name]);
    

    So the function would only change if the name dependency changes.

    Login or Signup to reply.
  2. Since you have not specified any dependency in the useEffect hook, your component gets rendered infinitely.

    To fix the issue, add displayName in the dependency array of useEffect. This will ensure that every time displayName changes the useEffect callback will be called.
    eg.

        useEffect(() => {
        setValue(displayName());
      },[displayName])
    

    If you want the displayName to be called only once on component mount add a blank array in the useEffect dependency.

        useEffect(() => {
        setValue(displayName());
        },[])
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search