Episode 2: Components and Props.

Episode 2: Components and Props.

Introduction

This episode focuses on the core concept of components and props in React. Students will learn how to build reusable components, pass data between components using props, and understand the lifecycle methods of React components. By the end of this section, students will have a solid understanding of how components and props work in React and will have hands-on experience building and using components and props in real-world applications.


Outline

I. Understanding Components and Props

  • What are components in React and how do they work?

  • Understanding the role of props in passing data between components

  • Examining the structure and syntax of components and props

II. Building Reusable Components

  • Creating and rendering reusable components

  • Using props to pass data to reusable components

  • Building and rendering complex components using reusable components

III. Passing Data Between Components using Props

  • Understanding how to pass data from parent components to child components

  • Using props to update the state of child components

  • Managing and controlling the flow of data between components

IV. Examining Component Lifecycle Methods

  • Understanding the lifecycle methods of React components

  • Using lifecycle methods to control the behavior of components

  • Examining the use of lifecycle methods in real-world applications


Understanding Components and Props

What are components in React and how do they work?

Components are the building blocks of a React app, they define the structure and appearance of the user interface. They are similar to functions, they accept inputs (props) and return a React element that describes how a section of the UI should look. Components allow you to split the UI into independent, reusable pieces, and think about each piece in isolation.

Understanding the role of props in passing data between components

Props are a way to pass data from a parent component to a child component. Props are essentially arguments that are passed to a component when it is rendered. They can be used to pass data such as text, numbers, objects, or functions, to a component and are read-only within the component.

Examining the structure and syntax of components and props

Here's a simple example of a component with props:

import React from 'react';

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

export default Greeting;

And here's an example of how you can use the component and pass in props:

import React from 'react';
import ReactDOM from 'react-dom';
import Greeting from './Greeting';

ReactDOM.render(
  <Greeting name="Sammy" />,
  document.getElementById('root')
);

Points to Remember

  • Components in React are building blocks of the user interface, and they work by taking in inputs (props) and returning React elements to describe what should appear on the screen.

  • Props are used to pass data between components, and they are like function arguments in that they provide the components with the information they need to render.

  • Components have a structure and syntax that consists of a JavaScript function that returns React elements. Props also have a specific syntax and structure for passing data.


Building Reusable Components

A. Creating and rendering reusable components Reusable components are components that can be used multiple times within a single app. By creating reusable components, you can make your code more organized, easier to maintain and improve the overall performance of your app.

Here's an example of a reusable component:

import React from 'react';

function Comment(props) {
  return (
    <div>
      <p>{props.text}</p>
      <p>By {props.author}</p>
    </div>
  );
}

export default Comment;

Using props to pass data to reusable components

In the example above, we used props to pass data to the reusable component. We passed two pieces of data: text and author. These props can be used to display dynamic data within the component.

Building and rendering complex components using reusable components

By combining reusable components, you can build more complex components. For example, you could create a reusable CommentList component that displays a list of Comment components:

import React from 'react';
import Comment from './Comment';

function CommentList(props) {
  return (
    <div>
      {props.comments.map((comment) => (
        <Comment
          key={comment.id}
          text={comment.text}
          author={comment.author}
        />
      ))}
    </div>
  );
}

export default CommentList;

Activity:

  1. Create a component that displays information about a product (e.g. product name, product image, product description).

  2. Create another component that displays a list of products using the first component you created.

  3. Pass data (e.g. product name, product image, product description) to each product component

Points to Remember

  • Reusable components are components that can be used multiple times within an application. They allow developers to write less code and make their applications more modular and maintainable.

  • To create reusable components, you write a component once and then render it multiple times, passing in different props to customize its behavior.

  • To build complex components using reusable components, you can nest components within each other and pass props down the component hierarchy.


Passing Data Between Components using Props

One of the key features of React is the ability to pass data between components. Components are the building blocks of a React app, and they are used to encapsulate and reuse code. The ability to pass data between components is essential for creating complex and dynamic user interfaces.

In React, data is passed between components using props. Props is short for "properties", and it is used to pass data from one component to another. Props are essentially arguments passed to a component, and they can be used to pass any data, including strings, numbers, objects, and even functions.

