The Ultimate React Guide 2024: A Deep Dive into Creating a Project with Vite, Component Lifecycles, Props, Styling & More

Introduction

Let me take a wild guess: you’ve just finished learning JavaScript, and you’ve been hearing a lot about React, and you’re thinking, “What the heck is React?” or you are like Jimmy, who needs to learn React but don’t know where to start from.

Congratulations! You’ve just found the perfect guide to help you get started.

In this tutorial, you’ll learn about React components and their lifecycle, how to create elements using the JSX (JavaScript XML) syntax, states and props, and the different ways to style React components.

What is React?

React is a JavaScript library that enables us to create the user interface for software applications – including web and native user interfaces. Unlike plain HTML and CSS, it allows us to build highly functional applications easily. 

It also uses JSX syntax, allowing us to write HTML within JavaScript. In React, webpages can be divided into various components.

You’ll learn more about JSX and React components in the coming sections. Next, let me walk you through how to set up React on your computer.

How to Set up React on Your Local Computer

To start creating web applications with React, you need to install the Node.js – an open-source JavaScript runtime environment. 

After installation, run the command below within your terminal. It will return the current version of Node.js installed on your computer.

node -v

Next, create a React project using Vite – a development environment that enables us to create React projects. 

Run the code snippet below within your terminal, provide a name for your project, and select React as the framework.

npm create vite@latest

Navigate into the project folder via your terminal and run the code snippet below to install the project dependencies.

npm install

Start the development server by running the npm run dev within your terminal.

How to Create React Elements with JSX

JSX – an acronym for JavaScript XML is a syntax that enables us to write HTML code within JavaScript. Unlike HTML and CSS, creating web applications with JSX in React enables us to create reusable and readable elements.

React provides a function called React.createElement() that accepts three arguments – the HTML element, an object containing the HTML element’s attribute, and the content of the HTML element.

Let’s consider the code snippet below.

import React from “react”;

export default function App() {
    const data = React.createElement(“h1”, {}, “Hello World”);
    return data;
}

The code snippet above creates an App function that returns the data variable containing a <h1> tag with the text “Hello World”. Imagine you want to create multiple contents using this syntax; you may need to create a variable with nested JSX elements. This method will make your code messy and difficult to read or understand.

To solve this problem, JSX provides a much better and easier way to create React elements. 

export default function App() {
    return (
        <div>
            <h1>Hello World</h1>
        </div>
    );
}

The code snippet above returns a parent div element containing a <h1> tag with “Hello World” as its content.

It is important to note that JSX can only have a single parent element. You can not return more than one parent element from a JSX function.

export default function App() {
    return (
            <h1>Hello World</h1>
            <p>Welcome to React</p>
    );
}

The code snippet above is incorrect because the h1 and p tags are not within a parent element. The correct way of returning multiple elements from the JSX function is by placing them within a parent container.

export default function App() {
    return (
        <div>
            <h1>Hello World</h1>
            <p>Welcome to React</p>
        </div>
    );
}

Finally, you can also render content within JavaScript variables on the webpage via JSX. Consider the code snippet below.

export default function App() {
    const name = “Jimmy”;
    const message = { user: “jimmy”, content: “Welcome to React” };
    const greeting = <p>Thank you for joining the React community</p>;

    return (
        <div>
            <h1>Hello {name}</h1>
            <p>{message.content}</p>
            {greeting}
        </div>
    );
}
React components

How to Use and Create Components in React

React components are reusable JavaScript functions that return JSX elements representing a specific part of a user interface. For instance, a web page can be divided into header, main, and footer components.

React State Management

Components in React allow us to adhere to the DRY (Don’t Repeat Yourself) principle in software engineering. If a particular section of the user interface is duplicated elsewhere within the application, you can extract that section into a component. 

This practice improves code readability and makes maintenance more straightforward.

React components are of two types – Class or Stateful components and the Function or Stateless components.

Class Components

This is an old method of creating components in React. The components are declared using the JavaScript class keyword. They are also referred to as “stateful” because the states – variables within the components are bound to them using the JavaScript this keyword.

import { Component } from “react”;
class ComponentName extends Component {
    constructor(props) {
        super(props);
        this.state = {
            //👉🏻 contains state variables
        };
    }
    render() {
        return <div>{/** — UI elements –*/}</div>;
    }
}

– From the code snippet above,

  • The component extends the Component class provided by React and has a constructor method.
  • All states are declared using the this.state keyword within the constructor method.
  • The render function displays the user interface associated with the component.

You should avoid using class components in modern React applications because new features are primarily focused on function components and hooks. 

However, you might encounter class components in older codebases. It is not advisable to use class components when developing React applications.

Function Components

Function components are similar to the way we declare functions in JavaScript. They accept a single argument known as props (object data) that may be returned together with the JSX element. It is a modern approach to writing React and contributes to a cleaner and more readable code. 

