React Basics

Chapter 7 50 mins

Learning outcomes:

  1. React nodes and elements
  2. What are props in React
  3. Working with events
  4. What are components and how to create them
  5. Working with state

React nodes

We've had a quick and brief experience of React elements from the previous chapter as we developed our first React program. Let's now dig deeper into what React elements are, and even before that, what React nodes are.

At the core, all React applications are made up of these bits and pieces known as React nodes (elements, textual pieces, and so on).

The official documentation of React doesn't formally define or use the phrase 'React nodes.' We use it for two reasons:

  1. Type declarations in the React library label the third parameter of React.createElement() to be a rest parameter, each of whose arguments implements the ReactNode type. (If you've worked with TypeScript before, you'll be able to understand what this means.)
  2. Using the term 'React node' simplifies the discussion when we want to talk about React.createElement() or anything to be rendered by React.

A React node can be any of the following: React elements, strings, arrays, Booleans, numbers, undefined, and null.

Any other value besides the ones listed above doesn't constitute a React node and thus couldn't be used wherever React expects a React node.

How exactly each of these values is handled by React will be explored later on as this course proceeds. For now, let's concern ourselves with the most important kind of React nodes — React elements.

React elements

React elements are described as follows by React's documentation, specifically in Glossary of React Terms:

React elements are the building blocks of React applications.

There's absolutely no doubt in this.

When we build UIs, we always require HTML elements, such as <div>s, <section>s, <header>, <footer>, <p>s, <h1>, <img>s, and so on and so forth. We just can't build literally anything without these core pieces.

In JavaScript, we create these HTML elements by constructing HTML DOM elements.

React adds an abstraction layer over these DOM elements, calling them as React elements. So in that way:

React elements are abstractions over DOM elements.

When we are working in React, the <h1> React element, for instance, is not the same as an <h1> HTML DOM element. Obviously, the React <h1> does somewhere reference an HTML DOM <h1>, but it also includes a host of other utilities, which drive the ideology of React.

React elements are created using createElement() (or speaking more precisely, using React.createElement()).

createElement(tagName, props, ...children)

The first argument to the function is a string representing the tag name of the element to create, the second argument is an object specifying the props to set on the element, and from the third argument onwards, every argument specifies a React node to put inside the element.

React.createElement() is also used to create components, when the first argument is a reference to a function. We'll see details to this later on in this chapter.

In the previous chapter, we created an <h1> element with the contenteditable attribute set and the text 'Hello World!' inside it using the following statement:

