React's Odd Obsession With Declarative Syntax
Tags: react, javascript, graphql, apollo
Published: 2020-03-23 03:56:51

The first thing you need to know is that I'm a React developer.  I've been slinging code since long before there was anything called "React".  But in the last several years, it's become my favorite tool and it's the primary skill I'm paid for in my current job. So any "critique" to be drawn from this post is in no way a slam on the framework itself.  I _love_ React.  

But "love" doesn't have to be unconditional.  I love my family.  But I can still point out instances where my family members have done some really stupid stuff.  And as a self-appointed "React Acolyte", I can easily point out some places where React - and its associated community - can get downright... _odd_.  The _declarative syntax_ is one of those places.

## Declarative vs. Imperative Syntax

React devs _loooooove_ to talk about declarative syntax.  They speak of it lovingly, like some kind of magic spell, the way that Java devs talk about "encapsulation".  As though merely uttering the word will somehow wash the bugs from their code and solve their greatest programming challenges.  

Hell, I'll even admit that _I'm_ a huge fan of declarative syntax.  So much of UI development just feels more intuitive if you can _declare_ the component (and its associated logic) in the _place_ where that component will ultimately be rendered.  Compare this to, for example, jQuery, where it felt like every bit of display logic was flung off into functions that seemed to have only loose connections to the eventual layout of the app.  So in the interest of full disclosure, I think that the declarative syntax is, _in most cases_, pretty damn cool.

The problem isn't with React's declarative syntax in general.  The problem is that, like so many other things in tech, the community gets ahold of something and decides that **There Shall Be No Other Approach**.  The problem is that the community doesn't embrace the declarative syntax as _a tool_, to be deployed _when it best suits the job_.  

Instead, the community too often looks at declarative syntax as some kind of religious dogma.  React devs who stubbornly try to shove _everything_ into a declarative syntax are like construction managers who show up on site and say, "_This_ building will be constructed entirely with **hammers**!  _NO SCREWDRIVERS!_  Hammers are _good_!  Screwdrivers are _bad_!  So we will only be using hammers on this project."

## Declarative = Rendering

So if React is fundamentally tied so closely to declarative syntax, and if I truly love React as much as I say that I do, then why would I ever get exasperated/annoyed with that syntax?  Part of the problem is based on _performance_, and part of it is based on _separation of concerns_.  

**Performance**

If you've spent any serious time around React, then you've also spent some serious time stressing out about unnecessary re-rendering.  React's virtual DOM is a pretty cool bit of auto-magicalism.  When it works properly - and it _usually_ works quite properly - it just kinda "magically" updates the required display elements whenever they need to be updated.  

React's re-rendering feels (to me) a lot like Java's garbage collection.  One of Java's big selling points was that devs no longer had to do manual memory management.  Java's garbage collector "auto-magically" frees up memory when it can be freed up, and releases the developer from having to worry about memory allocation.  But if you've ever worked on a large enough Java project, at _some point_ you found yourself wrestling with garbage collection, trying to _force_ it to release some critical bit of memory that it just didn't seem to want to release on its own.

Similarly, React's virtual DOM means that devs no longer have to manually refresh every single DOM element that was dependent upon `stateVariableX` every single time that variable is updated.  React's virtual DOM "auto-magically" figures out what should-and-shouldn't be refreshed (re-rendered), and releases the developer from having to manually update all the dependent DOM elements.  But if you've ever worked on a large enough React project, at _some point_ you found yourself wrestling with the render cycle, trying to stop it from spawning unnecessary re-renders.

You see, "auto-magicalism" has a cost.  At some point, it can be maddening to figure out _why_ Java's garbage collection is-or-is-not triggering at a given moment.  Similarly, it can be maddening to figure out _why_ React insists on re-rendering a component, even when you _swear_ that there should be no updates that would trigger such a re-render.

