React Fundamentals: Components, JSX, State, and Re-rendering

Why did developers create React when JavaScript already existed?
JavaScript could already change a webpage — grab an element, update its text, toggle a class. So why did an entire library get built on top of it?
Because changing one element is easy. Keeping a hundred interconnected pieces of UI in sync, correctly, as an application grows is not. React wasn’t invented to replace JavaScript — it was invented to replace a specific, painful way of thinking about UI updates. This guide builds that new mental model from the ground up: JSX, components, props, state, and the re-rendering cycle that ties them all together.
1. Why React Exists
Problems with traditional DOM manipulation
Before React, building an interactive UI usually meant manually finding elements and mutating them directly:
document.getElementById("cart-count").innerText = newCount;
document.getElementById("cart-icon").classList.add("bounce");This works for small pages. It becomes fragile fast in larger ones — every UI update needs its own hand-written instructions for exactly which element to find and exactly how to change it, and it’s easy for the actual DOM to drift out of sync with what your data says it should be.
Building complex user interfaces
A real application — a dashboard, a social feed, an e-commerce cart — is really dozens of small, interconnected UI updates happening constantly. Coordinating all of it by hand, imperatively, becomes its own significant engineering problem, separate from the actual features being built.
Reusable UI components
Traditional DOM code also doesn’t naturally encourage reusable pieces. Need three product cards that look and behave identically? Without a component model, you’re often copying and adapting the same DOM logic three times.
Why React became popular
React’s core idea was simple but powerful: describe what the UI should look like for a given set of data, and let React figure out how to update the actual DOM to match. Developers stopped writing step-by-step DOM instructions and started writing UI as a function of data.
React’s component-driven approach
React organizes UI into small, self-contained, reusable components — each responsible for describing one part of the interface. This single shift is the foundation everything else in this guide builds on.

2. Understanding JSX
What JSX is
JSX is a syntax extension for JavaScript that lets you write HTML-like markup directly inside your JavaScript code:
const element = <h1>Hello, Aarav!</h1>;It looks like HTML, but it’s not HTML — it’s a JavaScript expression that ultimately becomes a description of UI.
Why JSX was introduced
Before JSX, describing UI structure and the logic that drives it lived in separate files and separate mental contexts — markup here, behavior there. JSX lets structure and logic live together, in the same component, because in React’s model, they genuinely belong together: the markup depends directly on the data and logic around it.
JSX vs HTML
JSX looks nearly identical to HTML, but with a few real differences: class becomes className, every tag must be properly closed (including self-closing tags like <img />), and — crucially — JavaScript expressions can be embedded directly inside it.
Embedding JavaScript inside JSX
Any JavaScript expression can be dropped into JSX using curly braces:
function Greeting({ name }) {
return <h1>Hello, {name}!</h1>;
}function ProductCard({ product }) {
return (
<div className="card">
<h2>{product.name}</h2>
<p>${product.price.toFixed(2)}</p>
</div>
);
}JSX compilation process (high level)
Browsers don’t understand JSX natively. A build tool (like Babel) compiles it into plain JavaScript function calls before it ever reaches the browser:
<h1>Hello, {name}!</h1>compiles down to something conceptually like:
React.createElement("h1", null, "Hello, ", name, "!");You never have to write that second form by hand — JSX is simply a much more readable way to express the exact same thing.

3. Components in React
What components are
A component is a self-contained, reusable piece of UI — a JavaScript function that returns JSX describing what should appear on screen.
Reusable UI building blocks
Just like a physical UI is built from buttons, cards, and headers, a React application is built from <Button />, <ProductCard />, and <Header /> components — each one focused on a single, well-defined piece of the interface.
Function components
Modern React components are simply functions that return JSX:
function ProductCard({ product }) {
return (
<div className="card">
<h2>{product.name}</h2>
<p>${product.price}</p>
</div>
);
}Component composition
Components combine to build larger UI, the same way HTML elements nest inside each other — except now each piece is a named, reusable, purpose-built block:
function Dashboard() {
return (
<div>
<Header />
<ProductList />
<Footer />
</div>
);
}Breaking large UIs into smaller pieces
A social media post isn’t one giant block of markup — it naturally decomposes into an Avatar, an Author name, PostContent, and ActionButtons (like, comment, share). Recognizing these natural boundaries is one of the core skills of building well-structured React applications.

