React at a glance

November 26, 2023 - Reading time: 19 minutes

Learning React on FreeCodeCamp was confusing. For the first time in the curriculum I had to find some tutorials and go through W3C course as well to help me out. Let's hope writing down will help me understand how to use it.

What

A JavaScript library to build user interfaces thanks to its own markup language called JSX (combination of HTML and JavaScript). It was created and is maintained by Facebook.

Render

React splits up the web page structure to separate components that can be displayed (rendered) according to a set of rules. To execute the rendition, the browser will need a transpiler (a converter) such as Babel.

Virtual DOM

React uses a virtual DOM where it does all the changes before passing them to the browser DOM.

Initiate

On CodePen

Pen Settings/JS tab: select Babel as JavaScript Preprocessor

On JS tab add

import * as ReactDOM from "https://cdn.skypack.dev/react-dom@18.2.0";
import * as React from "https://cdn.skypack.dev/react@18.2.0";

ReactDOM.render(
  <React.StrictMode>
   <App />
  </React.StrictMode>,
  document.getElementById("root")
)

And on HTML tab add

<div id="root"></div>

On computer

Make sure npx and Node.js are installed, then open a terminal and

  1. Go to the where you would like to create your application (ncd Documents/...)
  2. Run npx create-react-app my-react-app (my-react-app is the name of your app/directory)

Wait a few minutes and it the React environment be ready. Then (and anytime later when located on your project directory), just run npm start. A new browser window will pop up with your newly created React App! If not, open your browser and type localhost:3000 in the address bar. Changes you make will be visible immediately after you save the file, without reloading.

Basics

See all basics examples on CodePen. Each part is rendered in a different section for a better understanding but in this article we keep the rendering in a div with an id of root which is more common in real life.

Components

React components are named functions that return HTML. If you have a project on your hardrive, you can split your work: 1 component equals 1 js file (Capitalized).

For instance:

in App.css

.red {color: red}

in Hello.js

function Hello() {
return <h2>Hello World!</h2>
}

export default Hello;

in App.js

import Hello from './Hello'
import './App.css';

function App() {
  return <>
   <h1 className="red">This is the App Name</h1>
    <Hello/>
  </>
}

Will be translated as:

<div id="root">
<h1 class="red">This is the App Name</h1>
<h2>Hello World!</h2>
</div>

Observations:

  • Use <> and </> fragment to enclose your code if there's no HTML tag to encapsulate it.
  • You can call a component in another
  • The HTML class attribute has to be changed to className because class is a reserved keyword in JavaScript (and so, in JSX)
  • Vanilla HTML would have be enough for this example

Props & children

Components can recieve properties (which would act as function arguments) from element's attributes. For instance:

function Yummy(prop) {
return <p>I love {prop.treat}!</p>  
}

ReactDOM.render(
<React.StrictMode>
<Yummy treat="cookies" />
  </React.StrictMode>,
  document.getElementById("root")
)

prop will regroup all attributes and children that where provided in an object, this is why we use the dot notation un Yummy fonction. If there's only a few attributes, we can just import in the function the needed key:

function Yummy( {treat, children} ) {
return <p>I love {treat}! {children ? <strong>{children}</strong> : "Reasonably."}</p>
}

ReactDOM.render(
<React.StrictMode>
<Yummy treat="chocolate">
<em>Too much, actually.</em>
</Yummy>
  </React.StrictMode>,
  document.getElementById("root")
)

Note that the code to be treated as JavaScript should be within curly braces. Methods (functions) can be passed as properties.

Events

Let's have a look at this example for W3schools:

function Football() {
  const shoot = (a) => {
    alert(a);
  }
 
    return (
    <button onClick={() => shoot("Goal!")}>Take the shot!</button>
  );
}

ReactDOM.render(
<React.StrictMode>
<Football />
  </React.StrictMode>,
  document.getElementById("root")
)

Observations:

  • events are written in camelCase syntax (onClick instead of onclick)
  • event handlers are written inside curly braces
  • to pass arguments we need to use an arrow function

Conditional rendering

In this example, also from W3schools, we use two methods: && operator and ternary operator. We could also have used a classic if/else statement based on a prop value for instance (if prop is true, show this, else, show that).

function Garage(props) {
const cars = props.cars;
const message = `You have ${cars.length} cars in your garage.`;

return (
<>
<h3>Garage</h3>
{cars.length > 0 &&
<p>
Using && :<br/>
{message}
</p>
}

{
cars.length > 0 ?
<p>Using ternary operator :<br/>{message}</p> :
null
}
</>
);
}

const listofcars = [
{id: 1, brand: 'Ford'},
{id: 2, brand: 'BMW'},
{id: 3, brand: 'Audi'}
]

ReactDOM.render(
<React.StrictMode>
<Garage cars={listofcars} />
  </React.StrictMode>,
  document.getElementById("root")
)