Coupled with hooks, it offers a more concise and expressive way to manage state – you’ll learn about that shortly.

The code snippet below shows how to create function components in React.

export default function ComponentName() {
    return (
        <div>
            <h2>Hello World</h2>
        </div>
    );
}

Nesting React components

It is important to note that you can also return components with another component in React. This process is called Nesting, and it enables us to create higher-order components that break the various parts of the user interface into simpler or modular sections.

For example, you might have a Nav component that needs to be rendered within the Header and Footer components. 

To do this, you need to first create the Nav component, as shown below.

//👇🏻 Within Nav.jsx
export default function Nav() {
    return (
        <ul>
            <li>
                <a href=’/home’> Home</a>
            </li>
            <li>
                <a href=’/about’> About Us</a>
            </li>
            <li>
                <a href=’/contact’> Contact Us</a>
            </li>
            <li>
                <a href=’/blog’> Blog</a>
            </li>
        </ul>
    );
}

Then, import the Nav component and render it within the Header and Footer components.

import Nav from “./Nav”
//👇🏻 Within Header.jsx
export default function  Header(){
    return (
        <header>
            <Nav />
            <h1>This is the header</h1>
        </header>
    );
}

//👇🏻 Within Footer.jsx
export default function Footer(){
    return (
        <footer>
            <Nav/>
            <h1>This the footer</h1>
        </footer>
    );
}

PS:  Every React component name must begin with a capital letter.

The Lifecycle of a React Component

The lifecycle of a React component simply refers to the phases from when a component is added to the DOM tree to when it is removed from the DOM tree. It can be divided into three phases: the Mounting, Updating, and Unmounting phases.

The React useEffect hook can be used to demonstrate each phase within the lifecycle. It enables us to keep track of various changes within a React component, such as when a component is added or removed from the DOM tree, re-rendering, etc.

It also accepts two parameters: a function and a dependency array. The function executes any instruction given to it based on the dependency array. You’ll learn more about them shortly as we go through the various phases within the component’s lifecycle.

import { useEffect } from “react”;