4. Props in React
What props are
Props (short for “properties”) are how data is passed into a component — conceptually similar to how HTML attributes configure an element, but far more flexible, since props can be any JavaScript value: strings, numbers, objects, even other components.
Passing data between components
function ProductCard({ name, price }) {
return (
<div className="card">
<h2>{name}</h2>
<p>${price}</p>
</div>
);
}
function App() {
return <ProductCard name="Wireless Mouse" price={24.99} />;
}Parent-child communication
Props always flow in one direction: from parent to child. App (the parent) hands data down to ProductCard (the child). This one-directional flow is intentional — it keeps data flow predictable and easy to trace, even in a large tree.
Read-only nature of props
A component receiving props must never modify them directly — props belong to the parent that passed them, and treating them as read-only keeps the data flow one-directional and predictable throughout the tree.
Building reusable components with props
The same ProductCard component can render an unlimited variety of products just by receiving different props — this reusability is exactly what makes components so powerful:
<ProductCard name="Wireless Mouse" price={24.99} />
<ProductCard name="Mechanical Keyboard" price={89.99} />
<ProductCard name="USB-C Hub" price={34.50} />
5. State in React
What state is
State is data that a component owns and manages internally — and, critically, data that can change over time in response to user interaction, unlike props, which a component only receives.
Why state exists
Props alone can’t represent things like “is this dropdown currently open,” “what has the user typed so far,” or “how many items are in the cart” — data that originates inside a component and changes as the user interacts with it.
Local component state
React’s useState hook lets a function component hold its own piece of state:
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}State updates
Calling the state-setter function (setCount, in the example above) doesn't just update a variable — it tells React "this component's data has changed, please update the UI to match." This is the trigger for the re-rendering cycle explored next.
State-driven UI
This is the essence of React’s model: the UI you see is always a direct reflection of the current state. Change the state, and React takes care of updating the UI to match — you never manually touch the DOM yourself.

6. Understanding Re-rendering
What causes a re-render
A component re-renders — meaning React re-runs its function to get an updated UI description — when its own state changes, when its props change, or when its parent re-renders.
State changes and UI updates
Every call to a state-setter function schedules a re-render. React re-runs the component function with the new state value, gets back new JSX, and updates the actual DOM to match — automatically, without you writing any manual DOM instructions.
Props changes and re-rendering
If a parent passes a new value as a prop, the child receiving that prop re-renders too, since its output may now depend on different data.
Component lifecycle from a high level
At a beginner-friendly level, every component moves through three broad phases: mount (it first appears), update (it re-renders in response to state/prop changes), and unmount (it’s removed from the UI). Most day-to-day React work happens in the update phase.
Why React updates the UI automatically
This is the payoff of the entire model: you never write “find this element and change its text.” You write “here’s what the UI looks like, given this state” — and React handles translating every state change into the correct, minimal DOM updates behind the scenes.

7. React’s Declarative Nature
Imperative vs declarative programming
Imperative code describes how to do something, step by step: “find this element, change its text, add this class.” Declarative code describes what the result should look like, and leaves the “how” to something else: “this heading should show the user’s name.”
Describing UI instead of manipulating UI
A React component never says “change the DOM element’s text.” It says “given this data, the UI looks like this” — and lets React work out exactly which DOM operations are needed to make that true.
// Imperative (traditional DOM manipulation)
const heading = document.getElementById("heading");
heading.innerText = isLoggedIn ? "Welcome back!" : "Please log in";
// Declarative (React / JSX)
<h1>{isLoggedIn ? "Welcome back!" : "Please log in"}</h1>Benefits of declarative rendering
- The UI code directly reflects the current data — no separate mental model to track “what did I already change on the page”
- Far easier to reason about and debug, since the output is a predictable function of the input state
- Components naturally stay easier to test, since “given this state, what does it render?” is a clean, isolated question
Predictable UI updates
Because the UI is always described from the current data rather than incrementally patched by hand, there’s no risk of the actual DOM silently drifting out of sync with what your application believes is true.

