0

Say I have a React component that looks like this:

const MyReactComponent = (props) => {
  const my_function = () => {// do some stuff...}

  return (
    <div>
      <p>
        Hello {props.name}, would you like to eat a {my_function()}?
      </p>
    </div>
  )
}

Would the code defining my_function be re-evaluated every time My_React_Component is used? (By "used", I mean "appears in the JSX.")

Asker
  • 1,299
  • 2
  • 14
  • 31
  • 1
    If you mean is the function re-declared every render, then yes. If you mean is the code inside executed every time then yes it is too, because you are calling it inside the JSX. The entire function is executed through during a re-render. Variables redeclared, function called, all of it. If you want to avoid that, then things like `useEffect`, `useCallback` and `useMemo` can be used for that – Jayce444 Oct 27 '20 at 06:28
  • @Jayce444 If I were to have, say, five `MyReactComponent`s in the JSX of some other component, would this mean that `my_function` would be re-defined at least five times? Or is it only defined once per render, regardless of the number of `MyReactComponent`s in that render? – Asker Oct 27 '20 at 06:41
  • 2
    Each is an "instance" of the component function, so anything declared internally would ***not*** be shared. – Drew Reese Oct 27 '20 at 06:58

3 Answers3

4

Yes. Sort of. Maybe no.

When executing a javascript function each line in the function will get executed/evaluated. So the function definition will be evaluated again each time your function is called. Since you are using a function component then yes, the function will get redefined not only each time your component is used but also each time it is re-rendered.

However, does it mean that javascript recompiles the function each time it is defined? Maybe. In theory javascript does not need to recompile the function. It only needs to create a new closure. In theory you do not need to recompile a function to create a new closure - you just need a copy of the function's stack frame. Due to heavy competition from Netscape4 onwards most javascript interpreters have been optimised to such an extent that almost no modern javascript interpreter will recompile the inner function again. So the slowest part of function definition happens only once.

Still, in theory this still gives class-based components a small advantage over function components: the function definition does not need to be evaluated again on each render. In practice the performance difference is very small.

If you really insist on avoiding reevaluating the function definition you can always declare it outside of the component. This will surely evaluate the function only once. However you cannot use closures to share variables with the function but this is not much of an issue as you can always pass the variables into the function. Declaring functions outside of components also encourage you to write pure functions because of the inability to share closures:

const my_function = (propsArgs) => {// do some stuff...}

const MyReactComponent = (props) => {

  return (
    <div>
      <p>
        Hello {props.name}, would you like to eat a {my_function(props)}?
      </p>
    </div>
  )
}
slebetman
  • 109,858
  • 19
  • 140
  • 171
  • Thanks -- could you elaborate on this part? "In theory javascript does not need to recompile the function. It only needs to create a new closure. In theory you do not need to recompile a function to create a new closure - you just need a copy of the function's stack frame." I know what closures are, but how can making a new closure remove the need to recompile the function? And, how can new closures be created given a copy of the function's stack frame? – Asker Oct 27 '20 at 17:14
  • 1
    A closure is by definition a copy of a function's stack frame. It's like the relationship between classes and objects. An object is an instance of a class. A closure is an instance of a scope. And instances of scopes are stack frames. The only difference is that with a closure the stack frame is not destroyed when a function returns but is copied and saved in memory so that when the inner function is called that stack frame gets attached to it. – slebetman Oct 27 '20 at 17:26
  • 1
    ... my answer to this question explains how closures work in more detail: https://stackoverflow.com/questions/26061856/javascript-cant-access-private-properties/26063201#26063201 – slebetman Oct 27 '20 at 17:26
  • Thanks, that link was very helpful. To check my understanding, would it be correct to say "Closures are just stack frames that include the variables of an enclosing scope. There's no strict need to recompile functions because, once a function is compiled, its instructions are stored in a fixed place in memory, so that in order to call the function again, it is enough to simply know the new contents of its stack frame (or its closure!)." I'd appreciate very much if you point out any errors you see in that statement. Otherwise, thanks for the help you've already given! – Asker Oct 28 '20 at 01:09
  • 1
    Yes. That's basically it. Closures are just a mechanism to attach stack frames to each other. Technically, the lisp/scheme guys originally use the term "closure" to refer to just the mechanism and they have other terms for the other things involved like `"closed over variables"` and `"enclosed function"` etc. but the js community and other languages that copied them use "closure" loosely to mean all the parts. – slebetman Oct 28 '20 at 02:36
0

Do you mean Used or re-rendered?

In case of when you meant Used: Yes every component acts as it's own instance hence the methods are executed every time when the function is either called or component is rendered initially (if used on rendering), But if you use the component at multiple times on the DOM, it writes the script only once. The markup is duplicated for that part of DOM, however the script isn't.

usmany
  • 146
  • 2
  • 11
-1

when only initialize, maybe you can use

React.useEffect(() => {
  const my_function = () => {console.log('my_function')}
  my_function();
}, [])
Lashan Fernando
  • 1,187
  • 1
  • 7
  • 21