📜 ⬆️ ⬇️

Unconventional React Overview

Hi, Habr!

We in Hexlet love our technology stack :) When telling others, many are jealous: Rails, Docker, AWS, React JS. The reaction we use primarily to create a web environment for the development of Hexlet-IDE , which allows our users to perform an exercise on developing applications and interacting with the virtual machine directly in the browser.

Today we publish a translation of the article “An Unconventional Review of React” by James Shore, the lead project for Let's Code: Test-Driven JavaScript.
')


I liked him. I did not expect this.

For special issues of Let's Code JavaScript in August and September, I studied React .

In case you don’t know React: this is a library for front-end web development. Using it, components are created: short, not-quite-HTML tags that can be combined to create an interface.

React is famous for its unconventional solutions: the implementation of a virtual DOM, the creation of interface elements in JavaScript instead of templates, the creation of a superset of the JavaScript language - JSX, which allows you to insert non-quite-HTML XML directly into JS code.

With these solutions, development is moving away from the DOM manipulation scheme - add this element, hide the effect of another element, update this text field. Instead, you describe how the DOM should look now. A reaction takes on the hard work of defining the necessary actions so that the DOM actually looks like you said.

For example, in the code that I wrote for the review there is a table that should change every time the configuration fields change. You might think that the code will be full of scary DOM manipulation logic, but in fact there is no code for manipulation at all. Here it is :

/** @jsx React.DOM */ // Copyright (c) 2014 Titanium IT LLC. All rights reserved. For license, see "README" or "LICENSE" file. "use strict"; var StockMarketTableCell = require("./stock_market_table_cell.js"); var StockMarketTableRow = module.exports = React.createClass({ render: function render() { var year = this.props.stockMarketYear; return <tr> <StockMarketTableCell value={year.year()} /> <StockMarketTableCell value={year.startingBalance()} /> <StockMarketTableCell value={year.startingCostBasis()} /> <StockMarketTableCell value={year.totalSellOrders().flipSign()} /> <StockMarketTableCell value={year.capitalGainsTaxIncurred().flipSign()} /> <StockMarketTableCell value={year.growth()} /> <StockMarketTableCell value={year.endingBalance()} /> </tr>; } }); 

This is the essence of the React, and this is what distinguishes it from others. The only question is: is he good?

Nontraditional review criteria


Usually, when you read a review of a front-end framework or library, you will learn about its size, or what famous people and companies use it, or its performance. Yes, all this is important. But the most important question for me sounds simpler:

Over the next 5-10 years, when will I support my product, will this code bring more benefit or suffering?

Not so important how much time the library will save me in the initial development. Oh no. Much more important is the cost of support throughout the life of my application.

For this, I have five criteria.

1. Closure (in-lock). When I decide to switch to a new or better framework (or library), how difficult will it be to switch?

2. Stubborn architecture (Opinionated Architecture). Can I solve problems in the way my application needs, or should I obey certain ideas developed by the authors of the framework?

3. Adverse complexity (Accidental Complexity). Do I spend time solving my problem or struggling with the framework?

4. Testing. Can I just test my code, without unnecessary trouble with mock objects?

5. Compatibility with search engines (Search Engine Compatibility). Will I have to dance with a tambourine to make the search engines index my site?

I rated React in each category with a (aiii!), (Buee!), Or ⚇ (neither there nor here).

1. Closure - ⚇ (neither there nor here)


Let's be honest: when you decide to say goodbye to React, you will have to rewrite the interface from scratch. There is no normal way to hide the React behind the layer of abstraction, and the React Interface code is like nothing else. So everything is pretty closed.

But why didn't the Reaction get a sad face?

Two moments save React. First, React provokes to put the application logic outside the UI, so you don't have to rewrite the entire application.

Secondly, the React API is relatively small. Not many points of contact (see point 3). This means that it is less likely to break something when updating the React. Also, the React is easy to use in isolation, for a separate part of the page, so you can gradually migrate from the React when the need arises.

2.Direct architecture - (uiii!)


