My 7-Day Journey with React: An In-Depth Look at Key Concepts, Hooks, and Best Practices

rohit mantharohit mantha
5 min read

React has revolutionized how developers build user interfaces by simplifying DOM manipulation and optimizing state management. In this article, I’ll walk you through my day-by-day experience, covering everything from fundamental concepts to complex state handling and advanced hooks.

Day 1: The Foundation - Understanding React’s Core Functions

Primary Functions of React

React serves two fundamental purposes:

  1. DOM Manipulation Made Easy: React uses JSX (JavaScript XML) to make HTML-like syntax available within JavaScript, enabling seamless DOM manipulation. This eliminates the need for cumbersome JavaScript methods like createElement or innerHTML. React’s ReactDOM library further simplifies the process by handling how elements are inserted into the DOM.

  2. Efficient State Management: React enables intelligent state-based rendering. When the state of an app changes, React automatically re-renders only the affected parts of the DOM, which enhances performance. This is achieved by maintaining a virtual representation of the DOM, comparing it with the real DOM, and updating only the necessary parts.

Example - Basic JSX and State

javascriptCopy codeimport React, { useState } from 'react';

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

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

export default App;

Pitfalls on Day 1

  • Forgetting JSX Syntax: JSX isn’t HTML; it has its quirks. For instance, use className instead of class in JSX. Missing these details often led to errors.

  • Not Grasping State’s Role: It’s easy to misinterpret state as just another variable, but in React, state is central to reactivity and rendering. Using state correctly involves understanding how it triggers re-renders.


Day 2: Mastering JSX and React DOM

JSX and ReactDOM in Action

JSX lets us write HTML-like elements within JavaScript. It’s not just syntactic sugar but is transformed into JavaScript code (e.g., React.createElement). Here’s how JSX and ReactDOM make DOM manipulation efficient:

  • ReactDOM takes care of rendering React components to the actual DOM.

  • JSX helps blend HTML and JavaScript, so developers can write UI code within a single file.

Example - JSX and ReactDOM

javascriptCopy codeimport ReactDOM from 'react-dom';

function Greeting() {
  return <h1>Hello, world!</h1>;
}

ReactDOM.render(<Greeting />, document.getElementById('root'));

Pitfalls

  • Ignoring JavaScript Code in JSX: JSX lets you use expressions within {}, but it doesn’t support statements. Trying to use statements like if can cause syntax errors; instead, use conditional expressions.

Day 3: The Power of useState and setState for State Management

State Management with useState

In React, state refers to the data that controls the component’s behavior. Using useState, you can create a piece of state and a function to update it.

Example - Counter with useState

javascriptCopy codeimport React, { useState } from 'react';

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

  const increment = () => {
    setCount(count + 1);
  };

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

Pitfalls

  • Relying on Stale State: When updating state based on the previous state, using the function form of setState (e.g., setCount(prevCount => prevCount + 1)) helps prevent bugs, especially when dealing with asynchronous updates.

Day 4: Deeper into State Changes - The Importance of Top-Level State and setState

To ensure efficient rendering, React expects state to be managed at the top level of the component. This structure enables the component and its children to be efficiently re-rendered when the state changes.

Common Pitfall

  • Updating State in Nested Functions: State changes should be managed at the component’s top level to avoid unnecessary re-renders and to ensure all affected child components respond correctly.

Example - setState at the Top Level

javascriptCopy codeimport React, { useState } from 'react';

function ParentComponent() {
  const [parentState, setParentState] = useState("Hello");

  return (
    <div>
      <ChildComponent parentState={parentState} />
      <button onClick={() => setParentState("Hi there!")}>Update Parent State</button>
    </div>
  );
}

function ChildComponent({ parentState }) {
  return <p>{parentState}</p>;
}

Day 5: Introducing useEffect - Managing Side Effects

Understanding useEffect

useEffect allows components to perform side effects like data fetching, setting up subscriptions, or changing the DOM. useEffect runs after the initial render, and you can specify dependencies to control when it triggers.

Example - Fetching Data with useEffect

javascriptCopy codeimport React, { useState, useEffect } from 'react';

function FetchComponent() {
  const [data, setData] = useState(null);

  useEffect(() => {
    fetch("https://api.example.com/data")
      .then(response => response.json())
      .then(data => setData(data));
  }, []); // Runs only once, like componentDidMount

  return <div>{data ? JSON.stringify(data) : "Loading..."}</div>;
}

Pitfall - Forgetting Dependencies

  • Infinite Loops: Not including dependencies can lead to re-renders every time the component mounts. Always add the required state variables or props in the dependency array to avoid this.

Day 6: Building Complex Components - Single Element Return, Keys, and Memoization

Single Element Return and Keys

React requires components to return a single element. When rendering lists, React needs unique key properties for each item to optimize updates and ensure elements are correctly matched in re-renders.

Example - List Rendering with Keys

javascriptCopy codeimport React from 'react';

function ListComponent({ items }) {
  return (
    <ul>
      {items.map(item => (
        <li key={item.id}>{item.name}</li>
      ))}
    </ul>
  );
}

Using React.memo for Memoization

React.memo is a higher-order component that memoizes a component, preventing unnecessary re-renders when props haven’t changed.

Example - Optimizing with React.memo

javascriptCopy codeimport React from 'react';

const ExpensiveComponent = React.memo(({ data }) => {
  console.log("Rendering Expensive Component");
  return <div>{data}</div>;
});

Pitfall - Overusing React.memo

  • Premature Optimization: Using React.memo on components that don’t have performance issues can add unnecessary complexity. Only apply memoization when profiling shows a real need.

Day 7: Best Practices and Common Mistakes to Avoid in React

  1. Use setState Function Form for Dependent Updates: When updating state based on the previous state, always use the function form of setState.

  2. Place State in the Right Components: When multiple components need the same state, consider lifting it to a common ancestor to avoid prop drilling and redundant updates.

  3. Don’t Directly Mutate State: React relies on immutable data. Directly modifying an array or object in state can lead to bugs.

  4. Understand JSX Limitations: JSX is more than just HTML inside JavaScript; it has its syntax (like className instead of class and htmlFor instead of for).

  5. Use Effects Wisely: Don’t overuse useEffect for simple UI updates. Overusing effects can slow down your app and create hard-to-debug issues.


Final Thoughts

React’s ability to simplify DOM manipulation and optimize reactivity through efficient state handling makes it incredibly powerful. Throughout this journey, I learned that React is best used with a deep understanding of state management, component structure, and hooks like useState and useEffect.

0
Subscribe to my newsletter

Read articles from rohit mantha directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

rohit mantha
rohit mantha