Skip to content

Functional Components in React

React was originally built around class-based components. However, with the introduction of functional components, React development has become more concise and readable. Initially limited in capabilities, functional components became much more powerful with the release of React Hooks in version 16.8.

Now, functional components are the recommended standard for building components in React.

Functional components are:

  • Simpler and more concise

  • Easier to test and reason about

  • Compatible with hooks, which offer powerful features like state management and side effects


Class-Based Components Still Exist

Class-based components are still supported in React. You might encounter them in:

  • Older codebases that haven't migrated to hooks

  • Libraries or third-party tools that still use class syntax

  • Cases where developers are more comfortable with class lifecycle methods

  • Special use cases like error boundaries, which (as of now) can only be implemented using classes

Writing Components: Class vs Functional

Class-Based Implementation

jsx
import { Component } from 'react';
import "./App.css";

class App extends Component {
	render() {
	  return (
		<main>
		  <Menu />
		</main>
	  );
	}
}

class Menu extends Component {
	render() {
	  return (
		<nav className="navbar">
			<h1 className="title">TheMenuCompany</h1>
			<ul className="menu">
				<MenuItem label="Home" href="/" />
				<MenuItem label="About" href="/about/" />
				<MenuItem label="Blog" href="/blog/" />
			</ul>
		</nav>
	  );
	}
}

class MenuItem extends Component {
	render() {
		return (
		  <li className="menu-item">
			<a className="menu-link" href={this.props.href}
			  >{this.props.label}
			</a>
		  </li>
		);
	}
}

export default App;

Functional Component Equivalent

jsx
import "./App.css";

function App() {
	return (
		<main>
		  <Menu />
		</main>
	);
}

function Menu() {
	return (
		<nav className="navbar">
			<h1 className="title">TheMenuCompany</h1>
			<ul className="menu">
				<MenuItem label="Home" href="/" />
				<MenuItem label="About" href="/about/" />
				<MenuItem label="Blog" href="/blog/" />
			</ul>
		</nav>
	);
}

function MenuItem(props) {
	return (
		<li className="menu-item">
			<a className="menu-link" href={props.href}>
				{props.label}
			</a>
		</li>
	);
}

export default App;

Functional components are just JavaScript functions that return JSX. They accept props as an argument and return a representation of the UI.

Advanced Functional Patterns

Destructuring Props

Instead of accessing props via props.property, destructuring makes components more readable:

jsx
function MenuItem({ href, label }) {
	return (
		<li className="menu-item">
			<a className="menu-link" href={href}>
				{label}
			</a>
		</li>
	);
}

Alternatively, destructuring can be done inside the function:

jsx
function MenuItem(props) {
	const { href, label } = props;
	return (
		<li className="menu-item">
			<a className="menu-link" href={href}>
				{label}
			</a>
		</li>
	);
}

Default Property Values

Functional components allow you to specify default values directly in the function signature using destructuring:

jsx
function MenuItem({ label, href, target = "_self" }) {
	return (
		<li className="menu-item">
			<a className="menu-link" href={href} target={target}>
				{label}
			</a>
		</li>
	);
}

Now you can omit the target when calling the component:

jsx
<MenuItem label="Home" href="/" />  // Uses target="_self" by default
<MenuItem label="Blog" href="/blog/" target="_blank" />

Pass-Through Props and Rest/Spread Syntax

Often, you may want to allow additional props (e.g., id, aria-label) to be passed without explicitly listing them. This is where rest and spread syntax comes in.

jsx
function MenuItem({ label, href, target = "_self", ...rest }) {
	return (
		<li className="menu-item">
			<a className="menu-link" href={href} target={target} {...rest}>
				{label}
			</a>
		</li>
	);
}

Use like this:

jsx
<MenuItem label="About" href="/about/" id="about-link" />
<MenuItem label="Blog" href="/blog/" target="_blank" id="blog-link" />

Now any extra props (id, aria-label, etc.) will be automatically passed to the <a> element.

Using Arrow Functions and Expressions

You can define components using function expressions or arrow functions:

jsx
const Menu = () => {
	return <nav />;
	};

Or even inline:

jsx
const App = function () {
	const EmptyMenu = () => <nav />;
	return (
		<main>
			<EmptyMenu />
		</main>
	);
};

Any function that returns JSX can be treated as a React component.

Functional vs Class-Based: A Comparison

FeatureClass ComponentFunctional Component
SyntaxES6 ClassesJavaScript functions
Statethis.state & this.setState()useState() hook
LifecycleLifecycle methods (componentDidMount)useEffect()
ReadabilityMore verboseMore concise
ReusabilityDifficult without mixinsEasy with custom hooks
Error BoundariesSupportedNot natively supported

Benefits of Functional Components

  • More concise and readable

  • Easier to test

  • Works well with React Hooks

  • No need to bind methods or deal with this

  • Encourages pure functions

Disadvantages

There are no inherent downsides to using functional components. However:

  • Some legacy features like error boundaries still require class-based components.

  • Some developers might be more familiar or comfortable with class components, especially in older teams or projects.

Special Case: Error Boundaries

Error boundaries are React components that catch JavaScript errors anywhere in their child component tree and display a fallback UI.

As of now, error boundaries must be implemented using class components:

jsx
class ErrorBoundary extends React.Component {
	constructor(props) {
		super(props);
		this.state = { hasError: false };
	}

	static getDerivedStateFromError(error) {
		return { hasError: true };
	}

	componentDidCatch(error, info) {
		// Log error
	}

	render() {
		if (this.state.hasError) {
			return <h1>Something went wrong.</h1>;
		}
		return this.props.children;
	}
}

Functional components are now the preferred approach in modern React development due to their simplicity, flexibility, and the power of hooks.

While class components still have their place—especially for legacy reasons or rare features—functional components are the future of React.


Made with ❤️ for students, by a fellow learner.