8. Component Tree Architecture
Parent components
A parent component renders and controls one or more child components, typically passing data down to them as props.
Child components
A child component receives data from its parent and focuses on rendering its own specific piece of the UI — usually unaware of anything happening outside itself.
Data flow
Data in a standard React tree flows downward, from parent to child, via props — a predictable, traceable direction that makes it much easier to reason about where any given piece of data actually comes from.
Component hierarchy
A real application forms a tree, much like nested folders — a Dashboard might contain a Sidebar and a MainPanel; MainPanel might contain several Widget components; each Widget might contain a Header and a Chart.

Application structure
Thinking of an application as a tree of components — rather than a flat collection of DOM elements — is the structural shift that makes large UIs manageable: each branch of the tree can be understood, built, and tested largely on its own.
9. Common Beginner Mistakes
Mutating state directly
// Wrong: mutating state directly
count = count + 1;
// Correct: using the setter function
setCount(count + 1);Directly changing a state variable doesn’t tell React anything happened — since React only knows to re-render when you call the setter function it gave you. Direct mutation silently breaks the entire update model.
Confusing props and state
A simple test: if the data is handed to the component from the outside, it’s a prop. If the component manages and changes it internally, it’s state. Mixing the two up — trying to reassign a prop, or duplicating a prop into local state unnecessarily — leads to confusing, hard-to-trace bugs.
Overusing state
Not every piece of data needs to live in state. A value that can be directly calculated from existing props or state (like a formatted string, or a filtered list) usually shouldn’t be duplicated into its own state — it should simply be computed during render.
Large components
A single component trying to handle layout, data fetching, and five different pieces of UI logic becomes hard to read, test, and reuse. Breaking it into smaller, focused components — the same instinct behind good function design in any language — keeps things manageable.
Poor component organization
Placing every component in one giant file, or naming them inconsistently, makes a codebase hard to navigate as it grows. Organizing components by feature or domain (rather than dumping everything in one flat folder) pays off quickly once a project passes a handful of components.
10. Building Applications with Components
Thinking in components
The most valuable React skill isn’t memorizing hooks — it’s learning to look at a design (a dashboard, a product page, a social feed) and instinctively see it as a tree of components: what’s a component, what’s a prop, what’s local state.
Reusable design patterns
A well-designed Card, Button, or Modal component, built once with sensible props, can be reused dozens of times across an application — this compounding reusability is a large part of why component-driven UI scales so well.
Component architecture
Good architecture means drawing sensible boundaries: which pieces are truly reusable and generic (a Button), and which are specific to one feature (a CheckoutSummary) — and organizing the codebase to reflect that distinction.
Scaling React applications
As an application grows, the component tree grows with it. The fundamentals in this guide — components, JSX, props, state, and the re-render cycle — remain exactly the same at any scale; what changes is how deliberately you structure the tree and manage where state actually lives (a topic worth its own deeper guide).
Real-world examples brought together
Final Takeaway
React’s entire model rests on a simple reframe: instead of telling the browser how to change, you describe what the UI should look like for the current data — and let React handle the rest. Components break that description into small, reusable pieces. Props carry data down a predictable, one-directional tree. State holds the data that changes over time. And re-rendering is simply React keeping the UI honest with whatever state and props currently say is true. Everything more advanced in React — Context, memoization, custom hooks — is built directly on top of these five ideas.
Frequently Asked Questions
Do I need to learn class components to use React today?
> No. Modern React is built around function components and hooks like useState. Class components still exist in older codebases, but new React code is written with functions almost exclusively.
Is JSX required to use React?
> Technically no — JSX compiles down to plain React.createElement() calls, which can be written directly. In practice, virtually every React codebase uses JSX because it's dramatically more readable.
What’s the simplest way to tell props and state apart?
> Ask where the data comes from. If a component receives it from its parent, it’s a prop. If the component creates and updates it itself, it’s state.
Why does my component re-render even when I didn’t change anything in it?
> Most often, its parent re-rendered, and by default, every child re-renders along with its parent — even if that specific child’s own props stayed the same. This is normal in small apps and only becomes worth addressing in larger, performance-sensitive components.
Originally published by Mr Madhukar
Read the complete article on Medium with full formatting & reader responses.