React is a library, not a framework, and this is noticeable. The reaction does not dictate the architecture of the application. I had no problems connecting my existing and obviously strange code to React.

Some people see stubborn architecture as a good sign. "It allows me to understand how to structure the code." I prefer the opposite. The structure of the application should be dictated by the requirements of the application. The framework cannot predict these requirements, and they will change with the development of the application.

The reaction contains an architectural pattern called Flux , but it is completely optional. This is just a way to talk about the structure of the code, and not the mechanism built into the Reactor. It should be so.

3. Side complexity - ⚇ (neither there nor here)


It is necessary to know very little about the reaction, and it seemed simple and clear to me. There are only a couple of moments (the difference between “props” and “state”), only a couple of concepts (how to manage the state; immiable renderer methods) and several methods for implementing a typical component. My most complex component contains as many as three React methods. In most cases, one render () is enough.

The fly in the ointment is a virtual DOM. This is an impressive achievement, a key piece in React ... but it can be a leaky abstraction . As soon as you see a new or advanced DOM feature, you risk running into a fight with React. For example, CSS animations caused problems for some time, and focus management is still naughty .

Now, it seems, the React team has time to edit everything. But what will happen in five or ten years when React is no longer the most fashionable thing? The browsers continue to evolve, and before choosing a React for your project, ask yourself: am I sure that React will keep up with all the innovations my application needs?

4. Testing - (uiii!)


The story of Testing React looks a bit immature. She barely reached for a smiling face.

At first glance, React provides a simple API for testing, and it seems there is everything you need. You can render a component and search the DOM tree with a good set of functions. You can simulate events. You can make mock components, but I was pleased that I never needed them.

There is not a lot of documentation, there are not enough examples and recommendations on design, especially when compared with the rest of the React documentation. It only supports the sense of immaturity. But the main problem is that I could not find a way to compare components. Even in a relatively simple application, your components will contain components, and you don't want the tests to know something about the implementation details of the additional components.

For example, the ApplicationUi component contains the StockMarketTable component. I want to check if the table is updated when the configuration changes. For this, I wanted to check the table with a ready-made hard-code:

 it("updates stock market table when user configuration changes", function() { config.setStartingBalance(...); var expectedTable = <StockMarketTable stockMarketProjection={projectionFor(config)} />; var actualTable = TestUtils.findRenderedComponentWithType(app, StockMarketTable); //    ? }); 


In the end, I bypassed the problem by digging into the private details of Rekat's implementation, rendered the components into a static CTML and compared the result. Here is the code.

 function checkComponent(actual, expected) { var actualRendering = React.renderComponentToStaticMarkup(actual._descriptor); var expectedRendering = React.renderComponentToStaticMarkup(expected); expect(actualRendering).to.equal(expectedRendering); } 


It works, but in case of a fall it generates a terrible error message, and this code depends on the details of the implementation of the React. ( I had to visualize the runtime object graph!) Perhaps there is a better way - and there must be a better way - but I did not find it.

In addition to this not so small problem, it is a pleasure to test the React. Check out the ApplicationUi tests . They are wonderful in their simplicity, understandable and do not contain mocks. No test contains more than two lines, and it is the most complex component of the entire application.

5. Compatibility with search engines - (wiii!)


The reaction was able to make a small miracle: they made a front-end framework that has no problems with search engines.

Thanks to the virtual DOM, Reactor applications can be rendered on the server side using Node.js. This means that you only need one render channel for both search engines and real users. This also means that the pages are displayed immediately after they are submitted. No waiting for document ready events or downloading the entire js. The reaction can be used to supply static markup, with no client code at all.

Cool.

Bottom line: I recommend.

The reaction is surprisingly well-assembled library. It seemed to me simple, intuitive and easy to use. If you are looking for a front-end library for complex applications or even complex widgets for an existing page, you should pay attention to React. It is not perfect, and it is worth thinking about potential problems with a perforated abstraction of DOM, but it is very good. Recommend.

Source: https://habr.com/ru/post/249579/


All Articles