State and Props in React Components.

State and Props in React Components.

Introduction

State and Props in react are used to pass and manage data between react components. They are the foundation upon which a react application is built.

Props (properties) are read-only data that are passed from a parent component to a child component. State on the other hand, is a way to manage and store dynamic data that can change over time within a component. Unlike props, which are passed hierarchically, state is managed internally by a component and can be updated using the setState or useState method.

React component-based architecture

In comparison with the traditional Model-View-Controller, React provides a component-based architecture. React component-based architecture is a fundamental aspect of react, as it allows for isolating and decomposing parts of the application, in creating a whole web application. This unique architecture allows for complex web applications to be distilled into small reusable independent components.

Components emulate the concept of AJAX requests, allowing client-side service, which enables the DOM to be dynamically updated. The independent nature of components diffuses the effect of one component from others. React manages components effectively through its virtual DOM which uses an algorithm known as diffing to compare and reflect changes in the UI. When data changes occur, the DOM is not directly manipulated, rather, a virtual representation of the DOM is created by abstraction. The Virtual DOM is a lightweight copy of the actual DOM. React uses it to keep track of changes and perform updates in batches, reducing the need for direct manipulation of the real DOM. This abstraction allows React to optimize the process of rendering and updating UI components, leading to faster rendering and better performance.

The component-based architecture requires all the methods and APIs about a component to exist within its structure.

It provides an environment for clean and organized code, which makes managing the application easier. It also makes debugging and code testing easier. It reduces code duplication, as the essence of components is reusability.

Props in react components

Props, known as properties, are immutable data passed to components when they are created. As react decomposes the UI into various components, when these components need to send data to themselves, they do so by passing props.

The data flow structure in react follows a unidirectional pattern, flowing hierarchically through the component tree using props. Interaction between a child component and its parent is possible by inheritance, where the callback function of the parent is passed as props.

// Parent.jsx
import React from 'react';
import Child from './Child';

function Parent() {
  const data = "Hi, I'm passing prop";
  return <Child message={data} />;
}

// Child.jsx
import React from 'react';

function Child(props) {
  return <div>{props.message}</div>;
}

export default Child;

Passing props

In passing prop, if a component receives the wrong type of prop, it can lead to bugs and unexpected errors in the application.

import React from 'react';

function App (props) {
  return <div>{props.message}</div>;
}
export default App;


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

function Message () {
  // we pass an integer instead of a string.
  return <App message = {78} />;
}
export default Message;

The parent component app passes a prop to its child component message. It passes a string as prop, but the child component receives an integer instead. To solve this, React provides a mechanism for props validation called prop types.

PropTypes are no longer available in the react package, the proptypes dependency has to be added to the react application. This dependency can be added to the react application by running the command in the terminal;

npm install prop-types --save

Let's fix the issue using prop types. First, the method is to be imported into the React application.

import React from 'react';
import PropTypes from 'prop-types';

function App (props) {
  return <div>{props.message}</div>;
}

App.propTypes = {
  message: PropTypes.string.isRequired
};
export default App;

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

function Message() {
  return <App message = {78} />;
}
export default Message;

When the code is run, the console will throw an error message indicating that the prop type doesn't match the expected type defined in propTypes.

Props destructuring

For clean and readable code, props destructuring is incorporated. Props destructuring is a common practice in react. Destructuring was introduced by JavaScript ES6.

The snippet below provides an insight into destructuring.

const Userinfo = {
  name: "Carl",
  age: 20,
  pet: false
}
//the Userinfo object is destructured thus;
const { name, age, pet } = Userinfo;

React provides two ways of destructuring props in a component. The first method can be done in the function parameter, and the second way is by destructuring props in the function body.

Destructuring props in the function parameter can be done like this;

import React from 'react'

function Userinfo = ({name, age, pet}) {
    return (
        <div>
            <h1> User Details</h1>
            <p> Name : {name} </p>
            <p> Age : {age} </p>
            <p> Own Pet : {pet ? "Yes" : "No"} </p>
        </div>
    )
}

export default Userinfo;

Destructuring props in the function body can be done like this;

import React from 'react'

function Userinfo (props) {
const {name, age, pet} = props;
    return (
        <div>
            <h1> User Details</h1>
            <p> Name : {name} </p>
            <p> Age : {age} </p>
            <p> Own Pet : {pet ? "Yes" : "No"} </p>
        </div>
    )
}

