React: Ten Years of “Rethinking Best Practices”

A JavaScript library to develop user interfaces” was the simple motto when React saw the light of day in May 2013. Today – ten years later – it is an integral part of the everyday life of many developers. React is considered one of the most widely used libraries for developing single-page applications (SPA).Not only Facebook and its parent company Meta, which developed React and published it as open source, use this library, but also many well-known products such as Jira, Figma, Microsoft Outlook and Teams developed.

React did a lot of things differently than established UI libraries for web and desktop back then, and it still does today. For this alternative approach, Pete Hunt, React developer from the very beginning, coined the still applicable motto in a presentation at JSConf 2013: “Rethinking Best Practices” (see video). As such, the history of the library has been marked by some fundamental shifts in best practice. In the course of ECMAScript 6, classes also found their way into React, a few years later the development team followed up with the Hooks API, which made it possible to develop React components solely with JavaScript functions. In the recent past, there have been signs of a move away from client-side Single Page Applications (SPA) towards complete React applications that require a JavaScript server at runtime – and should therefore preferably be created with full-stack frameworks.

Recommended Editorial Content

With your consent, an external YouTube video (Google Ireland Limited) will be loaded here.

Always load YouTube video

React developer Pete Hunt coined the still applicable motto: “Rethinking Best Practices” in a presentation at JSConf 2013.

Historically, the React team has always been careful to avoid technical breaks (breaking changes), such as those that occur when different programming and template languages ​​are combined: Components are therefore written exclusively with JavaScript. There is no template language, as is usual in many UI libraries. Instead, React comes with the JSX JavaScript language extension. This extension makes it possible to write XML code directly in the JavaScript code. During the build process, a compiler ensures that valid JavaScript code is generated that browsers can understand. The idea behind it: If developers use a JavaScript library to build interfaces, they have to know or learn the JavaScript language anyway. Instead of having to learn a second (template) language, they can use JavaScript extensions. According to the understanding of the React team, JSX is therefore not a template language, but merely “syntactic sugar” for JavaScript. The current React documentation even immodestly states: “Learning React is learning programming.”

You will also look in vain for popular architecture patterns such as the MVC pattern (Model View Controller) in React. React deliberately avoids the separation into individual technical parts (“separation of concerns”), for example in model, view and controller, and concentrates everything that belongs to a component directly in this component. In this way, code that belongs together technically should stay together and not be “artificially” distributed to several places. This is based on the assumption that changes or extensions to components not only result in adjustments to the UI, model or logic layer, but that all layers are usually affected by the changes, so that you have to tiresomely jump back and forth between them the individual parts of a component. In addition, the individual technical parts of a component cannot usually be reused in other components, so that a division seems pointless for this reason as well. Consequently, in React, the entire component is the only reusable entity.

What hasn’t changed to this day is that React application development revolves around making optimal use of the state of components. This is changeable component-internal data, such as the current content of an input field. When this data changes, React triggers the re-rendering of the component whose state has changed, including all components beneath it. In React there is no two-way data binding, i.e. the possibility of automatically transferring changes to the interface (e.g. after entering them into a text field) to the model or the state of a component. The desired reaction to such changes, which are usually triggered by events (text field was changed, checkbox clicked, data arrived from the server …), must be explicitly programmed in the component in React. The life cycle of a component in React is therefore very simple: After the initial rendering, the component returns the desired UI. Event listeners can be set on the returned UI elements. If an event occurs, the component can process the event (text field was changed) and update the internal state. As a result, React re-renders the component and the cycle begins again.

In React, data is always passed between components from top to bottom, i.e. from higher-lying components to lower-lying ones. This is why React also speaks of unidirectional data flow: the data only ever flows through the system in one direction. In other UI architectures, it is widespread that components also know each other – possibly separated by a controller, for example – and inform each other about changes or have them informed about them via listeners. The problem with this architecture can be that it is not always clear which data changes when and how: Which listeners react to which change and when? What change then triggers event handlers again? In the worst case, this leads to event cascades or “event storms” that make the interface unnecessarily slow.

React counteracts this problem with unidirectional data flow: there is only one source of truth and that is the state of a component. However, this approach means that a state that many components have to use moves higher and higher in the component hierarchy. In React, the principle of “Lifting state up” the speech.

While this pattern is very helpful for understanding applications and can also avoid typical inconsistency problems, it also has a disadvantage: “pushing up” the state in higher-level components can quickly create very complex components whose state and logic are overloaded. The deeper located components then wither away to pure display components. The latter are unproblematic since they are easily testable and possibly also easily reusable, but the complex “God components” at the top of the hierarchy pose a challenge. They can prove to be a bottleneck for several reasons: First, they are difficult to test , on the other hand they limit the scalability of the development approach. Because in the worst case, several functionalities are bundled in one component, so that different teams may have to develop it.

To home page

source site