const element = React.createElement(
   { contentEditable: true },
   'Hello World!'

Let's now consider a more complex example.

In the code below, we create a <div> element with an <h1> and a <p> inside it (in this very order):

const element = React.createElement(
   React.createElement('h1', null, 'A heading'), 
   React.createElement('p', null, 'A paragraph')

Here's what's going on here:

  • The main element is <div>, likewise the first arg to the main, outer createElement() call is 'div'.
  • No attributes are required on the <div> element, likewise the second arg is null.
  • The next two args are React elements themselves, i.e. an <h1>, followed by a <p>. They both will be placed inside the <div> element being created.


Although React.createElement() isn't imperative like the document.createElement() DOM method, it still is a bit tedious to work with.

You would almost never find big apps, even not small apps, being made just by using such React.createElement() calls. Instead, you'll almost always find React elements created using JSX.

A JSX element denotes a React element and resembles the syntax of constructing elements in HTML. That is, we use the < and > angle brackets to denote an element's starting and ending tags and then put its content inside these tags.

For instance, the <div> element shown above could be represented in JSX as follows:

const element = <div>
   <h1>A heading</h1>
   <p>A paragraph</p>

As you can see, the code is just like how we'd express the element in pure HTML.

Restating an important fact as we did in the previous chapter, having a JSX element as it is between given JavaScript code is bound to reduce its readability. A better approach is to use parentheses (()) around the element.

The same code above could, henceforth, be expressed as follows:

const element = (
      <h1>A heading</h1>
      <p>A paragraph</p>

The addition of the parentheses (()) and the extra indentation of the <div> element makes the JSX code here much more readable than the one we saw before.

What do you say?

Moving on, attributes of JSX elements work the same way as attributes do in HTML. More precisely, they are simply the properties of the object passed into the second parameter of React.createElement(), also referred to as props of the element.

The values of JSX attributes can be strings, numbers, Booleans, undefined, null, arrays, objects, functions, regular expressions, dates — just about anything!

This isn't counter-intuitive. Remember that JSX elements are converted to createElement() calls, whereby the attributes of those elements are converted to properties of the second argument object given to createElement(), and then the values of these properties are simply obtained from the values of the corresponding attributes of the JSX element.

However, there's a specific syntax that we ought to use if we wish to set the value of a JSX attribute to any value other than a literal string.

For instance, if we know that the value is a string, it could be easily provided as follows

<div title="50">A div</div>

just as we're accustomed to do in HTML, i.e. encapsulate the value inside a pair of quotes, usually double quotes ("").

But, if the value is NOT a string, and if we specify it as it is, as shown below,

<div title=50>A div</div>

it would automatically get converted to a string by the JSX transformer.

So, the following expression

<div title=50>A div</div>

would become:

<div title="50">A div</div>

To correctly set an attribute to an arbitrary value, we need to use curly braces ({}) to tell the JSX parser that a JavaScript expression is given inside the braces.

As one can expect, only JavaScript expressions are allowed as JSX attribute values.

The attribute above, with the numeric value 50, could likewise be set as follows:

<div title={50}>A div</div>

The braces ({}) mean that a JavaScript expression is given inside them, which in this case turns out to be the number 50. Our title attribute here doesn't have a mere textual value; instead it has a numeric value.

As this course progresses, we'll get to appreciate the applications of providing numeric values to JSX attributes.

Anyways, having covered some rock-solid ground on React elements, let's now discuss about the related idea of props.

What are props?

Consider the following JSX element,

<h1 contentEditable="true">Hello World!</h1>

and notice the contentEditable attribute.

If we see this same element as a React.createElement() call, the attribute is merely a property of the object passed as the second argument to the method:

React.createElement('h1', { contentEditable: "true" }, 'Hello World!')

contentEditable in both these snippets is a prop.

So what exactly is a prop?

As you can probably guess, prop is a fancy word for 'properties' in React. But a prop isn't just any property.

In React, a prop is a property of the object passed as the second argument to createElement().

This shorthand word 'prop' really helps us distinguish other properties from the ones that we specifically provide in createElement() invocations.

In a createElement() call, all the properties of the second argument object (except for key) are the element's props. Pretty simple.

Similarly, in JSX, all the attributes of a JSX element are the props of the corresponding React element (again except for key).

The purpose of props of React elements is the exact same as the purpose of properties of HTML DOM elements — to customize the element's content, appearance, and/or provide additional data to it.

The nomenclature of many props is the same as the nomenclature of properties in the DOM. This makes sense because React processes these props as properties of DOM element nodes, at some point. If React innovated a lot in this area, like coming up with different property names, it would've had to do an extreme amount of processing.

As we shall see later on, React already innovates on the naming of event handlers, and if it were to do the same in all the property names, things might've become a bit difficult to work with.

Let's consider a very common attribute applied to HTML elements — class.

Do you know the name of the corresponding DOM property of element nodes representing the class HTML attribute? Well, it's called className (to learn why it isn't called class; refer to JavaScript HTML DOM — Attributes: className).

The corresponding prop in React is guessed it... className.

In the code below, we showcase an example of className on <h1>:

const element = (
   <h1 className="blue">React is amazing!</h1>

Supposing that the following CSS is set in the HTML file where the React program is linked,

.blue {
   color: blue

as soon we launch the page in the browser, we get the following output:

React is amazing!

Not that difficult.

className is an extremely commonly used prop in React apps, just like class is in HTML documents.

Besides className, another commonly used prop is style.

Do you remember the style HTML DOM property? Do you remember how it works?

In HTML DOM, the style property of element nodes (in particular, of HTMLElement instances) points to a CSSStyleDeclaration object that we could use to manually set any inline CSS style on a given element.

In React, the style prop works, more or less, the same way.

But since style is a prop that we set ourselves and not a predefined property to refer to (as is otherwise the case with the HTML DOM style property), we obviously can't access styles on it. It just doesn't make any sense!

What we have to do instead is to tell React all the inline styles that we want, in one go.

React expects the value of the style prop to be an object. Each property of this object is internally applied by React to the style DOM property of the corresponding element node.

For example, to set the marginLeft and marginTop properties in HTML DOM, we'd do the following, supposing that h1Element is an <h1> element node:

// Suppose h1Element is an <h1> element node. = '70px'; = '30px';

But in React, we'd do the following:

const element = (
   <h1 style={{ marginLeft: '70px', marginTop: '30px' }}>Hello World!</h1>

The value of the style JSX attribute here is a JavaScript object literal with two properties: marginLeft defining the margin-left CSS property and marginTop defining the margin-top CSS property.

Note that React innovates a little bit in style's property values.

That is, the value of style properties don't just have to be strings (such as '10px'); they could be numbers as well (such as 10), in which case they're automatically converted to a '<number>px' string internally, where <number> is the number used.

For example, the value 50 would become '50px'; the value 20.55 would become '20.55px'; and so on and so forth.

This can save us from having to do this work manually.

Let's consider a quick example.

In the code below, we set the width of the <h1> element to 100px by providing the width style property the string value '100px':

const element = (
   <h1 style={{ backgroundColor: 'yellow', width: '100px' }}>Hello World!</h1>
Hello World!

Live Example

But thanks to React, we can simplify this as follows:

const element = (
   <h1 style={{ backgroundColor: 'yellow', width: 100 }}>Hello World!</h1>

The value of width now is the number 100, not a string, which is automatically converted to the string '100px' by React.

Remember, a numeric style property value in React gets converted to a string ending in the px unit, always. That is, 100 would always become '100px'.

The output remains the same:

Hello World!

Simply amazing.

Events in React

Let's now talk about events in React, starting with a rudimentary question.

What is the property used to register a click handler on an element node called? Well, it's simply called onclick.

Now you might be tempted to think that React abides by this exact same naming, but that's NOT the case. Yes, React does call it the same as 'onclick' but with a different casing.

In React, all event-handler props follow the camel casing convention.

This is unlike event handler properties in the DOM and unlike attributes in HTML.

So onclick in React would be called onClick; onmousedown would be called onMouseDown; ontouchstart would be called onTouchStart; and so on and so forth.

That why exactly is this casing used will be explored in the chapter React Events where we'll learn more about how events work in React and why they use W3C's SyntheticEvent API instead of the native events.

Anyways, now that we know that onClick represents the prop used to set up a click event handler on a React element, let's use it.

In the code below, we set up a click event handler on our <h1> element:

const element = React.createElement(
   { onClick: function(e) { alert('Clicked'); } },
   'Hello World!'

As can be seen, the onClick prop is assigned a function, just like we'd do to the onclick property of a DOM element node. The given function simply makes an alert.

Here's the output produced:

Hello World!

Quite simple.

Let's now make this a bit more involved by changing the content of the <h1> element itself upon its click.

Inside the handler function, we'll call the render() method of the root object to change the content of #root:

import React from 'react';
import ReactDOM from 'react-dom/client';

const element = React.createElement(
   { onClick: () => {
      root.render(React.createElement('h1', null, 'New content'));
   } },
   'Hello World!'

const root = ReactDOM.createRoot(document.querySelector('#root'));

Let's see the effect of clicking on the <h1>:

Live Example

As soon as we click the <h1> element, its content indeed changes. This is React in action.

The same code could be expressed in JSX as follows:

import React from 'react';
import ReactDOM from 'react-dom/client';

const element = (
   <h1 onClick={() => { root.render(<h1>New content</h1>); }}>Hello World</h1>

const root = ReactDOM.createRoot(document.querySelector('#root'));

The onClick attribute of the <h1> element is assigned a function value with the help of a pair of curly braces ({}) to instruct the JSX parser that the attribute's value is a JavaScript expression. This function calls root.render(), passing it a new <h1> element.

Live Example

Yet again, it works flawlessly.

However, as you might've felt, this code isn't very elegant, not even after the addition of JSX. We are directly triggering the rendering of an <h1> element inside #root when the current <h1> is clicked.

As we keep on adding more and more bells and whistles to this program, the code would just keep on becoming more and more complex and tedious.

For example, let's say we want to implement a counter inside an <h1> that increments on each subsequent click.

Consider the following code where we illustrate the implementation:

import React from 'react';
import ReactDOM from 'react-dom/client';

let counter = 0;

function clickHandler() {
   root.render(<h1 onClick={clickHandler}>Count: {++counter}</h1>);

const element = (
   <h1 onClick={clickHandler}>Count: {counter}</h1>

const root = ReactDOM.createRoot(document.querySelector('#root'));

As we click on the <h1> element, a new <h1> element is rendered inside #root.

By virtue of how reconciliation works in React, technically, rendering a new <h1> element in place of the current <h1> element in the code above doesn't create a new <h1> in the DOM; instead, the same old <h1> is used with a different content. We'll learn more about this later on in this course.

Notice the values {counter} and {++counter} in the code above.

Similar to what we saw for JSX attributes above, curly braces ({}) in a JSX element's content represents a JavaScript expression that's resolved and then its resulting value used in place of the whole placeholder.

For example, Count: {counter} doesn't literally render the text 'Count: {counter}' but instead renders the text 'Count: ' followed by the resolved value of counter. So, let's say if counter is 10, Count: {counter} would be rendered as 'Count: 10'.

In the following link, try clicking on the <h1> element:

Live Example

As you do so, the count of the counter increments.

Even though the code does its job, this is NOT how React is designed to be run.

Someone could argue that the code could be simplified further to make it look more elegant, as shown below,

import React from 'react';
import ReactDOM from 'react-dom/client';

let counter = 0;

function incrementCounterAndRender() {
   root.render(<h1 onClick={incrementCounterAndRender}>Count: {++counter}</h1>);

const root = ReactDOM.createRoot(document.querySelector('#root'));

but still React was NOT made for us to worry about manually handling rendering concerns, as we're doing in all these code snippets.

React could instead do this all on its own, given that we know how to properly use it. And for that, we ought to know how to work with state.

But before that, we need to know about one of the foundational concepts of React — components.

Components — the cornerstone of React

Components are the cornerstone of React. From day one, React has been based on the idea of reusable components to build the UI.

Now what are components?

Well, there are two ways to define a component, one is completely from the perspective of the UI while the other is more technical and tied to the design of React.

Starting with the former:

A component is a reusable piece of the UI.

Let's consider a webpage. What things could a webpage be composed of? It could have a header, a footer, a section where all the main content goes, maybe even some sidebars, and so on.

As another instance, consider the header. What things could the header be composed of? Well, it could have a logo, a navbar, even a search bar, and so on.

Components can be composed of components (as the previous example demonstrates), which can further be composed of components themselves, and so on.

Now, let's define a component technically.

In modern-day React,

A component is a function that returns a React node.

Such components are more precisely referred to as function components, simply because they are based on functions.

In slightly older-day React, which still exists and is based on the idea of classes,

A component is a class with a render() method that returns a React node.

As you can probably guess, such components are more precisely referred to as class components, simply because they are based on classes (ES6).

Let's now take an example of using a component.

If we want to represent a header in React, we can easily do so using nested JSX, just like nested HTML, as shown below:

   <div className="logo">...</div>

This works but it's NOT reusable. The whole idea of a header isn't encapsulated.

Not being encapsulated means that if we want to, for example, tie some state data with the header, we can't do so if it's defined in this rudimentary style, without being a components. We'll see what this means later on in this chapter.

The ultimate solution here is to use a React component.

Let's see how to define a component.

In the code below, we define a function called Header that returns the same JSX that we had above for the header:

function Header() {
   return (
         <div className="logo">The logo</div>
         <nav>The nav</nav>

This Header function is a component, more specifically a function component. As its name suggests, it represents a header.

Now if we want to be able to render this component into the webpage, we have to provide it to createElement(). (Yes, the same createElement() function we've been using uptil now.)

The component, i.e. the function, goes as the first argument to the method, but keep in mind that we don't call the function; we just provide its reference.

Here's how we'd render the Header component into the #root element:

import React from 'react';
import ReactDOM from 'react-dom/client';

function Header() {
   return (
         <div className="logo">The logo</div>
         <nav>The nav</nav>

const element = React.createElement(Header, null); const root = ReactDOM.createRoot(document.querySelector('#root')); root.render(element);

React.createElement(Header, null) serves to instantiate a concrete Header instance (note that this is not OOP) and then the render() method of root renders this instance into the #root element.

Live Example

As we run this code, the dummy text 'The logo' and 'The nav' are displayed on the document, indicating clearly that the <header> element has been rendered out on the document.

We can even inspect React's in-house DOM tree in React DevTools. Here's the tree for the code above:

Component tree for the Header component in React DevTools.
Component tree for the Header component in React DevTools.

First we have the Header component and then, within it, the <header> element with its <logo> and <nav> elements.

As this illustration depicts, React's own element tree includes component instances. However, when this tree is ultimately flushed to the DOM, only React elements representing DOM elements are rendered on to the document.

Anyways, moving on, just as we could replace createElement() calls with the corresponding JSX elements, we could do so for components as well.

That is, the same Header component above could be instantiated as follows:

/* ... */

const element = (
); const root = ReactDOM.createRoot(document.querySelector('#root')); root.render(element);

The name of the component, i.e. Header, is used to denote the starting tag (<Header>) and the ending tag (</Header>) of the element denoting the component's instance.

If we want to, we could even omit the ending tag (</Header>) here, making sure that there is a / at the end of the starting tag, as shown below:

const element = (

Once again, this concise <Header/> syntax is borrowed from HTML itself.

Recall the <input> element from HTML, or maybe <img>; they both are void elements that can optionally be ended as <input/> and <img/>.

However, unlike JSX, HTML doesn't strictly require us to put a / at the end of tags that don't have a corresponding ending tag, such as <img>, <link>, <meta>, etc.

So the following is invalid JSX:

const element = (

That's because nor does <Header> have an ending tag here and neither does it contain / at its end (as in <Header/>).

XHTML, an extension of HTML, does strictly require all single tags to have a / at their end. For example, where in HTML, <img> is valid, in XHTML, it's not. The correct way to write this in XHTML is <img/>.

Before we conclude this section, there's one more important thing to point out, which we shall explore in more depth in the React Components chapter.

That is, there is a common convention in React apps to create an App component to be rendered inside the #root element as the entry into the React application.

function App() {
// All our code goes here.
} const element = ( <App/> );

After all the initial configurations, all our React code goes inside this App component.

In the upcoming chapters, we'll be leveraging the App component quite a lot, so it's good to get used to creating it every now and then.

In fact, the convention goes way beyond than just a separate component — it also includes a separate file called App.jsx (or App.js) to host this App component. We'll see more details in the React Components chapter.

Now that we know what exactly is a component and how to create one, let's discover the idea of state in React.

State of components

The next exciting thing in React after components is state. Whenever we talk about state in React, it's intrinsic to talk about components.

The state of a component describes the component at a certain point in time.

State simply describes a component, so to speak.

If you have experience of object-oriented programming in JavaScript, you'd probably already be familiar with the idea of state. The state of an instance of a class describes the instance — it's simply a cohort of some characteristics of the instance.

The idea of state is even present in HTML and CSS.

For example, when you hover with the mouse pointer over an element, its state changes to :hover. Similarly, if you focus a given input, its state changes to :focus. Once again, the state here describes the element at a certain point in time, i.e. either the element is under the pointer or the element has active focus.

In user interfaces, the state of a given element describes that element, which in turn affects its visual appearance, its behavior, and/or its content.

For example, a button in a user interface might be 'disabled', an image might 'not be loaded' currently, an accordion might be 'hidden', and so and so forth. These are all the very states of these individual UI components.

The concept of state in React is not any different from this.

To define the state of a component in React — or more precisely speaking, to define the state of a function component — we use the useState() hook.

A hook is simply a way to 'hook' a component into a given functionality in React.

The useState() hook enables a component to hook into the state utility of React.

As with createElement(), useState() is defined on the imported React object.

The state data is simply provided as an argument to useState(). The data can be literally any value in JavaScript — a number, a string, a Boolean, undefined, null, an array, a regex, an object; just about anything!

The most interesting part of working with useState() is its return value.

useState() returns an array whose first element is the value of the corresponding state data and whose second element is a function to update the state to a new value (the main game-changer in React, as we shall see below).

Let's take an example.

Consider the following code where we try to store the text to be shown inside the <h1> element as state data of the Heading component:

function Heading() {
   const [text, setText] = React.useState('Hello World!');
   return (

The most important statement here is in line 2:

  • useState('Hello World!') adds a state datum to the Heading component. The initial value of this datum is the string 'Hello World!'.
  • useState() returns back an array whose first element is this state datum and the second element is a function to update this datum.
  • text is merely a convenient name that we use to refer to the state datum. We could name it anything (it's just an identifier) — content, str, h1Text, html, and so on.
  • setText is used to store the state-update function, used to update the state datum text. To distinguish it from the actual state value, and also because it holds a function, we'll refer to it as setText().

Note that it's conventional to name the state-update function starting with the word 'set', followed by the name of the state value.

For example, in the case above, the state was named text, likewise the function was named setText() (obviously after updating the casing of the state's name, i.e. going from text to Text in setText).

Similarly, if the state was called firstName, then, abiding by this convention, the corresponding state-update function would be named setFirstName.

Following this convention, yet again, what would the state-update functions for the states content and isThemed be called?

  • setcontent and setisThemed
  • set_content and set_isThemed
  • setContent and setIsThemed

Anyways, once we have the state value and the state-update function with us, we could use them both to make our component interactive, thanks to the state-update function.

In React, when the state-update function is invoked, it automatically triggers a rerender (similar to what we were doing manually by calling the render() method of our root object in the sections above).

Let's use text and setText() from the previous code to power a click handler on <h1>, similar to what we did in the previous sections above:

function Heading() {
   const [text, setText] = React.useState('Hello World!');
   return (
      <h1 onClick={() => { setText('useState() in action.') }}>{text}</h1>

Inside the onClick handler, we call setText() with the new text value to be put inside <h1>.

Open up the following link and click on the <h1> element. You'll notice its content changing upon the click, all thanks to setText().

Live Example

Let's see what exactly happens when setText() gets called:

  • The previous state value, which was 'Hello World!', is replaced with the value 'useState() is amazing'.
  • The Header component is rerendered and, likewise, invoked again (remember that it's a function).
  • Inside the Header() function, useState() executes again, this time returning an array whose first element is the latest state data, i.e. 'useState() is amazing', and the second element is the same state-update function that we had before.
  • This new state data obviously gets stored in text again.
  • text is rendered inside the <h1> element.

See how simple this is compared to manually invoking root.render(), as we did before.

This is how React is designed to be used. This is how React thinks about dealing with UI construction.

The setText() function above is reactive. That is, as soon as we call it, a new render is triggered automatically — a reaction is made — and the UI, thereafter, updates as if by magic.

Purely commendable.

One thing worth noting here is that instead of accessing useState() as React.useState(), we can simplify this by using a named import while importing the react package.

So the code above could be expressed more compactly as follows:

import React, { useState } from 'react';
import ReactDOM from 'react-dom/client';

function Heading() {
   const [text, setText] = useState('Hello World!');
   return (
      <h1 onClick={() => { setText('useState() in action.') }}>{text}</h1>

const root = ReactDOM.createRoot(document.querySelector('#root'));

Notice the { useState } named import in line 1 — it serves to introduce a variable called useState into the current module, holding the useState() function exported by react.

In React applications, this named-import approach is quite mainstream for all hooks.

That is, instead of accessing hook functions as React.hookFunction(), the functions are imported directly from the react package and thereafter used as hookFunction().

From this point onwards, we'll follow this very import convention when wanting to use hooks.

Moving on

This chapter touched on a lot of different ideas in React, which are fundamental for you to understand to be able to effectively build complex React apps without running into glitches.

However, there are tons and tons of intricate details left off deliberately here for the sake of brevity. Clearly, if we were to introduce everything rightaway at this beginning stage, it would've been way overwhelming and tedious to follow.

We'll explore all of this intricacy, to its very core, in the upcoming chapters.

For now, it's super important that you experiment with useState() to implement simple, elementary programs. They may seem elementary, for sure, but the more you code them, the better you'll become in React.

The upcoming two exercises get you to code such programs using all of the knowledge that you obtained thus far in this course. After the exercises, we'll move over to unravel the power of JSX and explore it in extreme detail.

But before all that, up next we have a React Basics quiz ready for you to test your comprehension of this chapter.

"I created Codeguage to save you from falling into the same learning conundrums that I fell into."

— Bilal Adnan, Founder of Codeguage