In this article, we will walk through the process of converting a class-style implementation using this.state into a clean React Functional Component (React.FC) using hooks like useState. We will also explain the key changes required to make the component work properly.


Refactoring an SPFx IFramePanel Component to React Functional Component (React.FC)

Introduction

When working with SharePoint Framework (SPFx) and the PnP React controls library, many examples still rely on class-based React components. However, modern React development encourages the use of functional components with hooks, which are simpler, more readable, and easier to maintain.

In this article, we will walk through the process of converting a class-style implementation using this.state into a clean React Functional Component (React.FC) using hooks like useState. We will also explain the key changes required to make the component work properly.


Original Problem

The original code attempted to use a functional component but still relied on class-based patterns:

import * as React from ‘react’;

import { IFramePanel } from “@pnp/spfx-controls-react/lib/IFramePanel”;

const IFramePanelWp: React.FC = () => {

  return (

    <div>

      <IFramePanel url={this.state.iFrameUrl}

        type={PanelType.medium}

        headerText=”Panel Title”

        closeButtonAriaLabel=”Close”

        isOpen={this.state.iFramePanelOpened}

        onDismiss={this._onDismiss.bind(this)}

        iframeOnLoad={this._onIframeLoaded.bind(this)} />

    </div>

  );

};

export default IFramePanelWp;

Issues in the Code

This implementation has several problems:

  • Use of this.state inside a functional component
  • Use of this._onDismiss.bind(this) which belongs to class components
  • Missing imports (PanelType)
  • No state management using React hooks

Refactored Solution Using React.FC

Below is the corrected version using modern React practices:

import * as React from “react”;

import { useState } from “react”;

import { IFramePanel } from “@pnp/spfx-controls-react/lib/IFramePanel”;

import { PanelType } from “@fluentui/react/lib/Panel”;

const IFramePanelWp: React.FC = () => {

  const [iFrameUrl, setIFrameUrl] = useState<string>(“https://www.microsoft.com“);

  const [isOpen, setIsOpen] = useState<boolean>(true);

  const onDismiss = () => {

    setIsOpen(false);

  };

  const onIframeLoaded = () => {

    console.log(“IFrame loaded successfully”);

  };

  return (

    <div>

      <IFramePanel

        url={iFrameUrl}

        type={PanelType.medium}

        headerText=”Panel Title”

        closeButtonAriaLabel=”Close”

        isOpen={isOpen}

        onDismiss={onDismiss}

        iframeOnLoad={onIframeLoaded}

      />

    </div>

  );

};

export default IFramePanelWp;


Key Changes Explained

1. Replacing this.state with useState

In class components, state is managed using this.state. In functional components, we use the useState hook:

const [iFrameUrl, setIFrameUrl] = useState<string>(“https://www.microsoft.com“);

const [isOpen, setIsOpen] = useState<boolean>(true);

This allows us to store and update state variables without needing a class.


2. Removing this Context

Functional components do not use the this keyword. Instead of defining methods like:

this._onDismiss.bind(this)

We define functions directly:

const onDismiss = () => {

  setIsOpen(false);

};


3. Handling Events Without .bind(this)

Because functional components do not have a this context, there is no need to bind functions. Arrow functions automatically preserve scope.

Before (class-based):

onDismiss={this._onDismiss.bind(this)}

After (functional):

onDismiss={onDismiss}


4. Importing Required Dependencies

The original code missed the PanelType import, which is required:

import { PanelType } from “@fluentui/react/lib/Panel”;

Without this import, the component will fail at runtime.


5. Cleaner and More Maintainable Code

Using React.FC with hooks:

  • Reduces boilerplate code
  • Improves readability
  • Makes state logic easier to reuse
  • Aligns with modern React best practices

Optional Enhancement

You can easily extend this component by adding a button to control the panel:

<button onClick={() => setIsOpen(true)}>Open Panel</button>

This allows users to trigger the IFramePanel dynamically.


Conclusion

Migrating from class components to functional components in SPFx projects offers significant advantages. By using React.FC and hooks such as useState, you can simplify your code, eliminate unnecessary complexity, and align your solution with modern React standards.

This approach is especially valuable when working with libraries like PnP SPFx React Controls, ensuring your components remain clean, efficient, and future-proof.


Edvaldo Guimrães Filho Avatar

Published by