DEV Community

Cover image for React Concepts Explained: Part 1 - Core Fundamentals
Dehemi Fabio
Dehemi Fabio

Posted on

React Concepts Explained: Part 1 - Core Fundamentals

React is packed with terminology that can sound intimidating at first—components, JSX, props, state, and hooks. But don't worry! In this two-part series, we'll break down every major React concept into simple, easy-to-understand explanations.

Part 1 (this post) covers the essential fundamentals you need to start building React apps.

Part 2 will dive into advanced patterns for building production-ready applications.

By the end of this post, you'll understand the core building blocks of React and be ready to create your first interactive components!


1. Components: The Building Blocks

What are they?

Components are the foundation of every React app. They're reusable pieces that represent visible parts of your UI—like buttons, inputs, forms, or entire pages.

Why are they useful?

Think of components like Lego blocks. Once you create one, you can use it as many times as you want throughout your app.

How do they work?

Every React component is simply a JavaScript function that returns markup:

function Button() {
  return <button>Click Me!</button>;
}
Enter fullscreen mode Exit fullscreen mode

You can use this Button component anywhere in your app, just like reusing a Lego piece!


2. JSX: JavaScript in Disguise

What is it?

JSX is a special syntax that looks like HTML but is actually JavaScript. It's what React components return to describe what should appear on the screen.

Why use it?

The alternative is using React.createElement() for everything, which gets tedious fast. JSX makes your code much more readable.

Key differences from HTML:

  • Use className instead of class
  • Write attributes in camelCase (like onClick instead of onclick)
  • You can embed JavaScript expressions using curly braces {}
function Greeting() {
  const name = "Sarah";
  return <h1>Hello, {name}!</h1>; // Output: Hello, Sarah!
}
Enter fullscreen mode Exit fullscreen mode

The One Parent Rule

Important: Components can only return one parent element. If you need multiple elements, wrap them in a parent <div> or use a React Fragment (<>...</>):

function App() {
  return (
    <>
      <h1>Title</h1>
      <p>Paragraph</p>
    </>
  );
}
Enter fullscreen mode Exit fullscreen mode

Why use Fragments?

Sometimes you don't want to add an extra <div> to your DOM. Fragments let you group elements without creating unnecessary wrapper elements.


3. Props: Passing Data Between Components

What are they?

Props (short for "properties") are how you pass data from one component to another. Think of them as custom attributes you can add to your components.

How do they work?

// Passing a prop
<Welcome name="John" age={25} />

// Using the prop
function Welcome(props) {
  return <h1>Hello, {props.name}! You are {props.age} years old.</h1>;
}
Enter fullscreen mode Exit fullscreen mode

Modern syntax (destructuring):

function Welcome({ name, age }) {
  return <h1>Hello, {name}! You are {age} years old.</h1>;
}
Enter fullscreen mode Exit fullscreen mode

Can you pass anything as a prop?

Yes! Strings, numbers, arrays, objects, functions, and even other components.

The Special children Prop

When you put content between opening and closing component tags, it becomes accessible via the children prop:

<Card>
  <h2>Title</h2>
  <p>Content goes here</p>
</Card>

