Mastering React's Dynamic Side: State, Events, and Conditional Rendering! (React Day 3)

Published: (January 10, 2026 at 11:30 PM EST)
6 min read
Source: Dev.to

Source: Dev.to

State Management: Introducing useState for Local Data

State is React’s way to remember data that changes over time—like a counter’s value or form inputs. Unlike props (passed from parents), state is private to a component and triggers re‑renders on updates.

useState is a hook (more on hooks later) that gives you a state variable and a setter function. Import it from React:

import { useState } from 'react';

How It Works

const [value, setValue] = useState(initialValue);
  • value is read‑only.
  • Call setValue to update it.

Live Example: Simple Counter

import { useState } from 'react';

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

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

Click the button → state updates → component re‑renders with the new count.

Real‑World Example: A Login Form Tracking Input

import { useState } from 'react';

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

  return (
    <input
      type="text"
      value={username}
      onChange={e => setUsername(e.target.value)}
      placeholder="Username"
    />
  );
}

State keeps the input synced, ready for submission.

Common Mistakes

  • Direct mutationcount++ won’t trigger a re‑render. Always use the setter.
  • Skipping the setter – Updating a variable without setValue does nothing.

Debugging Tip

console.log('Current count:', count);

Place the log inside the component to see the value on each render. Remember that re‑renders are asynchronous.

Event Handling: Responding to User Actions

Events in React look like HTML but use camelCase (e.g., onClick) and receive a function reference.

Analogy: Attaching a listener to a doorbell—when the user “rings” (clicks), your code responds.

Live Example (from the Counter)

<button onClick={() => setCount(count + 1)}>Increment</button>

Form Events

  • onChange – captures input changes.
  • onSubmit – handles form submission.

Real‑World Example: A Todo App Adding Items

import { useState } from 'react';

function TodoForm({ addTodo }) {
  const [text, setText] = useState('');

  const handleSubmit = e => {
    e.preventDefault();          // Prevent page reload
    addTodo(text);
    setText('');                 // Clear input
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        value={text}
        onChange={e => setText(e.target.value)}
        placeholder="New todo"
      />
      <button type="submit">Add</button>
    </form>
  );
}

Common Mistakes

  • Forgetting e.preventDefault() on forms → page reloads.
  • Defining heavy inline functions on every render → consider useCallback or extracting the function.

Debugging Tip

Open React DevTools, inspect the component’s props and state, and log the event object:

const handleClick = e => {
  console.log(e);
  // …your logic
};

Conditional Rendering: Showing/Hiding Based Logic

Render different UI based on conditions—just like if/else in regular JavaScript.

Methods

TechniqueSyntax
Ternary{condition ? <A /> : <B />}
Short‑circuit{condition && <A />}
Early returnif (!condition) return null;

Live Example: Toggle Visibility

import { useState } from 'react';

function Toggle() {
  const [isVisible, setIsVisible] = useState(false);

  return (
    <div>
      <button onClick={() => setIsVisible(!isVisible)}>Toggle</button>
      {isVisible && <p>Now you see me!</p>}
    </div>
  );
}

Real‑World Example: Loading Spinner

import { useState, useEffect } from 'react';

function DataFetcher() {
  const [data, setData] = useState(null);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    fetch('/api/data')
      .then(res => res.json())
      .then(json => {
        setData(json);
        setLoading(false);
      });
  }, []);

  return loading ? (
    <p>Loading...</p>
  ) : (
    <pre>{JSON.stringify(data)}</pre>
  );
}

Common Mistakes

  • Placing if statements outside the JSX return—JSX is an expression, so use ternaries or short‑circuit inside.
  • Deeply nested conditionals → extract them into separate components for readability.

Dynamic UI Updates: Bringing It All Together

Combine state, events, and conditionals for UIs that react to users—e.g., a filterable list that updates as you type.

Real‑World Example: Search Form

import { useState } from 'react';

function SearchList() {
  const [query, setQuery] = useState('');
  const items = ['Apple', 'Banana', 'Cherry'];

  const filtered = items.filter(item =>
    item.toLowerCase().includes(query.toLowerCase())
  );

  return (
    <div>
      <input
        type="text"
        value={query}
        onChange={e => setQuery(e.target.value)}
        placeholder="Search fruits"
      />
      <ul>
        {filtered.length ? (
          filtered.map(item => <li key={item}>- {item}</li>)
        ) : (
          <li>No results</li>
        )}
      </ul>
    </div>
  );
}

