LKB
LKB

Reputation: 515

Why React Function Component's "this" is undefined

I tested 'this' variable in React's Arrow function component.

I expected 'this' value may be Global variable Whenever I call function component .

Because so far as I know, 'this' in arrow function is bound When Arrow Function is declared and 'this' is determined by Lexical Scope rule.

The end of Lexical Scope is Global Scope, so 'this' might be Global Variable.

What I am missing for ? Thank you.

export default (props) => {

  console.log(this)

  return (
    <div>react this test</div>
  )
}

Upvotes: 11

Views: 9112

Answers (2)

Nick Parsons
Nick Parsons

Reputation: 50664

Function components can be written using both arrow functions () => {} like shown in the above question, or as regular function expressions/declarations such as function Foo() {}. To understand why the above behavior occurs, it is important to first understand that React components are (often) written within ES6 modules.

Why is this undefined in an arrow function component?

One of the properties of modules is that this at the top "module scope" level is undefined. This behavior differs from regular scripts:

<!-- A "module" is what react component code is usually written in -->
<script type="module">
  console.log("Module code (react code) this:", this); // undefined
  //                                             ^
  const App = () => { // example component       |  
     this // --- taken from surrounding scope ---+
  }
</script>

The above example shows how this when used inside of module scope defaults to undefined instead of the global object (such as window) like it does in standard scripts.

Inside of arrow functions, the value of this is taken from the surrounding scope that the arrow function was declared in. In your case, that is the top level of your module, so this takes on the value of undefined.


Why is this undefined inside a regular function component?

Unlike the above example, function expressions/declarations such as function App() {} can also be used to define our component. In this case, you would see that this is also undefined within the component, however, the reason why that's the case differs from why it's undefined in an arrow function component.

To understand why that is, another important property of modules to remember is that they automatically run in strict mode (emphasis mine):

Also, note that you might get different behavior from sections of script defined inside modules as opposed to in standard scripts. This is because modules use strict mode automatically

- MDN

When in strict mode, if this is not bound when a function is called, the function's this defaults to undefined, unlike in non-strict/sloppy mode where it defaults to the global object (such as window in browsers):

In strict mode, however, if the value of this is not set when entering an execution context, it remains as undefined, as shown in the following example

function f2() {
  'use strict'; // see strict mode
  return this;
}

console.log(f2() === undefined); // true

- MDN

Regular function expressions/declarations like function App() {} have their own this value and is set based on how the function is called. In the case of function components, React calls them in such as way that doesn't set the this value. In standard scripts not running in strict mode, that would cause the function component's this to default to the global object (eg: window), however, because we're in a module that behavior no longer applies. Instead, as the module automatically runs in strict mode, and no this is set by React when it calls the component, the this value defaults to undefined.


When you are using functional components, you shouldn't need to refer to this, and instead you should use:

  • hooks such as useState() to manage state
  • the event argument to access the element via the .target/.currentTarget properties when using an event handler (instead of this)
  • the props object passed into your functional component as an argument to access your props (instead of this.props).

Upvotes: 27

Dejan Sandic
Dejan Sandic

Reputation: 451

You can't use this in functional component, and there is no need to. You can access props directly, and if you need state you can use hooks.

import React, { useState } from 'react';

export default (props) => {
  const [state, setState] = useState(/* initial state here */);
  console.log(props, state)

  return (
    <div>react this test</div>
  )
}

this was used before hooks in class-based components:

class MyClass extends React.Component {
   render () {
     console.log(this.props, this.state);
   }
}

Upvotes: 5

Related Questions