export default function Component() {
    useEffect(() => {
          // 👉🏻 execute a function here     }, []); // 👈🏼 dependency array
  return (
      <div>
          <p>Hello world</p>
      </div>
    )
}

The Mounting Phase

In this phase, the component is rendered or added to the DOM tree. When a user loads a web page, the web components are retrieved and displayed on the screen; this process is known as the mounting phase.

Let’s take a look at some examples:

import { useEffect, useState } from “react”;

export default function App() {
    const [count, setCount] = useState(0);

    const increment = () => setCount( prev => prev + 1)
    const decrement = () => setCount( prev => prev – 1)

    useEffect(() => {
        console.log(“Run everytime count changes”);
    });

    useEffect(() => {
        console.log(“Run only once when component is mounted”);
    }, []);
   
    return (
        <div>
            <h1>Count: {count}</h1>
            <div>
                <button onClick={increment}>Increase</button>
                <button onClick={decrement}>Decrease</button>
            </div>
        </div>
    );
}

From the code snippet above, the useEffect hook without a dependency array runs every time the count changes. That is, whenever the page re-renders the useEffect hook executes its function. 

However, the useEffect with an empty dependency array executes only once when the component mounts or is added to the DOM tree. This method is commonly used when you need to fetch data from an API endpoint and display it on the page.

The Updating Phase

This phase keeps track of state changes of a particular variable and executes a function when that change occurs. The dependency array contains the list of variables to keep track of, and the useEffect function is executed every time the state changes.

PS:  It also executes the useEffect function on its initial render.

For example, suppose you want to perform some action every time the count changes; you can add the count state to the dependency array.

import { useEffect, useState } from “react”;

export default function App() {
    const [count, setCount] = useState(0);

    const increment = () => setCount( prev => prev + 1)
    const decrement = () => setCount( prev => prev – 1)

    useEffect(() => {
        console.log(“executes only when the count changes, Count is: “, count);
    }, [count]);
   
    return (
        <div>
            <h1>Count: {count}</h1>
            <div>
                <button onClick={increment}>Increase</button>
                <button onClick={decrement}>Decrease</button>
            </div>
        </div>
    );
}

To further explain how it works, let’s add another state and button that toggles its value. Then, we can keep track of the name changes and execute a function when these changes occur.

import { useEffect, useState } from “react”;

export default function App() {
    const [count, setCount] = useState(0);
    const [name, setName] = useState(“Ankur”);

    const increment = () => setCount( prev => prev + 1)
    const decrement = () => setCount(prev => prev – 1)
    const toggleName = () => name === “Ankur” ? setName(“Tyagi”) : setName(“Ankur”);

    useEffect(() => {
        console.log(“Name changed to”, name);
    }, [name]);
   
    return (
        <div>
            <h1>My Name is {name}</h1>
            <button onClick={toggleName}>Toggle Name</button>
            <h1>Count: {count}</h1>
            <div>
                <button onClick={increment}>Increase</button>
                <button onClick={decrement}>Decrease</button>
            </div>
        </div>
    );
}

The useEffect function only runs when the name changes because it depends on the name variable. You can also add multiple dependencies to the array, and it will run when any of those variables change.

The Unmounting Phase

This phase describes the process of removing a component from the DOM tree. The unmounting phase enables us to perform various actions, such as terminating network requests, canceling subscriptions, etc, within a clean-up function.

Suppose you have a function that fetches or updates data at intervals within your application; you can add a clean-up function within the useEffect hook that cancels the request.

useEffect(() => {
    fetchDataAtIntervals();
    return () => {
        // cancel request here
    };
}, []);

States and Props in React

Creating a stunning user interface for your application is only half of the work done in React. Another essential part of your application is the logic – questions like, is it accepting the correct data format? Is it functional? This leads us to the logical aspect  – States and Props (Properties).

States simply refer to the current value of a variable at a particular point in time. They are bound to a component and can only be accessed directly from that component. One of its distinguishing features is that its value can change at any point within the application.

Consider the Counter app we created earlier that has two states – name and count.

const [count, setCount] = useState(0);
const [name, setName] = useState(“Ankur”);

States are declared using the format below.

const [state, setState] = useState(<initial_value>)

The useState hook returns an array with two elements. The first value within the array represents the state name, and it holds the current value of the state. The second value is a function that enables us to update the state’s value.

However, since states are local to a component, how can we share data between different components in React? This is possible with Props. They act as messengers carrying data from one component to another. 

What are Props?

Props are immutable, meaning a child component can not change the values of the props received from the parent component. Also, any changes made within the parent component are reflected within the child components.

For instance, you can create a Counter component that accepts the count, increment, and decrement functions as props from the application and displays the counter.  

import { useEffect, useState } from “react”;

export default function App() {
    const [count, setCount] = useState(0);

    const increment = () => setCount( prev => prev + 1)
    const decrement = () => setCount(prev => prev – 1)

    return (
        <div>
      <Counter count={count} increment={increment} decrement={decrement}/>
        </div>
    );
}

function Counter({count, increment, decrement}) {    return (
        <div>
                <h1>Count: {count}</h1>
            <div>
                <button onClick={increment}>Increase</button>
                <button onClick={decrement}>Decrease</button>
            </div>
        </div>
   

    )
}

The values are destructured from the props object and utilized within the component, as shown above.

How to Style React Components: CSS and Beyond

There are several methods to style React components. However, unlike HTML and CSS, JSX elements in React cannot use the class attribute since ‘class’ is a reserved keyword in JavaScript. Instead, the className attribute is used to denote CSS classes.

Here are some of the ways by which you can style your React apps:

Inline styling

Every JSX element has a style attribute that enables us to add CSS styles to the element. The styles are added to an object and named using the camel case naming convention. For example, “font-size” in CSS is written as “fontSize” in React. 

This method is commonly used for styling individual JSX elements. However, this method is not recommended for styling every element within your React application because it can make your code longer and less readable.

The code snippet below uses the inline style method.

export default function App() {

    const headerStyle = {
        fontSize: “2rem”,
        textAlign: “center”,
    }
   
    return (
        <div style={{ width: “100%”, height: “100vh” }}>
            <p style={headerStyle}>Hello World</p>
        </div>
  )
}

Component stylesheet

This method is commonly used in large applications that involve a large number of components. Each component has a CSS file that styles its JSX elements. It also prevents className conflicts and makes debugging easier.

For instance, a Counter component has a Counter.css file created to style its elements. For this to work, you need to import the CSS file into its component to enable the JSX elements to access the styles.

import “./App.css”
export default function App() {
    return (
        <div className=”container”>
            <p className=”heading”>Hello World</p>
        </div>
  )
}

Single Stylesheet

In this method, all the components within the application refer to a single CSS file. It is mostly used in small applications with a few components because it is prone to class name errors and difficult to debug.

Tailwind CSS

Tailwind CSS is a popular CSS framework used in React applications. It is highly customizable and uses the utility-first approach to enable us to add styles directly to the HTML tags within our application. 

It is widely used within the React community because it is flexible and easy to set up and makes it easy to design responsive applications for various screen sizes.

React UI libraries

There are numerous ways to style React applications. Some of them are the MUI library, Styled Components, Chakra UI, and many others. Depending on your choice, React allows you to style your applications using your preferred UI library.

Conclusion

So far you have learnt the following:

  • what React is and how to set up React on your computer
  • how to create JSX elements
  • the types and uses of components in React
  • the lifecycle of a React component
  • states and props, and how to style React components.

React is an open-source JavaScript with a large community constantly working to provide amazing features that enable users to build stunning and highly performant applications.

Thank you for reading.

If you like this blog and want to read more about ReactJS and JavaScript then start reading some of recent articles.

Leave a Comment

Your email address will not be published. Required fields are marked *