Codepath

Components

Components are the building blocks of React. It allow us to have independent, reusable pieces of code that brings composition to the UI layer.

Think of it as Legos for developers. Here are some example components that you might build or source externally:

  • <Navbar />
  • <Header />
  • <Avatar />
  • <Container> ... </Container>

⚠️ React components need to be capitalized. This is how React differentiates between a custom React Component and a built-in HTML element

In a nutshell, components are like JavaScript functions. They accept arbitrary inputs and return React Elements describing what should appear on the screen.

Defining a Component

React Components can be defined as functions - the modern, recommended approach:

function Header(props) {
  return (
    <div>
      <h1>Hello, {props.name}</h1>
    </div>
  );
}

💡 Since React 16.8, hooks have become the standard way to write React components. Functional components with hooks provide a simpler, more concise way to handle state and side effects. However, you may still encounter legacy code that uses class components.

// just for reference: Don't write components this way!
class Welcome extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

Passing & Accessing data

Components take parameters called props (properties) to receive data from parent components:

<Header name="CodePath" />;

The code above renders "Hello, CodePath" on the page as we are passing the name prop to the Header component.

// Header Component
function Header(props) {
  return <h1>Hello, {props.name}</h1>;
}

Props can include any JavaScript values including objects, functions, and even other components:

<Profile 
  name="CodePath" 
  username={<code>@codepath</code>} 
  onFollow={() => handleFollow()} 
/>;

Passing props is how data flows from parent to children in React apps as it adhere to the Unidirectional data flow. That said, they must follow one single rule: Never to modify it’s own props. All React components must act like pure functions with respect to their props.

Consider the following function, which is considered “impure” as it changes it’s own input

/**
 * AddToNumbers
 *
 * @param {Array<number>} numbers
 * @param {number} newNumber 
 * @return {Array<number>}
 */
function addToNumbers(numbers, newNumber) {
  numbers.push(newNumber);
  return numbers;
};

In contrast, take a look at this version of the function which is “pure” as it does not attempt to change the input.

/**
 * AddToNumbers
 *
 * @param {Array<number>} numbers
 * @param {number} newNumber 
 * @return {Array<number>}
 */
function addToNumbers(numbers, newNumber) {
  const numbersCopy = array.map((n) => n);
  numbersCopy.push(newNumber);
  return numbersCopy;
};

Component Lifecycle with Hooks

In modern React applications, we manage React Component Lifecycle with hooks like React useEffect Hook and React useState Hook rather than lifecycle methods

Fork me on GitHub