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.stateinside 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.
