React

Building Components with React

Published on January 28, 2026

Written by: Code Arc Studio Editorial Team

React logo with code

React is a declarative, efficient, and flexible JavaScript library for building user interfaces. Its core strength lies in its component-based architecture. Instead of thinking about your application as a single, monolithic block of HTML and JavaScript, React encourages you to break down the UI into small, independent, and reusable pieces called "components". Each component manages its own state and renders a piece of the UI, and you can then compose them together to build complex applications. This modularity is key to building scalable and robust web apps.

At the heart of React is the Virtual DOM. When a component's state changes, React creates a new virtual DOM tree, compares it with the previous one (a process called "diffing"), and then efficiently updates the actual browser DOM with only the necessary changes. This makes React applications feel fast and responsive.

Functional Components and Props

In modern React, the most common way to create a component is by writing a JavaScript function that returns JSX (a syntax extension for JavaScript that looks like HTML). These are called functional components. They can accept a single argument—a "props" object—and return a React element that describes what should appear on the screen.


// A simple component that accepts a 'name' prop
function WelcomeMessage(props) {
  return <h1>Hello, {props.name}!</h1>;
}

// You can use this component like an HTML tag, passing data via props.
const app = <WelcomeMessage name="Sarah" />;
      

Props (short for properties) are how you pass data from a parent component down to a child component. This data flow is one-way, from top to bottom (unidirectional data flow), which makes the logic of your application easier to follow and debug. It's a core principle of React: props are read-only; a component must never modify its own props.

Props vs. State

Feature Props State
Can be changed by Parent component The component itself
Mutability Immutable (read-only) Mutable (can be changed)
Data Flow Passed down from parent Managed internally

State and Interactivity with Hooks

While props are for passing data down, what if a component needs to manage its own internal data that changes over time? This is where state comes in. The useState Hook allows functional components to hold and manage their own state.


import React, { useState } from 'react';

function Counter() {
  // Declare a new state variable, which we'll call "count"
  const [count, setCount] = useState(0); // 0 is the initial state

  return (
    <div>
      <p>You clicked {count} times</p>
      <button onClick={() => setCount(count + 1)}>
        Click me
      </button>
    </div>
  );
}
      

In this example, useState returns a pair: the current state value (count) and a function that lets you update it (setCount). When setCount is called, React re-renders the Counter component with the new count value, updating the UI. Events like onClick are used to trigger these state updates in response to user interaction.

Composition of Components

The true power of components comes from composition. You can build larger, more complex components by combining smaller, specialized ones. This follows the principle of "separation of concerns" and leads to a more maintainable codebase.


function Avatar(props) {
  return <img src={props.user.avatarUrl} alt={props.user.name} />;
}

function UserInfo(props) {
  return (
    <div className="UserInfo">
      <Avatar user={props.user} />
      <div className="UserInfo-name">{props.user.name}</div>
    </div>
  );
}

function Comment(props) {
  return (
    <div className="Comment">
      <UserInfo user={props.author} />
      <div className="Comment-text">{props.text}</div>
    </div>
  );
}
      

Here, the Comment component is composed of a UserInfo component and some text. The UserInfo component is itself composed of an Avatar component and the user's name. By breaking your UI into a hierarchy of components, you create a system that is both flexible and easy to reason about. This component model is what has made React one of the most popular and powerful UI libraries available today.

10 Common React Component Errors and Their Fixes

Building with React components is powerful, but some common pitfalls can trip up developers. Here are 10 of them and how to solve them.

# Common Error Why It Happens Solution
1 Mutating State Directly Modifying state directly (e.g., this.state.x = 1 or myArray.push(newItem)) doesn't trigger a re-render and bypasses React's lifecycle. Always use the updater function from useState (e.g., setCount(newCount)). For objects and arrays, create a new instance: setMyArray([...myArray, newItem]).
2 Forgetting the key Prop in Lists React uses the key prop to identify which items in a list have changed, been added, or been removed. Without it, React can't efficiently update the UI. Always provide a unique and stable key prop to every element inside a .map() call. E.g., <li key={item.id}>{item.name}</li>.
3 Calling Hooks Inside Loops, Conditions, or Nested Functions React relies on the call order of Hooks to be the same on every render. Placing them inside conditions breaks this rule. Always call Hooks at the top level of your React function, before any returns or conditions.
4 "Too many re-renders" Error This infinite loop is usually caused by calling a state updater function (like setCount) directly in the component's render body. Only call state updater functions inside event handlers (like onClick) or useEffect hooks.
5 Passing a Function Call Instead of a Function Reference to Event Handlers Writing onClick={myFunction()} calls the function immediately on render, instead of waiting for the click. Pass the function reference without calling it: onClick={myFunction}. If you need to pass arguments, use an arrow function: onClick={() => myFunction(arg)}.
6 Incorrectly Using useEffect Dependencies Forgetting a dependency in the dependency array can lead to stale state or effects that don't re-run when they should. An empty array [] means the effect runs only once. Include every variable from the component's scope that is used inside the effect in the dependency array. Use the eslint-plugin-react-hooks to automatically detect missing dependencies.
7 Prop Drilling Passing props down through many layers of components that don't actually need the props themselves. This makes code hard to maintain. For state that is needed in many places, use React Context or a state management library (like Redux or Zustand) to provide the data directly to the components that need it.
8 Defining Components Inside Other Components If you define a component function inside the render body of another, React will unmount and remount it on every render, losing its state and causing performance issues. Always define your components at the top level of the module or outside the parent component.
9 Not Returning Anything from a Component Every component must return a value. Forgetting the return statement or returning undefined will cause an error. Ensure your component function always returns valid JSX, null (to render nothing), or a string/number.
10 Using JSX Comments Incorrectly HTML comments (<!-- ... -->) don't work in JSX. Using // also doesn't work as expected everywhere. Use JavaScript block comments inside curly braces: {/* This is a JSX comment */}.