DEV Community

Cover image for Why React Finally Clicked for Me
Salik Beigh
Salik Beigh

Posted on

Why React Finally Clicked for Me

I'll be honest—when I first heard about React, I rolled my eyes. "Another JavaScript framework? Really?" I was perfectly fine with vanilla JavaScript and jQuery (yes, I know, I know). Why complicate things?

Then I tried building a slightly complex web app without React. A simple todo list that needed filtering, editing, and local storage. What started as "this should take an hour" turned into a nightmare of DOM manipulation, event listeners everywhere, and bugs that made me question my career choices.

That's when I gave React a shot. And honestly? It changed everything.

The Problem: Vanilla JavaScript Gets Messy Fast

Here's what my vanilla JS code looked like for a simple todo app:

// Adding a new todo
document.getElementById('add-btn').addEventListener('click', function() {
    const input = document.getElementById('todo-input');
    const todoText = input.value;

    // Create elements
    const li = document.createElement('li');
    const span = document.createElement('span');
    const deleteBtn = document.createElement('button');

    // Set content
    span.textContent = todoText;
    deleteBtn.textContent = 'Delete';

    // Add event listeners
    deleteBtn.addEventListener('click', function() {
        li.remove();
        updateLocalStorage();
    });

    li.appendChild(span);
    li.appendChild(deleteBtn);
    document.getElementById('todo-list').appendChild(li);

    updateLocalStorage();
    input.value = '';
});

// And this is just for ADDING. Imagine editing, filtering, sorting...
Enter fullscreen mode Exit fullscreen mode

Every feature meant:

  • Manually creating DOM elements
  • Attaching event listeners everywhere
  • Keeping track of state across different functions
  • Syncing everything with local storage
  • Praying nothing breaks when I add a new feature

It was exhausting.

Enter React: Components Change Everything

Here's the same functionality in React:

