What is the best way to retrieve a class property within an arrow function that is passed to a constructor?

On a React login page, I created a class for rendering authentication methods. The class includes a default render function that I need to customize.

class AuthMethod {
    constructor(initializer: Pick<AuthMethod, 'id'> & Partial<AuthMethod>) {
        Object.assign(this, initializer);
    }
    id!: string;
    text: string = "";
    enabled: boolean = false;
    icon: React.ReactNode = React.Fragment;
    render: () => React.ReactNode = () => (
        <WhiteIconButton key={this.id} disabled={!this.enabled} >
            {this.icon}
        </WhiteIconButton>
    );
}

I have an array of these AuthMethod instances for different purposes:

const authMethods: AuthMethod[] = [
    new AuthMethod({
        id: "auth_facebook",
        text: "Sign in with Facebook",
        enabled: false,
        icon: <FontAwesomeIcon icon={faFacebookSquare} />,
        // render: () => this.icon  // This doesn't work
    }),
    new AuthMethod({
        id: "auth_twitter",
        text: "Sign in with Twitter",
        enabled: false,
        icon: <FontAwesomeIcon icon={faTwitter} />
    }),
    new AuthMethod({
        id: "auth_google",
        text: "Sign in with Google",
        enabled: true,
        icon: <FontAwesomeIcon icon={faGoogle} />
    })
];

To render them, I use the following code:

<div className={classes.socialLine}>
    { authMethods.map(m => m.render()) }
</div>

The issue arises when trying to override the "render" arrow function with one that utilizes the class properties. If I uncomment the "render:" line in the Facebook example, I receive an error stating "The containing arrow function captures the global value of 'this'".

How can I access member properties within the supplied arrow function?

Edit: To see the problem, you can run the code here: https://codesandbox.io/s/tender-bhabha-8jdmf?fontsize=14&hidenavigation=1&theme=dark

Simply uncomment the "render: " line to encounter the issue.

Solution:

Credit goes to jcalz for providing the answer that arrow functions do not have access to the "this" property (as it is bound to the context where it is created). Therefore, using a regular function (non-arrow) resolves the issue. Despite the class definition having an arrow function signature, a "normal" function works fine as shown below:

  new AuthMethod({
    id: "auth_facebook",
    text: "Sign in with Facebook",
    enabled: false,
    icon: <FontAwesomeIcon icon={faFacebookSquare} />,
    render: function() {
      return this.icon;
    }
  }),

You can view the solution in action here:

Answer №1

Arrow functions do not have their own context for 'this', unlike traditional non-arrow functions created with the 'function' keyword. Therefore, any reference to 'this' within an arrow function will actually point back to the lexical scope of 'this', which may not be the desired behavior.

To resolve this issue, one option is to avoid using arrow functions altogether. You can instead utilize an anonymous function such as function(){return this.icon}, or opt for a more concise method syntax:

  new AuthMethod({
    render(){return this.icon}, 
    id: "auth_facebook",
    text: "Sign in with Facebook",
    enabled: false,
    icon: <FontAwesomeIcon icon={faFacebookSquare} />
  }),

This approach should effectively achieve the desired outcome and is considered the standard way to handle this scenario. Best of luck with your implementation!

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Error in NodeJS when trying to run ESM: "ReferenceError: exports is not defined

Having a tough time with this task. I'm attempting to execute ESM scripts on Node 14 (AWS Lambda) I am working on running this piece of code to convert 3D objects to THREE JSON. This involves using the command node -r esm fbx2three.js model.fbx. I ...

Encountering issues with TypeScript class

