How to Create a Simple React Component
Advertisement
🧩 Scenario
Architecture Walkthrough
Anatomy of a Function Component
A React function component is a JavaScript function that returns JSX. The function receives a single argument (conventionally named props) which is an object containing all attributes passed to the component by its parent. The return value describes what should appear on screen.
Three rules make a function a valid React component. First, its name must start with an uppercase letter. JSX uses this convention to distinguish between HTML elements and React components: lowercase tags map to DOM elements, uppercase tags map to React components. Second, it must return either JSX, null, or another renderable value. Third, the returned JSX must have a single root element, or use a <Fragment> to group multiple siblings without adding a DOM node.
JSX and React.createElement
JSX is not a browser feature. Babel (or the React compiler in modern toolchains) transforms every JSX expression into a React.createElement(type, props, ...children) call. The type is either a string (for DOM elements like 'div') or a component function (for React components like Greeting). This is why the uppercase convention matters at a mechanical level: if greeting is lowercase, React.createElement('greeting', ...) creates an unknown HTML element; if Greeting is uppercase, React.createElement(Greeting, ...) calls your function.
Props Are Read-Only
Props flow from parent to child and are immutable inside the component. The component reads them, renders from them, and must never modify them. This unidirectional data flow is a core React design principle: it makes the source of truth for each piece of data unambiguous. If the component needs to change something, it should either call a callback prop provided by the parent or manage its own internal state with useState.
Key Code Explained
// Basic component with typed props
interface UserCardProps {
name: string;
role: string;
avatarUrl?: string;
}
function UserCard({ name, role, avatarUrl }: UserCardProps) {
// Destructuring in the signature avoids repeatedly writing props.name
return (
<div className="user-card">
{avatarUrl && <img src={avatarUrl} alt={`${name}'s avatar`} />}
<h2>{name}</h2>
<p>{role}</p>
</div>
);
}
// JSX compiles to:
// React.createElement('div', { className: 'user-card' },
// avatarUrl && React.createElement('img', { src: avatarUrl, alt: `${name}'s avatar` }),
// React.createElement('h2', null, name),
// React.createElement('p', null, role)
// )
// Usage
function App() {
return (
<UserCard
name="Ghazi Khan"
role="Frontend Developer"
avatarUrl="/avatars/ghazi.png"
/>
);
}
// Returning multiple siblings without a wrapper DOM node
function TagList({ tags }: { tags: string[] }) {
return (
<>
<h3>Tags</h3>
<ul>
{tags.map((tag) => (
<li key={tag}>{tag}</li>
))}
</ul>
</>
);
}
// <> </> is shorthand for <React.Fragment> </React.Fragment>
// No extra <div> is added to the DOM
// Common JSX differences from HTML:
// class -> className (class is a reserved JS keyword)
// for -> htmlFor (for is a reserved JS keyword)
// onclick -> onClick (camelCase for all event handlers)
// style="color:red" -> style={{ color: 'red' }} (object, not string)
The key prop on the <li> in the TagList example is not a custom prop: React consumes it internally for reconciliation. It is never accessible as props.key inside the component. Each key must be unique among siblings so React can identify which item changed, was added, or was removed when the list re-renders.
Tradeoffs
| Return approach | DOM nodes added | When to use |
|---|---|---|
| Single root element | 1 wrapper | When you need a container with layout or styling |
Fragment <>...</> | None | When you need siblings without a wrapper DOM node |
null | None | When the component should render nothing (conditional) |
What Interviewers Actually Check
- Whether you know that JSX compiles to
React.createElementand why capital letters matter - Whether you can destructure props in the function signature
- Whether you can explain the single-root rule and use Fragments correctly
- Whether you know that props are read-only and can explain why
- Whether you know the common JSX-HTML differences:
className,htmlFor, camelCase events
Follow-Up Questions
- What is the difference between a controlled and uncontrolled component?
- If a component receives an
onClickprop, is it a custom event handler or the native DOM event? How does React bridge the two? - How does
React.memoaffect a function component and when would you use it? - What is
childrenin props and how do you type it in TypeScript? - What is a default export vs named export for components and which convention is preferred?
Common Candidate Mistakes
- Writing a component name in lowercase and not understanding why the rendered output is wrong
- Returning sibling elements without a wrapper or Fragment and getting a "JSX expressions must have one parent element" error
- Accessing
props.keyinside a component and wondering why it isundefined - Writing
class=instead ofclassName=in JSX and not knowing why it fails - Modifying a prop value inside the component instead of lifting state or using a callback
Interview Readiness Checklist
Before you leave this question, make sure you can answer:
- Can you write a function component that receives and renders typed props?
- Can you explain what JSX compiles to and why a capital letter is required for component names?
- Can you explain the single-root-element rule and how Fragments solve it without adding DOM nodes?
- Can you destructure props in the function signature and provide a default value?
- Can you list three JSX differences from HTML and explain why each exists?
Summary
A React function component is a JavaScript function whose name starts with an uppercase letter, receives a props object, and returns JSX. JSX is transformed by Babel into React.createElement calls, where the type argument is either a string for DOM elements or a function reference for React components. The capital letter convention is what allows the JSX transform to make this distinction.
Props flow from parent to child as an immutable object. A component reads props and renders from them but never modifies them. This unidirectional data flow is the foundation of React's predictable rendering model. When a component needs to change something, it does so through its own state or by calling a callback received as a prop.
The single-root-element rule in JSX is a consequence of React.createElement taking one type argument. When you need to return multiple siblings, React.Fragment (or the <>...</> shorthand) groups them into a single return value without adding any real DOM node, keeping the component output clean and the DOM structure intentional.
Why must React component names start with a capital letter?
JSX uses the case of the tag name to decide whether it is a built-in HTML element (lowercase) or a React component (uppercase). <button> renders an HTML button; <Button> looks up the Button identifier in scope and calls it as a React component.
Advertisement
Stay Updated
Get the latest frontend challenges, interview questions and tutorials delivered to your inbox.
Advertisement