React JS Introduction

About

React.js is a JavaScript library for building user interfaces. It was created by Facebook and is now maintained by a large community of developers. React allows developers to build reusable UI components and manage the state of those components efficiently. With React, you can build complex and dynamic web applications with a high level of performance. React uses a virtual DOM, which improves the speed and efficiency of updates and rendering.

Important Components

There are several important components in React that developers should be familiar with:

  1. Components: React applications are built using reusable components. A component is a piece of code that defines a part of a UI, such as a button or a form. Components can be defined using JavaScript classes or functions.

  2. JSX: React uses JSX, a syntax extension for JavaScript, to define the structure of a component. JSX allows you to write HTML-like elements in your JavaScript code, making it easy to define the layout of a component.

  3. Props: Props, short for properties, are used to pass data into a component from its parent. Props are used to configure a component and can be used to make a component more reusable.

  4. State: State is used to store and manage the data that is specific to a component. It is used to track the internal state of a component and update the component's UI when the state changes.

  5. Lifecycle methods: React provides several lifecycle methods that allow developers to perform specific actions at different stages of a component's lifecycle. These methods can be used to handle initialization, updates, and cleanup.

  6. Hooks: Hooks are functions that allow developers to use state and lifecycle methods in functional components. They were introduced in React 16.8 and provide a way to write and manage stateful logic in functional components, which previously was possible only in class components.

Components

In React, a component is a piece of code that represents a part of a user interface. Components are reusable, and they can be nested inside other components to build complex user interfaces.

There are two types of components in React:

  1. Functional Components: These are simple JavaScript functions that take in props (short for properties) and return a React element. They do not have their own state or lifecycle methods.

  2. Class Components: These are JavaScript classes that extend the React.Component class. They have their own state and lifecycle methods, and can handle more complex logic.

Functional components are simpler to write and understand and recommended to use, unless you need to use state or lifecycle methods in your component.

Here's an example of a simple functional component that takes in a "name" prop and renders it in a h1 element:

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

And here's an example of a simple class component that also takes in a "name" prop and renders it in a h1 element:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}</h1>;
  }
}

A component can also handle its own state, props, lifecycle methods and functionality. And also you can pass the data from parent component to child component via props, and child component can pass data to parent component via callback functions.

It's important to note that when creating components, it's best practice to keep them as small and simple as possible and also use them in a modular way to make your code more maintainable and easy to understand.

JSX

JSX is a syntax extension for JavaScript that allows developers to write HTML-like elements in their JavaScript code. It is used in React to define the structure and layout of a component.

JSX elements are similar to HTML elements, but they are not actual HTML elements. They are a way to represent the structure of a component in a declarative way. When a JSX element is rendered, it is transpiled into JavaScript code that creates the corresponding HTML element.

For example, the following JSX code:

<div>
  <h1>Hello, World!</h1>
</div>

Will be transpiled to:

React.createElement("div", null,
  React.createElement("h1", null, "Hello, World!")
);

JSX elements can also include JavaScript expressions, which can be used to insert dynamic content into a component. For example, you can use a variable to set the content of an element:

<div>
  <h1>{greeting}</h1>
</div>

JSX is not a part of JavaScript, it needs a transpiler like Babel to convert JSX to JavaScript.

Overall, JSX provides a way to describe the structure and layout of a component in a way that is easy to read and understand, while also making it easy to include dynamic content.

Props

In React, props (short for properties) are used to pass data from a parent component to its child component. Props allow you to make a component more reusable by allowing you to configure it with different data and behavior.

Props are passed to a component as an object, and can be accessed inside the component using the this.props object. For example, the following component expects a prop called name:

class Greeting extends React.Component {
  render() {
    return <h1>Hello, {this.props.name}!</h1>;
  }
}

This component can then be used in another component as follows:

<Greeting name="John" />

Props can also be used to pass callback functions to a component, which can be used to handle events or update the state of the parent component.

Props are read-only, which means that a component cannot modify the props passed to it by its parent. If a component needs to update its own state based on props, it should use the componentDidUpdate lifecycle method.

Props are a powerful feature of React that allows you to create highly reusable and configurable components. By passing data and behavior through props, you can create complex and dynamic applications with a high level of maintainability.