The structure and syntax of components and props in React is straightforward. A component is defined using a function or a class, and props are passed to the component using the props object. In a functional component, the props object is passed as an argument to the function. In a class component, the props object is accessible via the this.props property.

Here is an example of a simple component that takes a single prop:

import React from 'react';

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

In this example, the Greeting component takes a single prop, name. The component uses this prop to render a greeting to the user. The component is called like this:

<Greeting name="John" />

In this example, the name prop is passed to the Greeting component, and it is used to render the greeting to the user. The name prop can be changed dynamically to display different greetings to the user.

Props can also be used to pass data between nested components. For example, consider the following component hierarchy:

App
  |
  --- Greeting
        |
        --- Avatar

In this example, the App component is the top-level component, and it contains a Greeting component. The Greeting component, in turn, contains an Avatar component. To pass data from the App component to the Avatar component, the data must be passed through the Greeting component.

import React from 'react';

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

function Greeting(props) {
  return (
    <div>
      <h1>Hello, {props.name}!</h1>
      <Avatar src={props.avatar} alt={props.name} />
    </div>
  );
}

function App() {
  return (
    <div>
      <Greeting name="John" avatar="https://example.com/avatar.png" />
    </div>
  );
}

In this example, the App component passes the name and avatar props to the Greeting component. The Greeting component then passes the avatar prop to the Avatar component. The Avatar component uses the src and alt props to render an avatar image for the user.

Reusable components are another important aspect of building React apps. Reusable components are components that can be used in multiple places within an app. Reusable components can be created by passing props to a component, and then using the props

Points to Remember

  • React allows data to be passed between components using props (short for properties). Props can be used to pass any data, including strings, numbers, objects, and functions.

  • Components are defined using a function or a class, and the props object is passed as an argument to the function or is accessible via the this.props property in a class component.

  • Props are passed to a component when the component is called. For example, <Greeting name="John" />. Nested components can receive data from parent components by being passed props from the parent component.

  • Reusable components can be created by passing props to a component. Reusable components are components that can be used in multiple places within an app.


Examining Component Lifecycle Methods

Component lifecycle methods in React are methods that are called at specific points during the lifetime of a component. They are used to perform actions or update the state of a component in response to changes in its props or state. There are several lifecycle methods available in React, and they can be used to control the behavior of a component and to optimize its performance.

The lifecycle methods are divided into three categories: mounting, updating, and unmounting. Mounting refers to the process of initializing a component and rendering it to the DOM for the first time. Updating refers to the process of re-rendering a component in response to changes in its props or state. Unmounting refers to the process of removing a component from the DOM when it is no longer needed.

The following are the most commonly used lifecycle methods:

  1. componentDidMount()

    • This method is called after a component has been successfully mounted and added to the DOM. It can be used to trigger side effects, such as fetching data from an API or setting up event listeners.
    javascriptCopy codeimport React, { Component } from 'react';

    class MyComponent extends Component {
      componentDidMount() {
        // Fetch data from an API
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => {
            // Update the state with the fetched data
            this.setState({ data });
          });

        // Set up event listeners
        document.addEventListener('click', this.handleClick);
      }

      handleClick = () => {
        console.log('Click event detected');
      };

      render() {
        // Render the component
        return <div>My Component</div>;
      }
    }

    export default MyComponent;

In this example, the componentDidMount() method is used to fetch data from an API and update the component's state with the fetched data. The method is also used to set up a click event listener on the document. The handleClick method is defined as a class property using the arrow function syntax.

This is just one example of how you can use the componentDidMount() method. The method can be used for any side effect, such as triggering animations, setting timers, or initializing libraries. The important thing to remember is that the componentDidMount() method is called only once, immediately after a component has been successfully mounted and added to the DOM.

  1. shouldComponentUpdate(nextProps, nextState)

    • This method is called before a component updates, and it is used to determine whether the component should update. If it returns false, the component will not re-render.

Here is an example code of how shouldComponentUpdate() can be used in a React component:

    class MyComponent extends React.Component {
      constructor(props) {
        super(props);
        this.state = {
          data: [],
        };
      }

      componentDidMount() {
        // fetch data from API
        this.fetchData();
      }

      fetchData() {
        fetch("https://api.example.com/data")
          .then((response) => response.json())
          .then((data) => {
            this.setState({ data: data });
          });
      }

      shouldComponentUpdate(nextProps, nextState) {
        // check if data has changed
        if (this.state.data !== nextState.data) {
          return true;
        }
        return false;
      }

      render() {
        return (
          <div>
            <h1>Data:</h1>
            <ul>
              {this.state.data.map((item) => (
                <li key={item.id}>{item.name}</li>
              ))}
            </ul>
          </div>
        );
      }
    }