export default Userinfo;

State in react components

State is an object which stores and manages dynamic information within a component. Whenever the state object changes, the component re-renders. Similar to a function’s local scope, the state cannot be accessed and modified outside its component. State in react determines a component's behavior. Every component in react has an inbuilt state object.

Managing state in class components

State can be managed and utilized in a class component by using a constructor. When a class instance is created, the constructor method is automatically called. The constructor is a method used to initialize the local state of a component, and bind methods that occur in the component.

When creating class components in react, the constructor of the parent class is to be called using super(props) to initialize the components initial state and inherit the behaviour of the component class.

Setting up the components initial state is to be done within the constructor, and the this keyword is used to set the initial state of the component. The state in class components cannot be altered except by setState() method. The setState() method is used to update the state of a component and trigger a re-render of the component to reflect the updated state.

Here's an example of how to use state in class components.

import React, { Component } from 'react';

class ElectionPoll extends Component {
  constructor(props) {
    super(props);

    // Initializing state
    this.state = {
      candidates: [
        { id: 1, name: 'Candidate A', votes: 0 },
        { id: 2, name: 'Candidate B', votes: 0 },
        { id: 3, name: 'Candidate C', votes: 0 }
      ]
    };

    // Binding the event handler to the component instance
    this.voteForCandidate = this.voteForCandidate.bind(this);
  }

  // setState method in the event handler to update the vote state of a candidate.
  voteForCandidate(id) {
    this.setState(prevState => ({
      candidates: prevState.candidates.map(candidate =>
        candidate.id === id ? { ...candidate, votes: candidate.votes + 1 } : candidate
      )
    }));
  }

  render() {
    return (
      <div>
        <h1>Vote Your Candidate</h1>
        <ul>
          {this.state.candidates.map(candidate => (
            <li key={candidate.id}>
              <p>{candidate.name}</p>
              <p>Votes: {candidate.votes}</p>
              <button onClick={() => this.voteForCandidate(candidate.id)}>Vote</button>
            </li>
          ))}
        </ul>
      </div>
    );
  }
}

export default ElectionPoll;

Here, the ElectionPoll class component manages the vote count for each contestant with state. The constructor method initializes the state with an array of contestants, with an initial vote count of 0. The voteForCandidate method is then defined to update the vote count when a user clicks the "Vote" button next to a candidate's name. The render method displays the list of candidates with their names, current vote counts, and buttons to vote for them.

Managing state in functional components

Functional components are defined using JavaScript functions. Functional components have become the preferred way to define components in react applications, as they are easier to read than class components. In the earlier versions of react, state and lifecycle methods were only supported in class components. V6 React enabled managing state and lifecycle in functional components using hooks.

One essential hook provided by react is the useState hook. The useState hook creates a state in a functional component and manages the form of the state.

To use state in functional components, we have to first import the hook to manage the state from React. Then we initialize the state.

Below is an example of using state in react functional components.

//importing the hook from React
import { useState } from 'react';

function ElectionPoll() {
//initializing the state
  const [candidates, setCandidates] = useState([
    { id: 1, name: 'Candidate A', votes: 0 },
    { id: 2, name: 'Candidate B', votes: 0 },
    { id: 3, name: 'Candidate C', votes: 0 }
  ]);

  const voteForCandidate = (id) => {
    setCandidates(prevCandidates => prevCandidates.map(candidate =>
      candidate.id === id ? { ...candidate, votes: candidate.votes + 1 } : candidate
    ));
  };

  return (
    <div>
      <h1>Vote Your Favorite Candidate</h1>
      <ul>
        {candidates.map(candidate => (
          <li key={candidate.id}>
            <p>{candidate.name}</p>
            <p>Votes: {candidate.votes}</p>
            <button onClick={() => voteForCandidate(candidate.id)}>Vote</button>
          </li>
        ))}
      </ul>
    </div>
  );
}

export default ElectionPoll;

Asynchronous updates in react components

Updating state in React is asynchronous, when an update to a component's state is requested, React does not apply the changes immediately, instead, it queues the requested changes and schedules a state transition to occur. What this update technique does, is prevent unnecessary re-rendering and ensure a smoother user experience.

The asynchronous update is done by a reconciliation method. Whenever the component's state is updated, the method is called. What the method does, is analyze the current DOM with the virtual DOM created by react through diffing, comparing changes before calling the render method.