function Card({ children }) {
  return (
    <div className="card">
      {children}
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Why is this useful?

The children prop is perfect for creating layout components and practicing composition (organizing components in an optimal way). You can create reusable containers that work with any content!

Real-world example:

function Container({ children }) {
  return (
    <div className="max-width-container">
      {children}
    </div>
  );
}

// Use it anywhere
<Container>
  <Header />
  <MainContent />
  <Footer />
</Container>
Enter fullscreen mode Exit fullscreen mode

4. The key Prop: Helping React Identify Components

What is it?

The key prop is a unique identifier React uses to tell components apart, especially when rendering lists.

When do you need it?

When creating lists with the .map() function:

const todos = [
  { id: 1, text: 'Learn React' },
  { id: 2, text: 'Build a project' },
  { id: 3, text: 'Deploy app' }
];

return (
  <ul>
    {todos.map((todo) => (
      <li key={todo.id}>{todo.text}</li>
    ))}
  </ul>
);
Enter fullscreen mode Exit fullscreen mode

Why is it important?

Without keys, React might get confused about which items changed, leading to weird bugs or poor performance. React will warn you in the console if you forget them!

Best practices:

  • ✅ Use unique IDs from your data: key={item.id}
  • ⚠️ Use array index as last resort: key={index} (okay for static lists)
  • ❌ Never use random values: key={Math.random()} (breaks everything!)

5. Rendering: How React Displays Your UI

What is rendering?

Rendering is the process React uses to take your components and display them in the browser.

The Virtual DOM (VDOM)

React uses a clever optimization called the Virtual DOM:

  1. Your app's state changes (user clicks a button, data loads, etc.)
  2. React updates the Virtual DOM (a lightweight JavaScript copy of the real DOM)
  3. React uses diffing to compare the new Virtual DOM with the previous version
  4. React uses reconciliation to update only the changed parts of the real DOM

Why this matters:

This process makes React incredibly efficient. Instead of updating the entire page, React only updates what actually changed!

The DOM explained:

DOM stands for Document Object Model—it's how browsers represent all the HTML elements on a web page as a tree structure.

Warning: Infinite Re-renders!

Be careful not to update state during render. This creates an infinite loop and crashes your app:

// ❌ BAD - Infinite loop!
function BadComponent() {
  const [count, setCount] = useState(0);
  setCount(count + 1); // This runs on every render!
  return <div>{count}</div>;
}

// ✅ GOOD - Update in event handler
function GoodComponent() {
  const [count, setCount] = useState(0);
  return (
    <button onClick={() => setCount(count + 1)}>
      {count}
    </button>
  );
}
Enter fullscreen mode Exit fullscreen mode

6. Event Handling: Responding to User Actions

What is it?

Event handling is how you detect and respond to user interactions like clicks, typing, and form submissions.

Common events:

  • onClick - User clicks an element
  • onChange - Input value changes
  • onSubmit - Form is submitted
  • onMouseEnter - Mouse hovers over element
  • onKeyDown - User presses a key

Example:

function AlertButton() {
  const handleClick = () => {
    alert('Button was clicked!');
  };

  return <button onClick={handleClick}>Click Me</button>;
}
Enter fullscreen mode Exit fullscreen mode

Important: Notice we pass the function itself (handleClick), not handleClick()—we don't want to call it immediately!

Inline event handlers:

<button onClick={() => alert('Clicked!')}>
  Click Me
</button>
Enter fullscreen mode Exit fullscreen mode

Accessing event details:

function SearchInput() {
  const handleChange = (event) => {
    console.log('User typed:', event.target.value);
  };

  return <input onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

7. State: Managing Dynamic Data

What is state?

State is like a snapshot of your app at any moment in time. It's data that can change based on user interaction or other events.

Why not use regular JavaScript variables?

Regular variables don't trigger React to re-render your UI. State does!

Using useState

How to use it:

import { useState } from 'react';

function Counter() {
  const [count, setCount] = useState(0); // Start at 0

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>
        Increment
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Breaking it down:

  • count is the current value (the state variable)
  • setCount is the function to update it (the setter function)
  • useState(0) sets the initial value to 0
  • When setCount is called, React re-renders the component with the new value

Multiple state variables:

function UserForm() {
  const [name, setName] = useState('');
  const [email, setEmail] = useState('');
  const [age, setAge] = useState(0);

  return (
    <form>
      <input value={name} onChange={(e) => setName(e.target.value)} />
      <input value={email} onChange={(e) => setEmail(e.target.value)} />
      <input value={age} onChange={(e) => setAge(e.target.value)} />
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

State with objects:

function UserForm() {
  const [user, setUser] = useState({
    name: '',
    email: '',
    age: 0
  });

  const updateName = (e) => {
    setUser({ ...user, name: e.target.value }); // Spread to keep other fields
  };

  return <input value={user.name} onChange={updateName} />;
}
Enter fullscreen mode Exit fullscreen mode

8. Controlled Components: Predictable Form Behavior

What are they?

Controlled components are form inputs whose values are controlled by React state. The state becomes the "single source of truth" for the input's value.

Example:

function NameForm() {
  const [name, setName] = useState('');

  return (
    <div>
      <input
        value={name}
        onChange={(e) => setName(e.target.value)}
      />
      <p>You typed: {name}</p>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

The flow:

  1. User types in the input
  2. onChange fires and calls setName with the new value
  3. State updates with the new value
  4. React re-renders
  5. Input displays the updated state value

Why use them?

Controlled components give you complete control over the input's value, making validation, formatting, and other logic much easier:

function EmailForm() {
  const [email, setEmail] = useState('');

  const handleChange = (e) => {
    const value = e.target.value.toLowerCase(); // Force lowercase
    setEmail(value);
  };

  return <input value={email} onChange={handleChange} />;
}
Enter fullscreen mode Exit fullscreen mode

Complete form example:

function LoginForm() {
  const [username, setUsername] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault(); // Prevent page refresh
    console.log('Logging in:', { username, password });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={username}
        onChange={(e) => setUsername(e.target.value)}
        placeholder="Username"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Login</button>
    </form>
  );
}
Enter fullscreen mode Exit fullscreen mode

9. React Hooks: The Foundation

What are hooks?

Hooks are special functions that let you "hook into" React features like state and lifecycle methods within function components.

Rules of Hooks:

  1. Only call hooks at the top level (not inside loops, conditions, or nested functions)
  2. Only call hooks from React function components (not regular JavaScript functions)

The Most Common Hook: useState

We've already covered useState extensively—it's the hook you'll use most often for managing component state.

Other Important Hooks (Preview)

We'll cover these in detail in Part 2, but here's a quick overview:

useEffect - Perform side effects (API calls, subscriptions)

useEffect(() => {
  // Run after render
}, [dependencies]);
Enter fullscreen mode Exit fullscreen mode

useRef - Reference DOM elements or store mutable values

const inputRef = useRef(null);
Enter fullscreen mode Exit fullscreen mode

useContext - Access data from React Context

const value = useContext(MyContext);
Enter fullscreen mode Exit fullscreen mode

Don't worry about memorizing these now—we'll explore them thoroughly in the next post!


10. Pure Components: Predictable Behavior

What does "pure" mean?

A pure component is like a mathematical function—the same input (props) always produces the same output (JSX), with no side effects.

Pure component (✅ Good):

function Cup({ guest }) {
  return <p>Tea cup for guest #{guest}</p>;
}
Enter fullscreen mode Exit fullscreen mode

Impure component (❌ Avoid):

let guestCount = 0;

function Cup() {
  guestCount = guestCount + 1; // Modifies external variable during render!
  return <p>Tea cup for guest #{guestCount}</p>;
}
Enter fullscreen mode Exit fullscreen mode

Why it matters:

React might render components multiple times for optimization. Impure components can produce unexpected results when rendered more than once:

// Using the impure Cup component
<>
  <Cup /> {/* guestCount = 1 */}
  <Cup /> {/* guestCount = 2 */}
  <Cup /> {/* guestCount = 3 */}
</>
// But if React re-renders, counts will be wrong!
Enter fullscreen mode Exit fullscreen mode

The fix (make it pure):

function Cup({ guest }) {
  return <p>Tea cup for guest #{guest}</p>;
}

// Usage
<>
  <Cup guest={1} />
  <Cup guest={2} />
  <Cup guest={3} />
</>
Enter fullscreen mode Exit fullscreen mode

Strict Mode: Your Safety Net

What is it?

Strict Mode is a special component that helps catch common mistakes during development.

How to use it:

import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';

ReactDOM.createRoot(document.getElementById('root')).render(
  <StrictMode>
    <App />
  </StrictMode>
);
Enter fullscreen mode Exit fullscreen mode

What does it do?

  • Highlights potential problems in your components
  • Warns about unsafe lifecycle methods
  • Detects unexpected side effects
  • Warns about deprecated APIs

Important: Strict Mode only runs in development mode. It won't affect your production build!


Quick Reference: Core Concepts Checklist

Here's what we covered in Part 1:

Components - Building blocks of React apps

JSX - JavaScript syntax extension for writing UI

Props - Passing data between components

Key Prop - Helping React identify list items

Rendering - How React displays your UI

Event Handling - Responding to user actions

State - Managing dynamic data with useState

Controlled Components - Form inputs controlled by state

Hooks - Functions for using React features

Pure Components - Predictable, side-effect-free components


These fundamental concepts form the foundation of everything in React. Master them, and you'll find Part 2's advanced patterns much easier to understand!

Top comments (0)