In this example, the component fetches data from an API when it is mounted (componentDidMount()). The shouldComponentUpdate() method is used to determine if the component should update when the data changes. The method checks if the data state has changed by comparing this.state.data with nextState.data. If the data has changed, the method returns true, which triggers the component to re-render. If the data has not changed, the method returns false, which prevents the component from re-rendering.

  1. componentDidUpdate(prevProps, prevState)

    • This method is called after a component has updated and re-rendered. It can be used to trigger side effects, such as updating the position of an element in response to a change in its size.

Here is an example of the componentDidUpdate lifecycle method in use:

    import React, { Component } from "react";

    class ExampleComponent extends Component {
      state = {
        count: 0,
      };

      componentDidUpdate(prevProps, prevState) {
        if (prevState.count !== this.state.count) {
          console.log(`Count has changed from ${prevState.count} to ${this.state.count}`);
        }
      }

      handleClick = () => {
        this.setState({ count: this.state.count + 1 });
      };

      render() {
        return (
          <div>
            <p>Count: {this.state.count}</p>
            <button onClick={this.handleClick}>Increment</button>
          </div>
        );
      }
    }

    export default ExampleComponent;

In this example, the ExampleComponent has a state variable count that keeps track of the number of times the "Increment" button has been clicked. When the component updates (i.e., when the count changes), the componentDidUpdate method is called and it logs a message to the console indicating that the count has changed.

It is important to note that componentDidUpdate should be used judiciously, as excessive use can negatively impact the performance of a React app.

  1. componentWillUnmount()

    • This method is called before a component is unmounted and removed from the DOM. It can be used to clean up any side effects, such as removing event listeners or cancelling network requests.

Here is an example of how the componentWillUnmount lifecycle method could be used in a real-life application:

    javascriptCopy codeimport React, { Component } from "react";

    class MyComponent extends Component {
      componentDidMount() {
        window.addEventListener("resize", this.handleResize);
      }

      componentWillUnmount() {
        window.removeEventListener("resize", this.handleResize);
      }

      handleResize = () => {
        console.log("Window resized");
      };

      render() {
        return <div>My Component</div>;
      }
    }

    export default MyComponent;

In this example, the componentDidMount method is used to add a resize event listener to the window. The componentWillUnmount method is used to remove the resize event listener from the window when the component is unmounted. This is important to prevent memory leaks and ensure that the component only responds to events while it is active on the page.

Component lifecycle methods are a powerful tool for controlling the behavior of components in React. They can be used to perform actions or update the state of a component in response to changes in its props or state, and they can help optimize the performance of an app.

It's important to note that lifecycle methods should be used sparingly and only when necessary, as they can impact the performance of an app. When using lifecycle methods, it's important to carefully consider the impact they will have on the behavior of a component and to test their implementation thoroughly.

Points to Remember

  • React component lifecycle methods are called at specific points during the lifetime of a component and are used to perform actions or update the state of a component in response to changes in its props or state. The lifecycle methods are divided into three categories: mounting, updating, and unmounting. The most commonly used lifecycle methods are:
  1. componentDidMount() - called after a component has been successfully mounted and added to the DOM. Can be used to trigger side effects like fetching data or setting up event listeners.

  2. shouldComponentUpdate(nextProps, nextState) - called before a component updates, used to determine if the component should update. If it returns false, the component will not re-render.

  3. componentDidUpdate(prevProps, prevState) - called after a component has updated and re-rendered, can be used to trigger side effects like updating the position of an element.


Sharing my understanding of concepts and approaches to problem-solving gives me happiness and it also helps me further my career. If you have any questions, feel free to reach out!

Connect with me on Twitter, LinkedIn, and GitHub!

Also, reach out to me, if you love to discuss startup building and building open-source software directly through my email📧.

Did you find this article valuable?

Support Were Samson Bruno by becoming a sponsor. Any amount is appreciated!