Are Functions Inside React Functional Components Always Recreated on Re-Render?

When you define a function inside a React functional component, it is recreated on every re-render. This is because the old values inside its function body are garbage-collected, and the following happens (as per the function definition):

  1. New primitive values are assigned in memory;
  2. New references are created for functions and objects in memory.

For example:

// MyComponent.jsx
import React, { useState, useEffect } from 'react';

export function MyComponent({ bar }) {
  const [foo, setFoo] = useState('');

  // every time `foo` changes, this will be a different function
  const someFunc = () => {
    // ...
  };

  useEffect(() => {
    console.log('function was recreated');
  }, [someFunc]);

  return (
    <button onClick={() => setFoo(Math.random())}>Foo</button>
  );
}

In this example, the reactive value "foo" will be updated with a new random value on each button click, causing "someFunc" to be recreated with every click. This in-turn will execute the useEffect callback each time as the reference of the "someFunc" function from the previous render will not be the same as the current reference in memory.

Normally, this isn't a problem, unless you're passing such functions as:

  1. Props to memoized child components;
  2. Dependencies to hooks;
  3. Values passed down via context.

In these cases, it can cause unnecessary re-renders. To mitigate this, you can use techniques such as using the useCallback() hook to memoize functions and ensure that they are only recreated when their dependencies change. For example:

// MyComponent.jsx
import React, { useState, useEffect, useCallback } from 'react';

export function MyComponent({ bar }) {
  const [foo, setFoo] = useState('');

  // function is not recreated unless `bar` changes
  const someFunc = useCallback(() => {
    // ...
  }, [bar]);

  useEffect(() => {
    console.log('function was recreated');
  }, [someFunc]);

  return (
    <button onClick={() => setFoo(Math.random())}>Foo</button>
  );
}

Now, with the "someFunc" function wrapped with the useCallback() hook, it won't be recreated unnecessarily unless its dependency "bar" changes.


This post was published by Daniyal Hamid. Daniyal currently works as the Head of Engineering in Germany and has 20+ years of experience in software engineering, design and marketing. Please show your love and support by sharing this post.