TypingonChange updates queryfiltered recomputes → JSX re‑renders the matching list.

How React Re‑Renders Components

When state or props change, React:

  1. Re‑runs the component function.
  2. Creates a new virtual DOM tree.
  3. Diffs the new tree against the previous one.
  4. Applies only the necessary changes to the real DOM.

Analogy

Think of it as redrawing a sketch: you only erase and redraw the parts that changed.

Visualizing the Render Cycle

React render cycle diagram

The diagram shows the flow from state/prop changes → render → commit → browser paint.

Key Points

  • Immutability – Always treat state as immutable; React relies on reference changes to detect updates.
  • Batching – Multiple state updates inside the same event loop are batched into a single render for performance.
  • Memoization – Use React.memo, useMemo, and useCallback to avoid unnecessary re‑renders.

Debugging Tip

Enable the “Highlight updates” option in React DevTools to see which components re‑render after a state change. Combine this with console.log statements to trace the render flow.

🎉 You’re All Set!

You now have the core tools to make your React components stateful, interactive, and dynamic. Experiment with the examples, break things, and then fix them—learning happens in the process. Happy coding!

State & Lifecycle Overview

State and LifeCycle in React – Beginner's Guide

Debugging Tip: Use the React DevTools Profiler to record renders and spot unnecessary ones.

State Immutability – Why You Can’t Mutate Directly

State should be treated as read‑only. Mutating it (e.g., array.push(item)) does not notify React, so the UI won’t update.

  • Why? React checks reference equality to detect changes. A mutation keeps the same reference, so React skips the re‑render.
  • Best Practice: Create a new object/array when updating state.
// ❌ Mutating the original array
array.push(item);
setArray(array);

// ✅ Creating a new array
setArray([...array, item]);

The React State Bug That Doesn't Throw Errors (But Breaks Your UI)

Common Mistake: Mutating nested objects. Use a deep copy or a library like Immer.

Batching – Grouping Updates for Efficiency

React automatically batches multiple state updates into a single re‑render, especially inside event handlers or lifecycle methods.

// Both updates are batched → count increases by 2 in one render
setCount(c => c + 1);
setCount(c => c + 1);
  • Why? Reduces DOM thrashing and improves performance.
  • Pitfall: Updates are not immediate in async code. Use callbacks or useEffect when you need to act after the state has changed.

Props vs. State – The Key Comparison

AspectPropsState
SourcePassed down from a parent componentManaged internally by the component
MutabilityRead‑only – cannot be changed by the childMutable via the setter function (setX)
TriggerChanging a prop causes the child to re‑renderChanging state re‑renders the component and its children
AnalogyGifts from parents – you can’t alter themYour own wallet – you can spend or add to it

What is State and Props?

  • When to use Props: For configuration data, values that come from a parent, or anything that should be immutable inside the child.
  • When to use State: For data that changes over time due to user interaction, network responses, timers, etc.
  • Common Mistake: Storing derived data in state. Compute it on‑the‑fly from props/state instead to avoid synchronization bugs.

Debugging Tip: If the UI isn’t updating, log both props and state inside the render function to verify they contain the expected values.

Wrapping Up – Your React Apps Come Alive

You’ve now mastered:

  • State – immutable updates, batching, and debugging.
  • Props – one‑way data flow from parent to child.
  • Lifecycle basics – when components mount, update, and unmount.

These concepts power real‑world features like counters, forms, dashboards, and chat interfaces.

Next step: Day 4 – Lists, Keys, and Effects.

Practice idea: Build a dynamic todo list that lets users add, edit, and delete items. Remember to:

  1. Never mutate the original list; always create a new array.
  2. Leverage batching by using functional updates when multiple state changes depend on the previous state.
  3. Use keys correctly to keep list items stable.

Happy coding, and keep reacting! 🚀

Back to Blog

Related posts

Read more »

Polyfill - useState (React)

!ZeeshanAli-0704https://media2.dev.to/dynamic/image/width=50,height=50,fit=cover,gravity=auto,format=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fupload...