reactjs_fundamental.jpg

19-08-2025

ReactJS Fundamentals: From Core Concepts to Your First App

React has become a staple in modern web development, powering user interfaces at companies like Facebook, Netflix, and Airbnb. Yet, for beginners, jumping into React can feel like trying to learn a new language while juggling.

This guide is designed to answer three key questions before we start coding:

  • Why React?
  • How does it work?
  • What can you build with it?

By the end, you'll not only understand React's core principles but also create a small working app a Counter to cement your knowledge.

Why ReactJs?

Before React, front-end development largely followed an imperative programming style—telling the browser step-by-step how to update the UI.


The Imperative Way (Pre-React)
document.addEventListener('DOMContentLoaded', function() { 
const p = document.createElement('p'); 
p.textContent = 'This paragraph was added imperatively with JavaScript.'; 
document.getElementById('content').appendChild(p); 
});

This works fine for small tasks but becomes painful when managing:

  • Multiple UI elements
  • Frequent updates
  • Complex state changes

The Declarative Way (React's Approach)

React embraces declarative programming—you describe what the UI should look like, and React figures out how to update it efficiently.

import React from 'react'
function App() {
return (
<div id="content"> <p>This paragraph was added declaratively with React.</p> </div>
);}
export default App;

With React:

  • You declare the desired state of your UI
  • React automatically updates it when data changes
  • You focus on logic, not DOM manipulation

Setting Up Your Environment


Prerequisites

Before diving in, make sure you know:

  • HTML tags & structure
  • CSS styling basics
  • JavaScript fundamentals (variables, functions, arrays, objects)

Install Node.js and npm

1. Download Node.js from nodejs.org

2. Verify installation:
node -v
npm -v
Create Your First React App
We'll use Vite for a fast development setup:
npm create vite@latest my-react-app
cd my-react-app
npm install
npm run dev

Understanding the Project Structure

A well-organized React project follows specific patterns:


src/
├── components/
│ ├── Button.jsx
│ └── Header.jsx
├── hooks/
│ └── useCounter.js
├── pages/
│ └── Home.jsx
├── assets/
├── styles/
└── App.jsx
Key folders:
  • components/: Reusable UI components
  • hooks/: Custom React hooks
  • pages/: Top-level page components
  • assets/: Images, fonts, etc.
  • styles/: CSS files

JSX — Writing HTML in JavaScript

JSX (JavaScript XML) lets you write HTML-like syntax directly inside JS.


Rules to Remember:
  1. One parent/root element per return
  2. camelCase for attributes (className instead of class)
  3. Every tag must be closed (<img /> not <img>)
  4. Use curly braces for JavaScript expressions

Example:


function Greeting({ name }) {
return (
<div className="greeting-container">
<h1>Hello, {name}!</h1>
<p>Today is {new Date().toLocaleDateString()}</p>
</div>
)}


Components: The Building Blocks

Components are the heart of React. They're like custom HTML elements that encapsulate logic and UI.


Function Components (Recommended)
// Simple component
function Welcome() {
return <h1>Welcome to React!</h1>;
}
// Component with props
function UserCard({ name, email, role }) {
return (
<div className="user-card">
<h3>{name}</h3>
<p>{email}</p>
<span className="role">{role}</span>
</div>
);
}
// Using the component
function App() {
return (
<div>
<Welcome />
<UserCard name="John Doe" email="john@example.com" role="Developer" />
</div>
);}
Component Best Practices
  • Keep components small and focused — One responsibility per component
  • Use meaningful names — UserProfile not Component1
  • Extract reusable logic — Create custom hooks
  • Destructure props — Improves readability

// Good: Destructured props 
function Button({ text, onClick, variant = 'primary' }) {
   return ( 
    <button className={`btn btn-${variant}`} onClick={onClick} > {text}    </button>
  ); 
} 
// Usage
<Button text="Click me" onClick={handleClick} variant="secondary" />  


State: Making Components Dynamic

State is data that can change over time and belongs to a component. When state changes, React automatically re-renders the component.


The useState Hook

import React, { useState } from 'react';
function Counter() { 
 // Declare state variable 
  const [count, setCount] = useState(0); 
  // Event handlers
const increment = () => setCount(count + 1);  
const decrement = () => setCount(count - 1); 
const reset = () => setCount(0); 
return ( 
<div> 
<h2>Count: {count}</h2> 
<button onClick={increment}>+</button> 
<button onClick={decrement}>-</button> 
<button onClick={reset}>Reset</button> 
</div> 
); 
}

State vs Props
state_vs_props.png
Complex State Example

function TodoApp() { 
const [todos, setTodos] = useState([ 
{ id: 1, text: 'Learn React', completed: false }, 
{ id: 2, text: 'Build an app', completed: false }
 ]); 
const [inputText, setInputText] = useState(''); 
 const addTodo = () => { 
 if (inputText.trim()) { 
 setTodos([ 
 ...todos, 
{ id: Date.now(), text: inputText, completed: false }
 ]); 
 setInputText(''); 
}}; 
const toggleTodo = (id) => { 
setTodos(todos.map(todo =>  
todo.id === id  ? { ...todo, completed: !todo.completed } : todo  )); 
}; 
return ( 
<div> 
<input value={inputText} 
onChange={(e) => setInputText(e.target.value)} 
placeholder="Add a todo..."  />
 <button onClick={addTodo}>Add</button> 
<ul> 
{todos.map(todo => ( 
<li key={todo.id}> 
<span style={{   textDecoration: todo.completed ? 'line-through' : 'none'  }} onClick={() => toggleTodo(todo.id)} > 
{todo.text} 
</span> 
</li> ))} 
</ul>
</div>
 );
} 

Event Handling

React handles events using SyntheticEvents, which provide consistent behavior across browsers.

Common Event Handlers
function EventDemo() { 
const [message, setMessage] = useState(''); 
const handleClick = () => { alert('Button clicked!');  }; 
const handleSubmit = (e) => { 
 e.preventDefault(); // Prevent form submission 
console.log('Form submitted with:', message);  }; 
const handleInputChange = (e) => { 
setMessage(e.target.value); 
}; 
const handleKeyDown = (e) => { 
if (e.key === 'Enter') { 
console.log('Enter pressed!'); 
 }  }; 
return ( 
<form onSubmit={handleSubmit}>
 <input  type="text"  
value={message}  onChange={handleInputChange} 
onKeyDown={handleKeyDown} 
placeholder="Type something..." /> 
<button type="submit">Submit</button> 
<button type="button" onClick={handleClick}> Click Me</button> 
</form> 
); } 

Passing Arguments to Event Handlers
function ButtonList() { 
const handleClick = (buttonName) => { 
alert(`${buttonName} was clicked!`); 
}; 
return ( 
<div> 
<button onClick={() => handleClick('Home')}>Home</button> 
<button onClick={() => handleClick('About')}>About</button> 
<button onClick={() => handleClick('Contact')}>Contact</button> 
</div> 
 );
} 

Conditional Rendering

Conditional Rendering

Methods for Conditional Rendering
1.If/Else Statements
function Greeting({ isLoggedIn, username }) { 
if (isLoggedIn) { 
return <h1>Welcome back, {username}!</h1>; 
 } else { 
 return <h1>Please sign in.</h1>; 
}
}
2.Ternary Operator
function StatusMessage({ isOnline }) { 
 return ( 
<div> 
<span>Status: {isOnline ? 'Online' : 'Offline'}</span> 
</div> 
); 
} 
3. Logical && Operator 
function Notifications({ messages }) { 
return ( 
<div> 
{messages.length > 0 &&  <div>You have {messages.length} new messages!</div>  } 
</div> 
 ); 
} 
4. Switch Statement 
function UserRoleBadge({ role }) { 
const renderBadge = () => { 
switch (role) { 
case 'admin': 
return <span className="badge badge-red">Admin</span>;
case 'moderator': 
return <span className="badge badge-blue">Moderator</span>;
case 'user': 
return <span className="badge badge-green">User</span>; 
default:
 return <span className="badge badge-gray">Guest</span>; 
 } 
 }; 
return <div>{renderBadge()}</div>; 
} 

Lists and Keys

When rendering lists of elements, React requires each item to have a unique key prop.

Why Keys Are Important
  • Help React identify which items have changed
  • Optimize rendering performance
  • Prevent component state issues during re-renders

Basic List Rendering
function ShoppingList({ items }) {
  return ( 
 <ul> 
 {items.map(item => ( <li key={item.id}> {item.name} - ${item.price} </li> ))} 
</ul> 
); } 
// Usage 
const groceries = [ 
{ id: 1, name: 'Apples', price: 2.99 }, 
{ id: 2, name: 'Bread', price: 1.99 }, 
{ id: 3, name: 'Milk', price: 3.49 } 
]; 
<ShoppingList items={groceries} /> 

Advanced List with Actions
function TaskList({ tasks, onToggle, onDelete }) { 
 return ( 
<div> 
{tasks.map(task => ( <div key={task.id} className="task-item"> 
<input type="checkbox" checked={task.completed} onChange={() => onToggle(task.id)} /> 
<span className={task.completed ? 'completed' : ''}>  {task.title} </span> 
<button onClick={() => onDelete(task.id)}>  Delete </button> 
</div> 
 ))} 
</div>  );
} 

Key Best Practices

// ✅ Good: Use unique, stable IDs 
{items.map(item => ( <Item key={item.id} data={item} /> ))} 
// ❌ Avoid: Using array index when order can change 
{items.map((item, index) => ( <Item key={index} data={item} /> ))} 
// ✅ Acceptable: Index as key only when list is static 
{staticItems.map((item, index) => ( <Item key={index} data={item} /> ))} 

useEffect: Handling Side Effects

The useEffect hook lets you perform side effects in function components.


Basic useEffect Usage
import React, { useState, useEffect } from 'react'; 
function Timer() { 
const [seconds, setSeconds] = useState(0); 
useEffect(() => { 
const interval = setInterval(() => { 
setSeconds(prevSeconds => prevSeconds + 1); 
 }, 1000); 
 // Cleanup function 
 return () => clearInterval(interval);
 }, []); // Empty dependency array = runs once on mount 
return <div>Timer: {seconds} seconds</div>; 
} 

useEffect Dependency Patterns

1. Run on Every Render

 useEffect(() => { 
console.log('Runs after every render'); 
}); 

2. Run Only on Mount

useEffect(() => { 
console.log('Runs only once after mount'); }, []); // Empty dependency array 

3. Run When Specific Values Change

useEffect(() => { 
console.log('Runs when count changes'); }, [count]); // Dependency array with count 
Data Fetching with useEffect
function UserProfile({ userId }) { 
const [user, setUser] = useState(null); 
const [loading, setLoading] = useState(true); 
const [error, setError] = useState(null); 
useEffect(() => { const fetchUser = async () => { 
try { 
setLoading(true); 
const response = await fetch(`/api/users/${userId}`); 
if (!response.ok) { 
throw new Error('Failed to fetch user'); 
}
const userData = await response.json(); 
setUser(userData); 
 } catch (err) { 
setError(err.message); 
} finally { 
setLoading(false); 
} };
fetchUser(); 
}, [userId]); // Re-fetch when userId changes 
if (loading) return <div>Loading...</div>;
if (error) return <div>Error: {error}</div>; 
if (!user) return <div>User not found</div>; 
return ( 
<div> 
<h2>{user.name}</h2> 
<p>{user.email}</p> 
</div>
 ); } 

Virtual DOM & Reconciliation

React uses a Virtual DOM to optimize updates to the real DOM.


How It Works

1.Virtual DOM Creation: React creates a lightweight copy of the real DOM in memory

2.Diffing: When state changes, React compares the new Virtual DOM with the previous version

3.Reconciliation: React calculates the minimum changes needed

4.DOM Update: Only the changed elements are updated in the real DOM


The Diffing Algorithm

React's diffing algorithm makes two key assumptions:

  • Different element types produce different trees
  • Keys help identify which elements have changed, moved, or been removed

// This change will completely rebuild the subtree 
<div>   →    <span> 
<Counter />   <Counter /> 
</div>             </span> 
// This change will preserve the Counter component 
<div>          →    <div>
<Counter />      <Counter /> 
</div>              <Timer /> 
</div> 

Performance Benefits
  • Batched Updates: React batches multiple state changes
  • Efficient Rendering: Only necessary DOM manipulations
  • Predictable Updates: Deterministic rendering based on state

Styling in React

React offers multiple approaches to styling components.

1. CSS Stylesheets
styles.css 
.card { 
background: white; 
border-radius: 8px; 
padding: 16px; 
box-shadow: 0 2px 4px rgba(0,0,0,0.1); 
} 
.card-title { 
font-size: 1.25rem;
font-weight: bold; 
margin-bottom: 8px; 
} 
Component.jsx 
import './styles.css'; 
function Card({ title, children }) { 
return ( 
<div className="card"> 
<h2 className="card-title">{title}</h2> 
{children}
</div>
 );
} 

Styled Components (CSS-in-JS)
import styled from 'styled-components'; 
const StyledButton = styled.button` padding: 12px 24px; border: none; border-radius: 4px; cursor: pointer; font-size: 16px;  background-color: ${props => props.primary ? '#007bff' : '#6c757d'}; 
color: white; &:hover { opacity: 0.8;}`; 
function Button({ primary, children }) { 
return ( 
<StyledButton primary={primary}> {children}  </StyledButton> 
); 
} 

Best Practices


Component Design

1.Single Responsibility - Each component should have one clear purpose

2.Composition over Inheritance - Combine small components to create complex UIs

3.Props Interface Design - Make props clear and well-documented

4.Error Boundaries - Handle errors gracefully


State Management

1.Keep state local - Only lift state up when necessary

2.Use functional updates - setState(prev => prev + 1) instead of setState(count + 1)

3.Avoid deeply nested state - Flatten state structure when possible


Performance

1.Use React.memo for components that don't need frequent re-renders

2.Optimize useEffect dependencies - Be specific about what triggers effects

3.Implement proper key props - Help React optimize list rendering


Code Organization

1.Consistent naming - Use PascalCase for components, camelCase for functions

2.File structure - Group related files together

3.Import organization - External libraries first, then internal modules


What's Next?

Now that you understand React fundamentals, here are your next steps:

Intermediate Topics
  • React Router - Navigation between pages
  • Context API - Global state management
  • Custom Hooks - Reusable stateful logic
  • Error Boundaries - Graceful error handling

Advanced Topics
  • Performance Optimization - React.memo, useMemo, useCallback
  • State Management Libraries - Redux, Zustand
  • Testing - Jest, React Testing Library
  • TypeScript - Type safety for React

Build Projects
  • Todo List App
  • Weather Dashboard
  • Shopping Cart
  • Blog Platform

Conclusion

Congratulations! You've learned the fundamental concepts that power React applications:

✅ Declarative programming with JSX

✅ Component-based architecture

✅ State management with useState

✅ Event handling and user interactions

✅ Conditional rendering patterns

✅ List rendering with keys

✅ Side effects with useEffect

✅ Styling approaches in React

✅ Project structure best practices

React's component-based approach makes building complex UIs manageable by breaking them into smaller, reusable pieces. The declarative nature means you describe what you want, and React handles the how.

The counter app you built demonstrates core React concepts in action. From here, you can expand your skills by building more complex applications and exploring React's ecosystem.

Remember: React is a library, not a framework, which means you have the flexibility to choose additional tools as your projects grow. Start simple, practice regularly, and gradually add complexity as you become more comfortable with React's mental model. Happy coding!


avatar-icon.png

Written By

Rohit Pawar

Using AI in DevOps: Transforming the Developer Workflow

Artificial Intelligence (AI) is fundamentally reshaping how DevOps tea.......

Dhananjay Kala

2025-08-14

Next.js vs React.js: What Should You Choose?

In the world of modern web development, React.js and Next.js are two o.......

Varun Patel

2025-08-14

Untitled-1.jpg
About Us

Learn about OpenSpace Services, a trusted end-to-end digital product development & consulting firm, delivering software, apps, CRM & web solutions.

    Category