function TodoApp() {
    const [todos, setTodos] = useState([]);
    const [input, setInput] = useState('');

    const addTodo = () => {
        setTodos([...todos, { id: Date.now(), text: input }]);
        setInput('');
    };

    const deleteTodo = (id) => {
        setTodos(todos.filter(todo => todo.id !== id));
    };

    return (
        <div>
            <input 
                value={input} 
                onChange={(e) => setInput(e.target.value)} 
            />
            <button onClick={addTodo}>Add</button>

            <ul>
                {todos.map(todo => (
                    <li key={todo.id}>
                        <span>{todo.text}</span>
                        <button onClick={() => deleteTodo(todo.id)}>
                            Delete
                        </button>
                    </li>
                ))}
            </ul>
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

Look at that. Clean, readable, and everything in one place. No manual DOM manipulation. No scattered event listeners. Just data and how it should look.

What Actually Made My Life Easier

1. Components = Reusable Building Blocks

Instead of copy-pasting HTML and JS everywhere, I build once and reuse:

function Button({ onClick, children, variant = 'primary' }) {
    return (
        <button 
            className={`btn btn-${variant}`}
            onClick={onClick}
        >
            {children}
        </button>
    );
}

// Now use it everywhere
<Button onClick={handleSave}>Save</Button>
<Button onClick={handleCancel} variant="secondary">Cancel</Button>
<Button onClick={handleDelete} variant="danger">Delete</Button>
Enter fullscreen mode Exit fullscreen mode

One component, infinite uses. Change the Button component once, and it updates everywhere. That's powerful.

2. State Management That Makes Sense

Remember tracking variables across different functions in vanilla JS? React's useState hook solved that headache:

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

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

State is local to the component. It updates automatically. The UI re-renders when needed. No manual DOM updates.

3. useEffect: Side Effects Without the Chaos

Need to fetch data? Save to local storage? Update the document title? useEffect handles it cleanly:

function UserProfile({ userId }) {
    const [user, setUser] = useState(null);
    const [loading, setLoading] = useState(true);

    useEffect(() => {
        // Fetch user data when userId changes
        fetch(`/api/users/${userId}`)
            .then(res => res.json())
            .then(data => {
                setUser(data);
                setLoading(false);
            });
    }, [userId]); // Only re-run when userId changes

    if (loading) return <p>Loading...</p>;

    return <div>{user.name}</div>;
}
Enter fullscreen mode Exit fullscreen mode

No more scattered AJAX calls. No wondering when to fetch data. The dependency array [userId] tells React exactly when to re-fetch. Beautiful.

4. Conditional Rendering is Intuitive

Vanilla JS:

if (isLoggedIn) {
    document.getElementById('dashboard').style.display = 'block';
    document.getElementById('login').style.display = 'none';
} else {
    document.getElementById('dashboard').style.display = 'none';
    document.getElementById('login').style.display = 'block';
}
Enter fullscreen mode Exit fullscreen mode

React:

{isLoggedIn ? <Dashboard /> : <Login />}
Enter fullscreen mode Exit fullscreen mode

One line. Clear. No DOM manipulation. Just logic.

5. Props Make Data Flow Obvious

Passing data from parent to child is explicit and traceable:

function App() {
    const [theme, setTheme] = useState('dark');

    return (
        <div>
            <Header theme={theme} />
            <MainContent theme={theme} />
            <Footer theme={theme} onThemeChange={setTheme} />
        </div>
    );
}

function Header({ theme }) {
    return <header className={`header-${theme}`}>My App</header>;
}
Enter fullscreen mode Exit fullscreen mode

I can see exactly where data comes from and where it goes. No more mystery bugs from global variables.

Real Project Example: My Experience

I recently built a movie search app for a class project. Here's how React made it painless:

The app needed:

  • Search movies via API
  • Display results in a grid
  • Filter by genre
  • Add to favorites
  • Persist favorites in local storage

In vanilla JS, this would have been:

  • 300+ lines of spaghetti code
  • Multiple files trying to share state
  • Event listeners attached and removed constantly
  • localStorage syncing nightmares

With React:

function MovieApp() {
    const [movies, setMovies] = useState([]);
    const [favorites, setFavorites] = useState(
        JSON.parse(localStorage.getItem('favorites')) || []
    );
    const [filter, setFilter] = useState('all');

    // Auto-save favorites
    useEffect(() => {
        localStorage.setItem('favorites', JSON.stringify(favorites));
    }, [favorites]);

    const searchMovies = async (query) => {
        const response = await fetch(`/api/search?q=${query}`);
        const data = await response.json();
        setMovies(data.results);
    };

    const toggleFavorite = (movie) => {
        setFavorites(prev => 
            prev.find(m => m.id === movie.id)
                ? prev.filter(m => m.id !== movie.id)
                : [...prev, movie]
        );
    };

    const filteredMovies = filter === 'favorites' 
        ? favorites 
        : movies;

    return (
        <div>
            <SearchBar onSearch={searchMovies} />
            <FilterButtons filter={filter} setFilter={setFilter} />
            <MovieGrid 
                movies={filteredMovies} 
                onToggleFavorite={toggleFavorite}
                favorites={favorites}
            />
        </div>
    );
}
Enter fullscreen mode Exit fullscreen mode

Clean components. Clear data flow. Everything in one place. I built this in a weekend instead of struggling for a week.

Things I Struggled With (And How I Got Past Them)

1. "Why isn't my component updating?"
Forgot that state updates are asynchronous. Solution: Use the functional form of setState:

// Wrong
setCount(count + 1);
setCount(count + 1); // Still adds only 1!

// Right
setCount(prev => prev + 1);
setCount(prev => prev + 1); // Adds 2!
Enter fullscreen mode Exit fullscreen mode

2. "Infinite re-render loop!"
Called setState directly in the component body. Solution: Always use useEffect or event handlers:

// Wrong - infinite loop
function Bad() {
    const [count, setCount] = useState(0);
    setCount(count + 1); // Re-renders forever!
    return <div>{count}</div>;
}

// Right
function Good() {
    const [count, setCount] = useState(0);

    useEffect(() => {
        setCount(count + 1);
    }, []); // Runs once

    return <div>{count}</div>;
}
Enter fullscreen mode Exit fullscreen mode

3. "My list items aren't updating correctly"
Forgot to add keys. React needs them to track which items changed:

// Wrong
{items.map(item => <li>{item.name}</li>)}

// Right
{items.map(item => <li key={item.id}>{item.name}</li>)}
Enter fullscreen mode Exit fullscreen mode

Is React Worth Learning?

For me? Absolutely. Here's why:

You should learn React if you:

  • Want to build modern web applications
  • Hate managing DOM manipulation manually
  • Need to build reusable UI components
  • Want a job in web development (it's everywhere in job postings)
  • Like working with a massive ecosystem (tons of libraries, tools, community support)

React might not be for you if:

  • You're building simple static sites (vanilla JS or even just HTML/CSS might be enough)
  • You're overwhelmed by JavaScript already (get comfortable with JS first)
  • You need SEO-heavy sites (though Next.js solves this)

My Advice for Learning React

1. Master JavaScript first
Seriously. Learn array methods (map, filter, reduce), destructuring, arrow functions, promises, and async/await. React will make SO much more sense.

2. Start with functional components and hooks
Ignore class components. They're legacy. Focus on useState, useEffect, and props.

3. Build projects, not tutorials
Watching tutorials feels productive but you don't really learn until you build. Start with:

  • Todo app (classic for a reason)
  • Weather app (API calls + useEffect)
  • Movie search (combining multiple concepts)

4. Don't overthink state management early
You don't need Redux or Context API for your first projects. useState and prop drilling are fine while learning.

5. Read the official React docs
They're actually good. The new docs (react.dev) are beginner-friendly and well-written.

The Bottom Line

React didn't just make my code cleaner—it made web development actually enjoyable. Instead of fighting with DOM manipulation and spaghetti code, I spend time building features and solving interesting problems.

Is there a learning curve? Yes. Will you get frustrated with re-renders and hooks at first? Absolutely. But once it clicks, you'll wonder how you ever built web apps without it.

React turned me from someone who tolerated frontend development into someone who actually looks forward to it. And for a CS student trying to build a portfolio and land internships, that's been a game-changer.


What's your React journey been like? Still learning, or already building cool stuff? Would love to hear what projects you're working on! ⚛️

Top comments (0)