React Const vs Function Component: Syntax Differences and When to Use Each

Both function declarations and const arrow functions create identical React components at runtime, but they differ significantly in hoisting behavior, refactoring ergonomics, and lexical this binding.

When working with the facebook/react repository, understanding the nuances of react const vs function component declarations helps teams write more maintainable code. While the React reconciler treats both styles identically during the render phase, JavaScript’s lexical scoping rules create practical differences that affect debugging, module organization, and future architectural changes.

Hoisting Behavior and Definition Order

Function declarations are hoisted to the top of their scope, allowing you to reference the component before its definition appears in the file. This enables patterns like circular imports or forward references without temporal dead zone errors.

In packages/react/src/__tests__/ReactStrictMode-test.internal.js at line 32, the React team uses function declarations that can be referenced anywhere in the module regardless of physical location.

Conversely, const-bound arrow functions are not hoisted. The variable exists only after the assignment expression executes, creating a temporal dead zone. Referencing a const component before its definition results in a runtime ReferenceError.

// src/components/Circular.js
export default () => <Header />;   // OK – Header is hoisted

function Header() {
  return <h1>Header</h1>;
}
// src/components/CircularConst.js
export default () => <Header />;   // ❌ Throws “Header is not defined”

const Header = () => <h1>Header</h1>;

Debugging and Display Name Inference

React DevTools and error boundaries rely on display names to identify components in stack traces. Both declaration styles provide this metadata automatically, but through different mechanisms.

  • Function declarations: React reads the name property of the function object directly.
  • Const arrows: React infers the name from the variable identifier to which the arrow function is assigned.

In practice, both approaches yield readable labels in development. However, aggressive minifiers may mangle const variable names more destructively than function declarations, potentially obscuring component identities in production builds.

Refactoring and Maintainability

The choice between syntaxes impacts long-term code evolution, particularly when migrating between component types.

Migration to Class Components

Function declarations simplify conversion to class components because they already follow the structural pattern of methods. To convert function MyComponent() to a class, you only need to add extends React.Component and wrap the body in a render() method.

Converting a const arrow function requires rewriting the assignment into a class body and method definition, introducing more mechanical changes and potential merge conflicts.

Inline and Callback Usage

Const arrow functions excel when defining inline components passed as props or rendered within map iterations. The concise syntax reduces boilerplate when the component is tightly coupled to its usage site, as seen in fixture applications like fixtures/fizz/src/App.js where lightweight utility components appear adjacent to their consumption.

The this Binding Nuance

Arrow functions capture the lexical this of their surrounding scope, while function declarations receive their own this context (typically undefined in strict mode).

In React function components, this is never meaningful—hooks and closures replace instance state. However, arrow functions may hide accidental this usage during refactoring, silently capturing an outer this rather than throwing an error that would alert you to architectural drift. Function declarations fail fast with explicit errors when this is accessed incorrectly.

Practical Code Examples from the React Source

The React codebase demonstrates both patterns in production test suites and internal fixtures.

Function Declaration Style

This pattern appears in packages/react/src/__tests__/ReactStrictMode-test.internal.js at line 32, demonstrating the classic hoisted approach:

// src/components/Greeting.js
function Greeting({name}) {
  return <p>Hello, {name}!</p>;
}
export default Greeting;

Const Arrow Function Style

Modern ES-6 syntax appears in packages/react/src/__tests__/ReactProfiler-test.internal.js at line 614, showing the expression-based approach:

// src/components/Farewell.js
export const Farewell = ({name}) => <p>Good‑bye, {name}.</p>;

Both components participate identically in the React profiler and strict mode tests, confirming runtime parity despite syntactic divergence.

Summary

  • React renders function declarations and const arrow components identically, with no measurable performance difference between the two styles.
  • Function declarations support hoisting, enabling flexible file organization and circular dependencies that would break with const expressions.
  • Function declarations provide a cleaner migration path to class components if legacy lifecycle methods become necessary.
  • Arrow functions capture lexical this, which provides no benefit in React function components and may mask programming errors.
  • Choose function declarations for top-level exported components and arrow functions for tightly scoped inline utilities, maintaining consistency with surrounding code in the facebook/react repository.

Frequently Asked Questions

Is there a performance difference between const and function components?

No measurable runtime difference exists between the two declaration styles. The JavaScript engine treats both as ordinary function objects, and React’s reconciler does not distinguish between them during the diffing or commit phases. Any performance impact from syntax choice is purely theoretical and negligible in production applications.

Why does my const component throw "not defined" when my function component works?

Const declarations are not hoisted, meaning the identifier does not exist until the assignment statement executes. If you reference a const component above its definition—such as in a default export or early return statement—you encounter a temporal dead zone error. Function declarations are hoisted to the top of their containing scope, making them available throughout the entire module regardless of declaration position.

Which style does the React core team prefer?

The facebook/react repository uses both styles interchangeably based on context. Function declarations dominate in test files and formal component modules, while arrow functions appear frequently in fixtures and inline utility components. The team prioritizes consistency within a given file over repository-wide uniformity, choosing the syntax that best fits the specific use case and surrounding code patterns.

Can I mix both styles in the same project?

Yes. Mixing function declarations for primary components and const arrows for inline utilities is a common and valid pattern. The key is maintaining local consistency—if a file predominantly uses const for other assignments, using a const arrow function for components preserves visual rhythm. Conversely, files emphasizing traditional JavaScript patterns benefit from function declarations throughout.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →