Learn Computing from the Experts | The Rheinwerk Computing Blog

The Most Important Terms and Concepts of the React World

Written by Rheinwerk Computing | Dec 14, 2023 2:00:00 PM

Development of a React application is sometimes very different from that of traditional web applications.

 

For example, React follows a component-oriented approach to building an application. This means that an application is composed of numerous small building blocks that are loosely connected to each other. In addition, React has some optimizations that allow changes in the appearance of the application to be displayed in a very performant way. The goal of React is to be able to handle very large amounts of data in the frontend.

 

Components and Elements

The central elements of React are components. They are the building blocks of an application and provide the structure of the interface. A component should be as small as possible in its scope and independent of its environment. This makes it possible to use it in multiple places in the application or even in multiple applications. The core of a component is a function that returns the structure of the component. This function is referred to as the render function.

 

You can define the structure of the display in two different ways:

  • You can use the createElement method to create new elements and build a hierarchy with those elements.
  • It’s also possible to use JavaScript XML (JSX)—a syntax extension for JavaScript— and thus use HTML-like notation directly in the JavaScript source code of your component to describe the structure.

The more common variant is the second one using JSX.

 

A component is not the smallest unit available to you in React. At the lowest level, there are the React elements. These are translated into native elements, depending on the environment. For the browser environment, this means that the React div element is translated into an HTML div element. In a component, you can use both components and elements to describe the structure of your application. To distinguish between elements and components, React has introduced the convention that elements always start with a lowercase letter and components with an uppercase letter.

 

Components can be parameterized for improved reusability. If you use JSX, you can pass attributes to a component that you write as a JSX tag. These are referred to as props in React and allow objects to be passed in the component tree. In general, React components have a defined lifecycle that you can intervene in at various points to influence the behavior of a component. Components can also have their own state. This state is a data structure that contains information for representing the component. If the value of the state changes, React makes sure that the change is reflected in the browser and the component will be rendered anew.

 

When it comes to components, React again distinguishes between two categories: class and function components. 

Class Components

The class components of React are in some ways relics from a bygone era. They represented the standard when it came to components prior to the introduction of the Hooks API in version 16.8 because only class components had their own state and lifecycle methods. However, the introduction of the Hooks API has caused class components to become less important. In modern React applications, class components are hardly ever found.

 

The reason for the decline of class components is that the second type of components, function components, are more in line with the character of React. They are more lightweight and flexible. In addition, the Hooks API solves some problems of the class components.

 

The name class component is based on the fact that a class component is a JavaScript class that derives from the React.Component base class. In previous versions of React, class components were created using the React.createClass method, although this method is now no longer available and you should only use the class-based variant. Alternatively, you can use the create-react-class add-on package, which is an interface that behaves very similarly to React.createClass.

 

The core of the class component is the render method, which makes sure that the component can be displayed. The method returns a React element or component as a return value that React uses for rendering. React manages the state of a class component in the form of a property and maps the lifecycle through various methods, such as componentDidMount.

 

When you start implementing a new React application, you should avoid using class components and instead draw on the more modern function components.

Function Components

As the name suggests, a function component consists of a single function. This function is nothing more than the render method of a class component and takes care of rendering the component. By default, such a function component originally did not have its own state and lifecycle methods. Function components were used in their original form as simple display components. However, with the introduction of the Hooks API, this changed and function components became full-fledged React components with state and lifecycle and have now almost completely replaced class components.

 

Data Flow

A React application lives by its dynamics. As a rule, users interact with your application and use it to produce and consume information. A core element of building a React application is modeling data streams. In the component tree of the application, information always flows from the parent elements toward their children.

 

If you imagine a typical React application that is used to manage information, typically one of the first requirements is to implement a list representation of the information. In the component tree, the list itself is represented by a component. The individual entries are in turn components that are in a parent-child relationship with the list. The list entries are the child elements of the list (see figure below). To display the information, you read the data into a central point, such as the list component, and distribute the information to the individual child elements. This solution has the decisive advantage that only a summarized request is required, and you receive an overview immediately.

 

 

The list component contains the state; that is, it is responsible for data management. It downloads the data for display from the server and takes care of sending changes to the server. For each data record, a child component is created, which receives the information to be represented as props. This method makes sure that a directed data flow can be implemented, through which React is able to make the rendering of the interface very performant. A side effect of this component partitioning is that you can use the components in multiple places in your application.

 

However, with this type of data flow, the child components have no way to pass information back to their parent components. But that becomes necessary when information has been modified and the parent component should be notified about it. One solution to this is to pass callback functions from the parent to the child component in addition to the rendering information. These functions, known as event handlers, are executed by the child component in certain cases—for example, when data is changed. The function works in the scope of the parent component, so it has access to its internal structures and can, for example, modify the state. This gives you the option to return the information to the parent component.

 

The performance benefits that are caused by the directed data flow come from the fact that React knows exactly where to change the application's display.

 

The Renderer

In the default configuration of a React application, the react and react-dom packages are installed. The react package contains the library itself. The second package, react-dom, contains the renderer. This component is used to translate React elements into concrete HTML elements that can then be rendered in the browser.

 

Another renderer for React is React Native, which ensures that the elements of a React app are translated into their native equivalents in an iOS or Android app. If you use different renderers, you should note that the different environments use their own elements. For example, you can use div elements with react-dom. In React Native, you use the view element as the container element instead.

 

Not only can a React app be rendered in the browser or on a mobile device, but there are many other renderers available as NPM packages. For example, Ink is a renderer for interactive command-line applications using React.

 

The Reconciler

Among other things, the main React package contains the reconciler. This algorithm is responsible for detecting changes in an application. An adjustment to a component can be made either by changing the props or the state. For a change to take effect in the browser, the DOM tree must be at least partially rebuilt in the case of the browser environment. The rendering of HTML structures is still one of the biggest weak points for the performance of web applications. React provides a solution to this problem in the form of the virtual DOM, an image of the application's structure in the form of JavaScript objects.

 

If a modification of the DOM structure is required, React generates a new version of the virtual DOM. This structure serves as a blueprint for the new version of the application. React then attempts to customize the existing DOM using a series of optimized actions.

 

For the optimization of the reconciler algorithm, two assumptions are made to reduce complexity:

  • Two elements with different types produce different trees.
  • The key prop can be used to specify which child elements remain stable between two render steps.

When comparing the original state and the target state, React proceeds from the root toward the child elements and performs the comparisons.

 

As already mentioned, the reconciler first checks whether the types of two elements match. If the types are different, the first optimization of the algorithm takes effect, which states, as mentioned earlier, that two different types lead to two different trees.

 

 

React can abort the check in this case and build a completely new subtree. This means that all previously built structures are discarded and all components are unhooked. This terminates the component lifecycle and, if present, executes the appropriate unmount logic used to clean up the environment. The new components are then built and the appropriate lifecycle functions are executed.

 

If the types of two elements match, then the attributes of the elements are checked and only the values are adjusted accordingly. For example, if the element's class name or style attribute changes, the underlying DOM element is adjusted accordingly and the subtree is not discarded.

 

 

With components, the situation is similar to elements with changed attributes: The component instance remains the same, so the state is preserved and the corresponding lifecycle functions are executed. Then the child elements and components are processed.

Multiple Child Elements and the “key” Prop

In the case of a list of several elements, it may happen that only the order is changed, but not the elements themselves. This becomes relevant, among other things, when a new element is inserted at a certain position in the list. As a result, the index of all subsequent elements changes, which would mean for React that they have to be rebuilt. This can be prevented by means of the key prop. The key prop must contain a unique and stable value in a list. If the render method of the parent component is executed again, the value of the key prop is used to check whether the elements have changed.

 

Typically, the unique IDs of data records are used as the value for the key prop. The value does not have to be numeric. However, it is mandatory that the value is unique within the list, not across the entire application, and does not change between the different render calls; otherwise the assignment cannot be done correctly.

 

As an aid during development, React issues a warning at each iteration about a list of elements without a key prop. This warning states that each child element of a list should have a unique key prop. Especially for large lists, using the key prop can significantly improve the rendering performance.

 

Learn about the component lifecycle in React in this blog post.

 

Editor’s note: This post has been adapted from a section of the book React: The Comprehensive Guide by Sebastian Springer.