Tuesday, 30 July 2019

My First React App And What I Did Wrong

I recently had the pleasure of using React to build an internal use only app for Acro Media. I say pleasure because it genuinely was despite the fact I was met with many frustrations with using React for the first time. To be fair, these were more my own shortcomings trying to learn a framework I'd never used before, rather than the framework itself.

As with building any app, my failures taught me far more than my successes. Here are those failures:

1. Poor Structure

This stems mainly from the fact I didn't understand what React really was. I was aware, of course, that parts of my page should be abstracted into components but I didn't understand how to truly utilize that. I didn't, for example, build my components in a way that would make them reusable in a concrete way. Not only were they not reusable within the app but they couldn't be copied into another app, either.

I didn't understand that even though I created a table component, with header and body sub-components abstracted out, I made them very specific to the app. While this app only needed the one table, and so this worked out fine in this instance, I would have had to do a lot of refactoring when I had the need to add a second one. Instead, I should have created a generic table component and used props or higher order components to customize it.

Finally, I used a single src/ directory to hold my handful of components. Even though this worked fine in this very specific case, if I'd laid out the project, and thereby the components in a more discrete way, I would have required a better defined structure.

Generally speaking, you'd have a Components/ directory separated into components, like Table/.

2. Poor Per-Component CSS

When I began the project, I was aware you could import CSS into a React component. I assumed, wrongly, this was just a nice way to abstract CSS into smaller chunks. While this is indeed a benefit, how wrong was I?

Thankfully, before the project's end, I realized the power of using per-component CSS. I was further relieved to discover how I could leverage SASS and Webpack with React to make a very powerful combination of tools.

3. Poor Understanding of State

This was highly frustrating. I had only two main components: a form in which you could set parameters with a button to submit them and a table where fetched data should be displayed. A classic "report" app. The problem was, these components were sister components, on the same level, with a common parent but I didn't understand how to react (lul) to an event in one component so that the other would automatically get updated.

Searches repeated suggested using Redux but I was convinced that route was completely overkill for what I was trying to achieve. I wasted a heck of a lot of time looking into Redux and other solutions. Shouldn't it be simple to link components up? Of course, I could use props from the parent to provide callbacks to update state in the App but that felt so wrong.

How can something that feels so wrong be so right?

Maybe there is an even better way but as it turns out, using Hooks (or state in a class) is really the easiest way. Store the state of the app in the top level component, pass a state update function into the form component and pass the state of the app as a props to the table component. Easy-peasy.

Another instance might be to create a global "state" class and you could dispatch updates from components but, honestly, you may as well use Redux at that point.

4. Lots of Classes

The documentation confused me. If I used a function to create a stateless component, and I used a class to create a stateful component, why not just make every component a class? Why did React prefer or encourage functions over classes?

Well, in 16.8 at least, you almost never need classes any more and using functions is actually a lot more straight forward, requiring fair less boilerplate. After many hours of use, I came to rewrite all my class based components to functions and I couldn't be happier. Viva function components!

5. No TypeScript

Not everyone may be a lover of TypeScript, and I'm certainly not an evangelist either, but I also appreciate what it's trying to do. I am a fan of strong, static typing and TypeScript is a good step in this direction.

When I started the app, I had some logic only portions written in TypeScript. Unfortunately, as development ground on, I ended up converting this code to pure Javascript because of a frustrating bug. I had concluded, wrongly, that something was being happening in the transpiling that was causing my issue.

As it turned out, this was not the case and I regret that I never converted the code back to TypeScript. Whoops.

6. No Object Destructering

Prior to this project, I wasn't familiar with destructuring in Javascript. After learning about it, I used array destructuring any time I used a React state Hook but, for some reason, I still didn't know about object destructuring. This in spite of the fact I came across examples that used it. I just didn't comprehend what I was seeing.

Now that I know about it, I wish I'd used it. Ah, well...

Things That Went Right

Here is a list of things, without explanation, that went right:
  1. Yarn dependency management.
  2. SASS.
  3. Fetch API and Promises.
  4. Webpack
That's all the wisdom I shall pass on.