I am facing an issue with transpiling the following TypeScript class: class DataService { styles: Object[]; selectedStyle: Object; selectedChildStyle: Object; constructor() { this.styles = [{ "name": " ...

Showcase data objects in JSX format

I have an Object stored in my state that looks like this: console.log(state) I've developed a component to display a card for each item within this object (which contains sub-objects). Despite trying multiple approaches, I keep encountering an error ...

What is the correct way to create a new SystemError object in Node.js?

After studying Node's documentation, it is evident that SystemError is an extension of the Error class. However, when attempting to utilize SystemError directly, Node throws a ReferenceError indicating that SystemError is undefined. While it is theor ...

Update a specific form data field within an Angular application

I recently encountered a situation where I had an angular form with 9 fields and submitted it to the server using a post request. However, I realized that I had only filled in values for 8 fields while leaving one as null. Now, in a new component, I am w ...

Is there a way to incorporate an external JavaScript file into a .ts file without the need for conversion?

I have an external JavaScript file that I need to utilize in a .ts file without performing any conversion. Does anyone know how to use it within TypeScript without the need for conversion? ...

When working with TypeScript for initial data, you have the choice between using interface types or class types. Which approach is the

When working with initial data in TypeScript, you have the option to use either an interface type or a class type. Which approach is preferable? export interface Item{ text: string, value: number } itemModel: ItemComboBox = { value:'valu ...

Initiate and terminate server using supertest

I've developed a server class that looks like this: import express, { Request, Response } from 'express'; export default class Server { server: any; exp: any; constructor() { this.exp = express(); this.exp.get('/' ...

The functionality of the Angular click event binding seems to be malfunctioning

When I click on a radio button, I want to see relevant selections. Below are the files: app.component.html <div class="col-md-3"> <b>Select Category</b><br> <input type="radio" name="colors" [(ngModel)]="typing" (clic ...

Restoring scroll position in Next.js when the page is reloaded

Problem Description I am facing an issue with the sticky header functionality I have implemented. It relies on a useEffect hook to monitor its scroll Y offset state. However, when I reload the page, it fails to detect the position until I manually scroll ...

The slice() method in arrays provides a reference to the elements rather than copying

In my file, I am exporting an object in the following manner: export const LINECHART2_DATA = { series: [{ data: [], name: 'HR', }, { etc... }] } The way I import it is like this: import { LINECHART2_DAT ...

Is it possible to optimize the performance of my React and TypeScript project with the help of webpack?

I am working on a massive project that takes 6 to 8 minutes to load when I run npm start. Is there a way to speed up the loading process by first displaying the sign-in page and then loading everything else? ...

Tips for getting Nativescript listview to function properly

I am currently developing an app using nativescript and angular 2. I am facing some issues while trying to implement the nativescript listview component. Whenever I run the app, all I see is " [object object] ". Below is my view code : <grid-layout c ...

Differences Between JavaScript and TypeScript Classes

I'm a novice when it comes to TypeScript and JavaScript classes! While learning TypeScript, I created a simple code snippet like this: class User { name: string; email: string; constructor(name: string, email: string) { this.name = name; ...

Combine Sonarqube coverage with Istanbuljs/NYC for enhanced code analysis

In my typescript project, we utilize a Jenkins pipeline to run all functional tests in parallel after building the main container. Towards the end of the pipeline, we conduct a code coverage check and then transfer the results to sonarqube. Below is an ex ...

Encountering TS2344 error when referring to the Component Ref in Vue.js during typing operations

I received a component reference on my FormCheckbox component from a patternlib. When I tried to incorporate the component into my own TestComp component, I encountered this TypeScript error that left me puzzled: TS2344: Type '{ name: string; mixins: ...

Step-by-step guide on incorporating an external JavaScript library into an Ionic 3 TypeScript project

As part of a project, I am tasked with creating a custom thermostat app. While I initially wanted to use Ionic for this task, I encountered some difficulty in integrating the provided API into my project. The API.js file contains all the necessary function ...

Tips for incorporating classes as a prop in material ui components

When working with material ui, I often find myself creating generic components where the styling is actually defined in a parent or grandparent component. For example: const GenericDescendant = (props: DescendantProps) => { const { classesFromAncestor ...

Setting up Typescript with React 17 and Tailwind CSS version 2.0

I'm struggling to set up TailwindCSS 2.0 with the create-react-app --template typescript configuration and encountering errors. Even after following the instructions on the official TailwindCSS website for React at https://tailwindcss.com/docs/guides/ ...

Unable to display information on mat table without receiving an error message

Hello everyone, I am a novice in Angular and I seem to be encountering an issue with displaying data on my mat table. Surprisingly, no errors are being shown. While I can see the column names, the actual data is not visible. Can someone help me figure ou ...