[**Note:** Somewhere, there's a C developer reading this and chortling.  Seasoned C developers don't get _angry_ about manual memory management.  They _prefer_ it. They even _embrace_ it.  But that's a topic for another post altogether...]

> So what does any of this have to do with _declarative syntax_??

If there's any "problem" with declarative syntax, it's that I've seen far too many cases where there is _business logic_ - logic that's normally represented in an _imperative style_, that's awkwardly shoved into a declarative syntax.  What this means, in a practical sense, is that:

> Any business logic that's been shoved into a declarative syntax _gets run every single time the component is rendered_.  

Sometimes, this is "manageable".  But other times... it just represents a needless recomputing of something that never needed to be recomputed.  To put it another way, there are many potential algorithms that I don't want to be repeated _every single time the component renders_.  But if _all_ of your logic is anchored into a declarative syntax, then it's definitely in danger of being run on every single render.

An example might illustrate this better.  Imagine that we want to show the user the encrypted equivalent of their username.  For the sake of the illustration, we'll also assume that the username is known at the point that the component is mounted, and that the username is immutable.

I've seen plenty of React solutions that attack this issue by saying, "Here's a component that you can use to display an encrypted value."  Then they proceed to show you how to use this component _declaratively_, like so:

```javascript
// Example 1
import React from 'react';
import ShowEncryptedValue from './ShowEncryptedValue';

export default class UserData extends React.Component {
   render = () => {
      const {name, username} = this.props;
      return (
         <>
            <div>Name: {name}</div>
            <div>Username: {username}</div>
            <div>Encrypted username:
               <ShowEncryptedValue value={username}/>
            </div>
         </>
      );
   };
}
```
When you've installed `ShowEncryptedValue` from NPM, and imported it into this component, and then leveraged its functionality with a simple `<ShowEncryptedValue value={username}/>`, you might be thinking, "Wow. That was easy.  What a great solution for showing an encrypted value."  But there's a _problem_ that's lurking in this example.

There's some kind of _calculation_ that must be done to determine the encrypted value.  Furthermore, since we've already established that the username is immutable, this calculation should really only need to be completed **_once_**.  But because we've tied this calculation to the render cycle (via declarative syntax), we now risk repeating this calculation on any future re-rendering.

Yes, I realize that some of that potential inefficiency will depend upon the quality of the code that lives inside of `<ShowEncryptedValue>` component.  But as programmers of quality solutions, we shouldn't be dependent upon the idea that these tools are doing the "right" processing on their own.  When we know that we have a calculation, that depends upon an immutable value, we should only ever be running that calculation _once_.

To illustrate this, consider the following counter example:

```javascript
// Example 2
import React from 'react';

export default class UserData extends React.Component {
   encryptedUsername = null;

   componentDidMount() {
      const {username} = this.props;
      /*
          do some logic here that computes the encrypted username value
      */
      this.encryptedUsername = whateverValueWasJustComputed;
   }

   render = () => {
      const {name, username} = this.props;
      return (
         <>
            <div>Name: {name}</div>
            <div>Username: {username}</div>
            <div>Encrypted username: {this.encryptedUsername}</div>
         </>
      );
   };
}
```
Notice the difference here.  In this example, the encrypted value can only ever be computed _one time_ - when the component is mounted.  But this example also depends upon a bit of _imperative syntax_.  In other words, there's some implied logic in `do some logic here that computes the encrypted username value` that is plain ol' function-based JavaScript.  And from what _I've_ seen, there are just sooooo many React devs who greatly prefer Example 1 over Example 2, even though Example 2 is probably much more efficient.

**Separation of Concerns**

For those who remember (or still adhere to) MVC, the `return` statement (in a class-based component _or_ in a functional component) is the "view".  It's the place where we're actually dictating how things should be displayed.  

For whatever reason, I've noticed that React devs _love_ to cram all kinds of _logic_ into the "view".  They'll do stuff like this:

```javascript
// Example 3
import React from 'react';

export default class UserData extends React.Component {
   render = () => {
      const {day, foos} = this.props;
      return (
         <>
            {foos.map(foo => {
               if (day === 'Monday') 
                  return foo;
               const newFoo = foo.replace(/./g, '');
               return (
                  <div key={newFoo}>
                     `${newFoo} with periods removed`
                  </div>
               );
            })}
         </>
      );
   };
}
```
I really don't expect any of you to agree with me on this.  I see code like I've shown above, in Example 3, _everywhere_ in React.  But I'm gonna be honest with you here - I _hate_ it.  I think it's a convoluted mess. I truly dislike seeing all of that if/map/for/whatever logic crammed into the middle of a `render()` function (or simply into the `return()`, if it's a Hooks-based component).  

It's hard (for me) to read.  It feels (to me) like a violation of _separation of concerns_.  And, to be completely honest, it just seems kinda _lazy_.  It seems like the dev couldn't be bothered to encapsulate that logic into a separate function - so they just crammed it all into the body of the `return`.

I know that many React devs don't share my viewpoint on this.  But this feels to me like a bastardization of the declarative syntax.  IMHO, it's not "declarative" if you've taken all of your normal _imperative_ code and shoved it right into the middle of your `render()/return()`.

## APIs

This might feel a bit "theoretical" to you.  So let me give you one simple example where I've seen the declarative syntax fail over and over again.  I'm talking about APIs.

An API call is perhaps one of the best examples of logic that I absolutely **_do not_** want to be tied to the render cycle.  API calls are slow.  They're computationally expensive.  When I'm building a Rich Internet Application, there is no excuse for spawning unnecessary API calls.  The API should be called _exactly when I want it to be called_, and it should be called _only as many times as are necessary_.

Recently, I started diving more into GraphQL.  If you're a React dev, and you start exploring GraphQL, it probably won't take you long to find Apollo.  When I first loaded up Apollo, I looked at the docs and read this:

> **Declarative data fetching:** Write a query and receive data without manually tracking loading states.

I'll be honest.  As soon as I read this "feature", it gave me pause.  But I figured, "Well, for such a well-supported package, they must have gone to great pains to avoid unnecessary API calls."  I... was mistaken.

After getting everything installed, I spent the better part of _two days_ trying to tightly constrain any stray renders.  I did this because Apollo uses a declarative syntax for its API calls.  This means that it tries to make a distinct API call _for every render of the component_.  

Some of this just comes down to solid React application design.  And there were certainly _some_ optimizations I was able to make that removed a lot of unnecessary renders (and thus, a lot of unnecessary API calls).  But even after great wailing and gnashing of teeth, I found that every time I loaded my app, it was making the core API calls **_TWICE_**.  

To be frank, I'm sure that if I'd just slaved away at this task for an indeterminate period of time, I would have, _eventually_, figured out how to limit my API calls to a _single_ request.  But after a while, it felt increasingly silly.

I mean... Why on earth would you ever want to tie your API calls _to the render function_???  That's just a recipe for creating an ongoing flood of unnecessary API calls.  But that's the way Apollo does it by default.  And when you start to look at _almost any other React/GraphQL library_, you realize that they all try to do it the exact same way.  They all do it that way because there is this odd... _obsession_ in the React community with the declarative syntax.  

My "answer" to this problem was to rip Apollo out altogether.  Rather than depending on its built-in (declarative) components, I just created my own `fetch()` calls, _manually_ formatted in the GraphQL syntax, written in _imperative_ functions, that could be called, with a high degree of control, whenever I _wanted/needed_ them to be called.  

## Conclusion

Please note that this post is **_NOT_** a generalized complaint about Apollo or GraphQL.  Nor is it any kind of complaint about the general idea of using declarative syntax.  But like any other _tool in the tool belt_, a declarative syntax has ideal uses - _and_ instances where it is **not** ideal.  IMHO, React devs tend to lose sight of this basic concept.