State

In React, state is used to store and manage data that is specific to a component. It is used to track the internal state of a component and update the component's UI when the state changes.

State is defined as an object within a component, and can be accessed and updated using the this.state object. For example, the following component has a state object with a property called count:

class Counter extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      count: 0
    };
  }
  render() {
    return <h1>{this.state.count}</h1>;
  }
}

The setState method is used to update the state and re-render the component. For example, the following code increments the count by 1:

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

It's important to note that React uses a virtual DOM, which means that when the state changes, React will efficiently update the actual DOM to reflect the changes in the state.

State is useful for storing data that is specific to a component and needs to be updated in response to events or user input. It can also be used to store data that is fetched from an API or a database.

It's important to keep in mind that state should be kept minimal and used only when necessary. Overuse of state can make a component difficult to understand and maintain.

Also, state should only be modified using setState() method, direct modification of state using this.state may cause unexpected results, because setState is asynchronous and will be batched for performance reasons.

Lifecycle methods

In React, lifecycle methods are special methods that are called at specific points in a component's lifecycle. These methods allow you to perform specific actions at specific points in the lifecycle of a component, such as initializing state, fetching data, and updating the component when its props or state change.

Here are some of the commonly used lifecycle methods in React:

  1. constructor(props): This method is called before the component is mounted, and is used to initialize the component's state and bind event handlers.

  2. componentDidMount(): This method is called after the component is mounted and has rendered. It's a good place to make API calls, set up subscriptions, and perform other side effects.

  3. componentWillUnmount(): This method is called just before a component is unmounted and destroyed. It's a good place to clean up any subscriptions or resources that were created in componentDidMount().

  4. componentDidUpdate(prevProps, prevState): This method is called after a component's props or state have been updated. It's a good place to perform any logic that should happen after the component has been updated.

  5. shouldComponentUpdate(nextProps, nextState): This method is called before a component is updated. It allows you to control whether a component should re-render or not.

  6. getSnapshotBeforeUpdate(prevProps, prevState): This method is called right before the most recently rendered output is committed to the DOM. It allows you to capture some information from the DOM before it is potentially changed.

    These lifecycle methods give you fine-grained control over how a component behaves, and can be used to implement complex logic and side effects in your application.

It's important to note that with the introduction of hooks in React, some of the lifecycle methods are replaced by hooks, like useEffect, useState, etc. These hooks provide similar functionalities and can be used to replace some of the lifecycle methods.

Hooks

Hooks are a new feature in React that allow you to use state and other React features in functional components, rather than just in class components. Hooks were introduced in React 16.8 to make it easier to share stateful logic and side-effects across components.

Hooks are JavaScript functions that can be called inside a functional component to add specific functionality to it. Here are some of the commonly used hooks in React:

useState(initialState): This hook allows you to add state to a functional component. It returns an array with two elements: the current state and a function to update the state.

useEffect(() => {...}, [dependencies]): This hook allows you to add side-effects to a functional component, such as data fetching, subscriptions and DOM updates.

useContext(context): This hook allows you to access and update context in a functional component.

useReducer(reducer, initialState): This hook allows you to handle complex state and actions, similar to how you would handle them in a Redux store.

useCallback(() => {...}, [dependencies]): This hook allows you to return a memoized callback function.

useMemo(() => {...}, [dependencies]): This hook allows you to return a memoized value.

Using hooks in functional components allows you to write more concise, easy-to-read, and easy-to-understand code. It also makes it easy to reuse stateful logic across multiple components, making your code more modular and maintainable.

It's important to note that hooks can only be called at the top level of a component and also you should not call them in loops, conditions or nested functions.

Full page rendenring example

Here's an example of a full page rendering using React:

import React from 'react';
import ReactDOM from 'react-dom';
function App() {
  return (
    <div>
      <header>
        <h1>Welcome to my website</h1>
      </header>
      <nav>
        <a href="#home">Home</a>
        <a href="#about">About</a>
        <a href="#services">Services</a>
        <a href="#contact">Contact</a>
      </nav>
      <main>
        <h2>Home</h2>
        <p>Welcome to my website, here you can learn more about my services and contact me.</p>
      </main>
      <footer>
        <p>Copyright © {new Date().getFullYear()} My Website</p>
      </footer>
    </div>
  );
}
ReactDOM.render(<App />, document.getElementById('root'));

