React refersher

Vignesh Muthukumaran - Jan 20 - - Dev Community

React

I recently decided to refresh my React skills, since it has been a very long time since I did something with any frontend technologies. React is one of the most used front-end JS libraries that is used to build user interfaces for web apps and native apps(React Native).

How does React work?

React maintains a Virtual DOM, similar to the actual DOM. DOM is a Document Object Model, which is essentially a tree. React works fast by updating the virtual DOM first which is cheaper compared to updating the actual DOM. Once it does that, it effectively reconstructs the actual DOM to push only the changes.

What is JSX?

React uses JSX which is nothing but syntactic sugar. Everything written in JSX is converted to JS.

const para = <p>Hi World</p>
Enter fullscreen mode Exit fullscreen mode

gets converted to

const tag = React.createElement("p", {}, "Hi World")
Enter fullscreen mode Exit fullscreen mode

One thing we observe with JSX that is different from HTML is that we can't use class, instead we use className. This is because class is a reserved keyword. There are a few subtleties like this in JSX which we need to be careful about.

What are components?

React is a component-based front-end library. This allows us to essentially build our UI as small reusable components. Every React app is a tree of React Components.

Types of Components

React has 2 types of components.

  • Class-based
  • Functional

Class Based Components

Let's see how class-based components look like first

import React, {Component} from 'react'
class Test extends Component {
    render() {
        return <div>Hi There!</div>
    }
}
Enter fullscreen mode Exit fullscreen mode

As we can see, we create a separate file for a component. Then we need to import React and Component. We create a class called Test(name of our component). Then we use the render method to define what to display. But this is history, it's legacy code now as functional components have started to take precedence.

Functional Components

import React from 'react'

const Test = () => {
    return <div>Hi There!</div>
}
Enter fullscreen mode Exit fullscreen mode

Here too, we import a React library, but this can be skipped in the latest versions. Then we just need to create a function(can be named or arrow). That's it.

Setting up a project

We can either

  • setup a project manually by using Webpack and Babel
  • using create-react-app command

We will go with create-react-app as it's far easier. But if finer control is required better to go with the first approach.

What is create-react-app?

create-react-app is a tool to generate the starter project. It's officially supported by the React team. To create a project just create a project directory and run the below command.

npx create-react-app ./
Enter fullscreen mode Exit fullscreen mode

This creates our React Project. We can start the project by running the below command.

npm start
Enter fullscreen mode Exit fullscreen mode

The project will be hosted on port 3000 on localhost.

React Project structure

Let's look at the directories the create-react-app had created to understand what files are required for React to run.

The first file we need to look at is package.json. Here we will find a list of dependencies for the project. We will find the react libraries as well here.

"dependencies": {
  "@testing-library/jest-dom": "^5.17.0",
  "@testing-library/react": "^13.4.0",
  "@testing-library/user-event": "^13.5.0",
  "react": "^18.2.0",
  "react-dom": "^18.2.0",
  "react-scripts": "5.0.1",
  "web-vitals": "^2.1.4"
}
Enter fullscreen mode Exit fullscreen mode

Next, in the public directory, we find the index.html. The main thing we need to look at is the root div. React injects the entire app inside the root tag.

<div id="root"></div>
Enter fullscreen mode Exit fullscreen mode

This is done in the index.js file found under the src directory. Below is a sample of the file.

import React from "react";
import ReactDOM  from "react-dom";

import App from './App';

ReactDOM.render(<App/>, document.getElementById("root"));
Enter fullscreen mode Exit fullscreen mode

Here the ReactDOM is imported with React library. We use ReactDOM only once in the entire app. We use ReactDOM.render with the component we want to inject and the target DOM element. React injects the App component into the root element. This is the basis of how React works.

The next file is App.js inside the src directory. It's the place where we are defining what to render.

React in action

The main feature of React is the power to write HTML inside Javascript and vice versa. Inside a pair of curly braces, we can put and valid Javascript code.

For instance, we can start with a clean App.js. Remember App.js is a component.

import './App.css';

