React Elements vs Components
Understanding the distinction between React elements and components is fundamental to React development. While they are related, they serve different purposes and have different characteristics.
Table of Contents
What are React Elements?
React elements are the smallest building blocks of React applications. They are plain objects that describe what you want to see on the screen.
Characteristics of React Elements:
- Immutable: Once created, they cannot be changed
- Lightweight: Simple JavaScript objects
- Platform-agnostic: Can represent DOM elements, native components, or custom components
- Serializable: Can be converted to JSON
Element Structure:
// React element object structure
const element = {
type: 'div',
props: {
className: 'container',
children: 'Hello, World!'
}
};
Creating Elements:
// Using React.createElement
const element = React.createElement(
'div',
{ className: 'container' },
'Hello, World!'
);
// Using JSX (compiled to React.createElement)
const element = <div className="container">Hello, World!</div>;
What are React Components?
React components are functions or classes that return React elements. They are reusable pieces of UI that can accept inputs (props) and maintain internal state.
Characteristics of React Components:
- Reusable: Can be used multiple times with different props
- Stateful: Can maintain internal state
- Composable: Can contain other components
- Lifecycle: Have lifecycle methods (class components) or effects (functional components)
Component Types:
Functional Components:
// Simple functional component
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Arrow function component
const Welcome = (props) => {
return <h1>Hello, {props.name}!</h1>;
};
// With destructuring
const Welcome = ({ name }) => {
return <h1>Hello, {name}!</h1>;
};
Class Components:
class Welcome extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
Key Differences
| Aspect | React Elements | React Components |
|---|---|---|
| Type | Plain JavaScript objects | Functions or classes |
| Mutability | Immutable | Mutable (can change state) |
| Reusability | Not reusable | Highly reusable |
| State | No internal state | Can have internal state |
| Props | Direct properties | Accept props as parameters |
| Lifecycle | No lifecycle | Have lifecycle methods/effects |
| Complexity | Simple objects | Can be complex with logic |
| Creation | React.createElement() or JSX |
Function/class definitions |
Element Example:
// This is a React element
const element = <div className="container">Hello World</div>;
// It's immutable - you can't change it after creation
// element.props.className = 'new-class'; // This won't work
Component Example:
// This is a React component
function Greeting({ name, isLoggedIn }) {
// Can have logic
const message = isLoggedIn ? `Welcome back, ${name}!` : 'Please log in.';
// Can have state (in functional components with hooks)
const [count, setCount] = useState(0);
// Returns a React element
return (
<div className="greeting">
<h1>{message}</h1>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>
Increment
</button>
</div>
);
}
Usage Examples
Elements in Practice:
// Creating elements directly
const headerElement = React.createElement(
'header',
{ className: 'app-header' },
React.createElement('h1', null, 'My App'),
React.createElement('nav', null, 'Navigation')
);
// Using JSX for elements
const buttonElement = (
<button className="btn btn-primary" onClick={() => alert('Clicked!')}>
Click Me
</button>
);
// Rendering elements
ReactDOM.render(buttonElement, document.getElementById('root'));
Components in Practice:
// Functional component
function UserCard({ user }) {
return (
<div className="user-card">
<img src={user.avatar} alt={user.name} />
<h3>{user.name}</h3>
<p>{user.email}</p>
</div>
);
}
// Using the component
const user = { name: 'John Doe', email: 'john@example.com', avatar: 'avatar.jpg' };
const userCardElement = <UserCard user={user} />;
// Rendering the component
ReactDOM.render(userCardElement, document.getElementById('root'));
Nesting Components:
// Parent component
function App() {
return (
<div className="app">
<Header />
<MainContent />
<Footer />
</div>
);
}
// Child components
function Header() {
return <header className="header">Header</header>;
}
function MainContent() {
return <main className="main">Main Content</main>;
}
function Footer() {
return <footer className="footer">Footer</footer>;
}
JSX and Elements
JSX Compilation:
// JSX code
const element = (
<div className="container">
<h1>Hello World</h1>
<p>This is JSX</p>
</div>
);
// Gets compiled to:
const element = React.createElement(
'div',
{ className: 'container' },
React.createElement('h1', null, 'Hello World'),
React.createElement('p', null, 'This is JSX')
);
JSX with Components:
// JSX with custom component
const element = <Welcome name="John" />;
// Gets compiled to:
const element = React.createElement(Welcome, { name: 'John' });
Conditional Rendering:
// Conditional elements
function ConditionalRender({ isLoggedIn }) {
if (isLoggedIn) {
return <h1>Welcome back!</h1>; // Returns a React element
} else {
return <h1>Please log in.</h1>; // Returns a React element
}
}
// Conditional rendering with ternary
function Greeting({ isLoggedIn, name }) {
return (
<div>
{isLoggedIn ? (
<h1>Welcome back, {name}!</h1>
) : (
<h1>Please log in.</h1>
)}
</div>
);
}
Best Practices
1. Use Components for Reusable Logic:
// Good: Component for reusable UI
function Button({ children, onClick, variant = 'primary' }) {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{children}
</button>
);
}
// Usage
<Button onClick={handleClick}>Click Me</Button>
<Button variant="secondary" onClick={handleCancel}>Cancel</Button>
2. Keep Elements Simple:
// Good: Simple elements for one-off use
const loadingElement = <div className="loading">Loading...</div>;
// Good: Component for complex, reusable logic
function LoadingSpinner({ size = 'medium' }) {
return (
<div className={`loading-spinner loading-spinner--${size}`}>
<div className="spinner"></div>
<p>Loading...</p>
</div>
);
}
3. Use Elements for Static Content:
// Good: Elements for static content
const staticHeader = (
<header className="static-header">
<h1>Company Name</h1>
<p>Tagline</p>
</header>
);
// Good: Components for dynamic content
function DynamicHeader({ title, subtitle }) {
return (
<header className="dynamic-header">
<h1>{title}</h1>
<p>{subtitle}</p>
</header>
);
}
4. Proper Component Structure:
// Good: Component that returns elements
function UserList({ users }) {
return (
<div className="user-list">
{users.map(user => (
<UserCard key={user.id} user={user} />
))}
</div>
);
}
// Good: Element for simple rendering
const emptyState = (
<div className="empty-state">
<p>No users found</p>
</div>
);
Common Interview Questions
Q: What is the difference between a React element and a React component?
- React elements are plain objects that describe what to render, while React components are functions or classes that return React elements and can have state and lifecycle.
Q: Are React elements mutable?
- No, React elements are immutable. Once created, they cannot be changed. To update the UI, you create new elements.
Q: How does JSX relate to React elements?
- JSX is syntactic sugar that gets compiled to
React.createElement()calls, which create React elements.
Q: Can you have state in a React element?
- No, React elements are plain objects and cannot have state. Only React components can have state.
Q: What does a React component return?
- A React component returns React elements (or null). These elements can be simple DOM elements or other components.
Q: How do you create React elements without JSX?
- Using
React.createElement(type, props, ...children)function.
Q: What is the relationship between components and elements?
- Components are functions/classes that return elements. Elements are what actually get rendered to the DOM.
Q: Can you pass props to React elements?
- Yes, props are passed as the second argument to
React.createElement()and become thepropsproperty of the element object.
Summary
- React Elements are immutable, lightweight objects that describe what to render
- React Components are functions or classes that return React elements and can have state and lifecycle
- Elements are created using
React.createElement()or JSX syntax - Components are reusable, can accept props, and can maintain internal state
- JSX gets compiled to
React.createElement()calls, creating React elements - Use elements for simple, static content; use components for reusable, dynamic UI
- Understanding this distinction is crucial for effective React development
Interview angle
- “Element or component?” - a component is a function; an element is the plain object it returns describing what to render.
<Foo />creates an element;Foois the component. Elements are immutable descriptions, not DOM nodes and not instances. - “Why does that distinction matter in practice?” - because creating an element is cheap and does nothing. Passing
<Foo />as a prop is fine; React decides when and whether to callFoo. It also explains why you passFoo(not<Foo />) where a component type is expected. - “Why does defining a component inside another component remount it?” - each render creates a new function identity, so reconciliation sees a different element type and tears down the subtree, losing its state. Define components at module level.