Note: to use a variable within a string, nest the string intro backticks (`) and let you variable into curly brackets be preceded by a $ sign.

Keys

Use key for re-rendering only the element of a list that has been updated. Using the same listofcars constant from above as well as the map JavaScript method (which iterates every item of provided list):

function Car(props) {
return <li>{ props.brand }</li>;
}

function Vroum() {
return (
<>
<h1>List of cars</h1>
<ul>
{listofcars.map((listofcars) => <Car key={listofcars.id} brand={listofcars.brand} />)}
</ul>
</>
);
}

ReactDOM.render(
<React.StrictMode>
<Vroum />
  </React.StrictMode>,
  document.getElementById("root")
)

Hooks

Hooks connects rendering to particular changes which will be described here after. They replace class components since version 16.8. They can be customed, otherwise some are pre-made. All examples comes from W3Schools and are available on this CodePen.

Import

First of all, if you have not imported all React features (using import * as React from...), import the hooks you need, for instance:

import { useState, useEffect } from "react";

Doing so you are destructuring useState from react and can use it as is (rather than specify React.useState like in CodePen).

And keep in mind these 3 rules from W3Schools:

  • Hooks can only be called inside React function components.
  • Hooks can only be called at the top level of a component.
  • Hooks cannot be conditional

In this article we'll just focus on three main hooks but feel free to explore the other existing ones (useContext, useReducer, useCallback, useMemo).

useState

Links a variable (its current state) to an updater function.

function App() {
const [color, setColor] = useState("yellow");
 
  return <>
    <p>My favorite color is {color}!</p>
    <button
        type="button"
        onClick={() => setColor("blue")}
      >Blue</button>
  </>
}

Observations:

  • to make the link, we use an array containing the variable and the function (commonly setVariablename)
  • useState("yellow") initiates the variable to the value "yellow" (a string)
  • read this variable in the return statement, simply calling it
  • update this variable with the function which contains "blue" as an argument (setting up a new state for color)

useState on an object

function App() {
  const [car, setCar] = useState({
    brand: "Ford",
    model: "Mustang",
    year: "1964",
    color: "red"
  });

  const updateColor = () => {
    setCar(previousState => {
      return { ...previousState, color: "blue" }
    });
  }

  return (
    <>
      <h1>My {car.brand}</h1>
      <p>
        It is a {car.color} {car.model} from {car.year}.
      </p>
      <button
        type="button"
        onClick={updateColor}
      >Blue</button>
    </>
  )
}

Observations:

  • we can read corresponding value of the object's property using the dot notation
  • we can't simply update a particular value in an object, we have to rewrite it (copy with ...previousState) and indicate the change afterwards. Otherwise the entire object will be replaced with the only pair color: "blue".

useEffect

Perform side effect like fetching data, updating DOM, play with timers and runs on every render. Don't forget the second parameter (an empty array or an array containing dependencies) which will prevent auto re-rendering.

function Counter() {
const [count, setCount] = useState(0);
const [calculation, setCalculation] = useState(0);

useEffect(() => {
    setCalculation(() => count * 2);
  }, [count]); // if count updates, update calculation variable

  return (
    <>
      <p>Count: {count}</p>
      <button onClick={() => setCount((c) => c + 1)}>+</button>
      <p>Calculation: {calculation}</p>
    </>
  );
}

If there's a useEffect hook on a timer, it should be disposed to reduce memory leaks; for this name the te timer and use a return statement to clear it:

function Timer() {
const [count, setCount] = useState(0);

useEffect(() => {
    let timer = setTimeout(() => {
      setCount((count) => count + 1);
  }, 1000);

  return () => clearTimeout(timer)
  }, []);

  return <h1>I've rendered {count} times!</h1>;
}

useRef

Can be used to access a DOM element directly or to keep track of previous state value. useRef() returns an object called current which should be intialized.

DOM pointer

function Pointer() {
const inputElement = useRef();

  const focusInput = () => {
    inputElement.current.focus();
  };

  return (
    <>
      <input type="text" ref={inputElement} />
      <button onClick={focusInput}>Focus Input</button>
    </>
  );
}

Using useRef, we associate the inputElement variable and the HTML element which have a ref attribute containing the variable's name. This is useful when we can't use getElementBySomething because the real DOM is not already built.

Previous state

function Before() {
const [inputValue, setInputValue] = useState("");
const previousInputValue = useRef("");

useEffect(() => {
    previousInputValue.current = inputValue;
  }, [inputValue]);

  return (
   <>
      <input
        type="text"
        value={inputValue}
        onChange={(e) => setInputValue(e.target.value)}
      />
      <h2>Current Value: {inputValue}</h2>
      <h2>Previous Value: {previousInputValue.current}</h2>
   </>
  );
}

Both inputValue and previousInputValue are initialized to an empty string. Each time there's an event (e) in the input field:

  • inputValue is updated via the setInputValue useState function and the variable equals field's content
  • as inputValue is changed and as it's a depedancy, useEffect comes in and replaces the value of current property to be equal to the inputValue. It is not re-rendered until there's another event in the input field.

We're done for now! Happy coding