In this example, App is a functional component that returns a JSX element that renders the structure of a basic website with header, nav, main and footer.

The ReactDOM.render function is used to render the App component into the div element with the id of "root" in the HTML page.

This is a simple example, but you could also use components inside other components, pass data via props, handle state and lifecycle methods, etc.

It's worth noting that in this example, the website is a static one, meaning that it won't update or change after it's rendered, but with the help of hooks or class components you can handle dynamic data and make your website more interactive and dynamic.

Routing

Routing in React is the process of mapping a specific URL path to a component that should be rendered for that path. This allows for different components to be displayed based on the current URL, providing a way to navigate between different pages in a single-page application (SPA).

There are several libraries available for handling routing in React, the most popular of which is React Router.

Here's an example of how routing might be implemented using React Router:

import {
  BrowserRouter as Router,
  Switch,
  Route,
  Link
} from "react-router-dom";
function App() {
  return (
    <Router>
      <nav>
        <ul>
          <li>
            <Link to="/">Home</Link>
          </li>
          <li>
            <Link to="/about">About</Link>
          </li>
          <li>
            <Link to="/services">Services</Link>
          </li>
          <li>
            <Link to="/contact">Contact</Link>
          </li>
        </ul>
      </nav>
      <Switch>
        <Route path="/about">
          <About />
        </Route>
        <Route path="/services">
          <Services />
        </Route>
        <Route path="/contact">
          <Contact />
        </Route>
        <Route path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
}

In this example, BrowserRouter is used to handle browser history and provide the Link and Route components. The Link component is used to create links that navigate to different routes, while the Route component is used to define which component should be rendered for a specific route. The Switch component helps to pick the first matching route.

In the above example, the Home, About, Services, and Contact components will be displayed based on the current URL path.

It's worth noting that routing is a powerful tool that allows for dynamic and interactive navigation in a single-page application. It makes it easy to handle different routes and navigate between different pages without having to refresh the whole page.

Redux

Redux is a JavaScript library that is often used in combination with React to manage the state of an application.

In a React application, the state of the application is typically stored in the components themselves, and passed down through props as the component tree is rendered. However, as the application grows in complexity, managing state in this way can become difficult.

Redux addresses this issue by providing a centralized store for the entire application's state, and a set of rules for how that state can be updated. This allows for better organization and predictability of the state, and makes it easier to debug and understand the state of the application at any given time.

Here's an example of how to implement a simple counter in a React application using Redux:

// actions.js
export const increment = () => ({
  type: "INCREMENT"
});

export const decrement = () => ({
  type: "DECREMENT"
});

// reducer.js
const initialState = {
  count: 0
};

export default function reducer(state = initialState, action) {
  switch (action.type) {

    case "INCREMENT":
      return {
        count: state.count + 1
      };
    case "DECREMENT":
      return {
        count: state.count - 1
      };
    default:
      return state;
  }
}

// store.js
import { createStore } from "redux";
import reducer from "./reducer";

export default createStore(reducer);

// App.js
import React, { useEffect } from "react";
import { useSelector, useDispatch } from "react-redux";
import { increment, decrement } from "./actions";

function App() {
  const count = useSelector(state => state.count);
  const dispatch = useDispatch();

  return (
    <div>
      <h1>Count: {count}</h1>
      <button onClick={() => dispatch(increment())}>Increment</button>
      <button onClick={() => dispatch(decrement())}>Decrement</button>
    </div>
  );
}

export default App;

In this example, the application has a simple state that is a number, and two actions increment and decrement that can be dispatched. The reducer function handles the actions and update the state accordingly. The store is created using the createStore function from the redux library, and the App component use the useSelector and useDispatch hooks to access the state and dispatch actions.

Redux is a powerful library that allows for better organization and management of the state of your application. It's particularly useful when working with large, complex applications, and can make it easier to reason about the state of your application and predict how it will change over time.