const App = () => {
  return (
    <div className="App">
      <h1>Hi There</h1>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

This renders a simple Hi There on the page. Let's first understand what is happening here.

  • We are importing a css file for styling.
  • We are defining a functional component called App using the arrow function.
  • We export the App function, so it can be used wherever the file gets imported.

Now, we can start playing with it. We can define a variable and display the same to the user.

const App = () => {
  const name = "John Doe";
  return (
    <div className="App">
      <h1>Hi {name}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

React renders us Hi John Doe. It evaluates the name variable to get the actual value and shows us the result.

We can make the same conditional based on a parameter.

const App = () => {
  const name = "John Doe";
  const isNameEnabled = false;
  return (
    <div className="App">
      <h1>Hi {isNameEnanled ? name : "there"}</h1>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

React renders Hi there. Here we have used a ternary operator to display the name conditonally. Similarly, we can perform calculations, computations, etc.

Now, let's assume we need to render multiple elements, we usually do that with divs. But a cleaner approach to stop the page from having multiple inner divs is using fragments.

import React from 'react';

const MultipleElements = () => (
  <>
    <h1>Hi</h1>
    <p>There</p>
  </>
);
Enter fullscreen mode Exit fullscreen mode

Note this is a newer React feature, so legacy apps might not support it. If we don't nest them, we run into the error "Adjacent JSX elements must be wrapped in an enclosing tag". So, be careful with this.

Moving forward, we will start creating components.

Creating and importing components

One of the selling points of React is that we can create smaller components and embed them into parent components. This way we can reuse the components in multiple places.

We will look at an example below.

const Person = () => {
  return (
    <>
      <h1>First Name: John</h1>
      <h1>Last Name: Doe</h1>
      <h1>Age: Unknown</h1>
    </>
  );
}

const App = () => {
  return (
    <div className="App">
      <Person />
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

This will render us with text defined in the Person Component. This is how we import one Component into another.

What are props?

To pass data to our Components we use props. Props are arguments passed into React Components. We pass them as HTML attributes. We use props to pass data from one component to another (Parent to Child). Data passed in props is read-only and cannot be modified by the received component.

We will look at the same example above with props.

const Person = (props) => {
  return (
    <>
      <h1>First Name: {props.firstName}</h1>
      <h1>Last Name: {props.lastName}</h1>
      <h1>Age: {props.age}</h1>
    </>
  );
}

const App = () => {
  return (
    <div className="App">
      <Person firstName='John' lastName='Doe' age={20}/>
      <Person firstName='Jane' lastName='Doe' age={25}/>
    </div>
  )
}
Enter fullscreen mode Exit fullscreen mode

As we can see, in the Child component we get the props argument and use the attributes passed from the parent component.

What is state?

State is a JS object used by React to represent the component's state(maybe a counter instance). It is completely managed by the Component it's present in. Whenever the state changes, the component re-renders. The state object is where we store property values that belong to the component. State data can be modified by its component, but is private.

We will look at a simple counter using state.

import { useState } from 'react';
import './App.css';

const App = () => {
  const [counter, setCounter] = useState(0);
  return (
    <div className='App'>
      <button onClick={() => {setCounter((prevCounter) => prevCounter - 1)}}>-</button>
      <h1>{counter}</h1>
      <button onClick={() => {setCounter((prevCounter) => prevCounter + 1)}}>+</button>
    </div>
  );
}

export default App;
Enter fullscreen mode Exit fullscreen mode

To use state we need to import the react hook called useState. There are a few hooks that React gives, it's better to know of them.

useState accepts an initial state and returns 2 values. They are the current state and a function to update the state. We should never update the state directly and always use this function.

So here we have defined the current state as 0, the current state is counter, and the setCounter is the function to update the state. This helps us keep track of the counter and as and when the counter gets updated the component gets re-rendered. If we don't use state and directly do the same, the component doesn't get re-rendered and the value remains the same.

Another important hook is useEffect. It's used to perform side effects on the components. For instance, if we want to show an alert every time the counter is updated, we can do something like this.

useEffect(() => {
  alert("Counter has been updated to " + counter);
}, [counter])
Enter fullscreen mode Exit fullscreen mode

useEffect takes in 2 arguments. The function it has to call, and what it is dependent on.

  • If we don't pass the second argument, it gets triggered on every re-render. The below block will always make the counter to 0, whenever it changes. (Just for example)
useEffect(() => {
    setCounter(0);
  });
Enter fullscreen mode Exit fullscreen mode
  • If we pass an empty array, it gets triggered only on the first render. The below block sets the counter to 100 on the first render.
useEffect(() => {
    setCounter(100);
  }, []);
Enter fullscreen mode Exit fullscreen mode
  • If we pass the dependent element, it gets triggered when the value gets updated. This block just alerts the counter whenever the counter gets changed.
useEffect(() => {
  alert("Counter has been updated to " + counter);
}, [counter])
Enter fullscreen mode Exit fullscreen mode

There are more hooks that React offers. It's a good idea to be aware of them.

In the next article, I write about React and will look at expanding further on it.

References

Sample project

. . . . . . . . . . . . . . . . . . .