React for the Angular Developer — Pt 2

A few weeks ago I wrote a blog post focused around the perspective of an Angular developer digging into React. That post was a high-level overview and mainly highlighted the things that I missed in React. In this post, I want highlight the other side of the conversation; which is what are the things that I really enjoy about React. In upcoming post, I’ll highlight the things I dislike about React so stay tuned!

Like I mentioned in my previous post, this is NOT a comparison article, its the story of an Angular developer trying out React. With that said, let’s dive in!

What I’ve really enjoyed

Simplicity

Simplicity is a double edge sword, it can be easy to get started and going but down the road bite you. I don’t think anyone will dispute that React is one of the easiest frameworks to get started with but thats exactly what worried me at first. Its so simple but when I get to a project of 100k+ LOC how is it going to scale?

So far so good, React’s done a great job of focusing on one goal of making an easy-to-use component library. They don’t claim to be the ‘batteries included’ framework that solves all your problems because the truth is while some problems can be cookie cutter, most are not that straight forward. Every organization has their quirks on how the UI is supposed to look, how data is acquired, etc.

React’s Documentation

Angular has a great depth of documentation but wowzers, its so overwhelming. On the other hand, the React documentation is straight forward and helps you avoid pitfalls by highlighting reasons why not to do things very nicely (👈 which I really like).

Simple Change Detection

In my past article, I mentioned one of the things I dislike about Angular is ZoneJS. ZoneJS is the way which Angular detects changes in the application and renders the updates. If you’ve ever read any of my work, you know I’m a pretty big critic of ZoneJS.

For those of you who don’t know what ZoneJS is, ZoneJS essentially monkey patches browser events and when you do something like click, it captures that scope and then re-runs change detection in that scope. It’s a pretty clever and ‘magical’ in theory but in practice it becomes a burden. By taking this approach it can create unexpected change detection cycles that can result in performance issues and if things don’t aren’t piped through the zones correctly change-detection doesn’t even run. To Angular’s credit, they know this is a problem and they are working to replace it.

Another mechanism Angular uses for change detection is observable from RXJS. This is awesome and painful all at the same time; you end up dealing with managing a slew of subscriptions just to do simple things and it can become difficult to do simple things with the variety of operators you need to learn. Another confusing subject is the different change-detection modes that Angular has: traditional and on-push.

The title of this section is called “Simple Change Detection” because to trigger change-detection cycles in React you literally just call setState to update the props of a component.

Let’s say we have a counter component, in Angular you would have an observable that each click would call next like:

obs.next(++count)

and then in the template you would use the async operator to subscribe to the observable .In React, you would simply do:

this.setState({ count: this.state.count + 1 });

By calling setState we tell the component to re-render the children, if props change on the sub-children they trickle down and update as well. I like to think of React as one big observable stream trickling changes downwards.

Context API

The Context API provides a mechanism to pass data, callbacks, etc to children without manually passing them. In addition, it can help scope and provides ways to do IoC (inversion-of-control) which can be awesome for testing. I like this think of it as a declarative dependency injection system 🔥🔥. It’s so powerful, it can/could even replace Redux!

A great example of a use case for this is a theming system. Let’s say we have the ability for users to toggle between light and dark mode. If we were in Angular, we might have some service that reads out of option from local storage or a service and then is injected into each component that it cares about. If our app has certain places where the theme can’t be toggled, we might use a DI token in our NgModule to replace the value. The Context API can handle this for us but in my opinion a cleaner and more natural declarative approach we web devs are accustomed to. Let’s take a look!

In our root app component, we would declare the provider like so:

<ThemeContext.Provider value={this.state.theme}>
<button onClick={this.toggleTheme}>Toggle theme</button> .
{children}
</ThemeContext.Provider>

In this example, we define the ThemeContext and give it the initial value. Now in any of the children of this component they can read the value of that context like so:

<ThemeContext.Consumer>
{theme =>
<Button style={{ background: theme.background }}>Hi</Button
}
</ThemeContext.Consumer>

If we want to interchange the value, we simply describe another provider and the children will receive that value. It’s so simple but powerful!

If you are interested in learning more, the React docs have a great spill on it: https://reactjs.org/docs/context.html

Error Boundaries

Error handling is always tricky; how do you handle them globally but in certain situations catch them and show something more graceful.

In Angular, we can override the Error object using dependency-injection globally and at the NgModule level to handle specific error situations but the problem is it does not handle the component tree very well. React created this concept of Error Boundaries which are “React components that can catch JavaScript errors anywhere in their child component tree, log those errors, and display a fallback UI.”

It’s pretty powerful, let’s take a quick look at how it works. In the example below we define a component with a componentDidCatch function that will be invoked anytime an error occurs in the scope (including children) of this component.

class ErrorBoundary extends React.Component {
state = { hasError: false };
   static getDerivedStateFromError(error) {
return { hasError: true };
}
   componentDidCatch(error, info) {
logErrorToMyService(error, info);
}
   render() {
if (this.state.hasError) {
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
}

When we want to use this, we just wrap our component with this new component:

<ErrorBoundary>
<MyWidget />
</ErrorBoundary>

Anytime an error is thrown in the context of this component, we can log the error to a service and then set our state to describe that an error occurred and in our render branch and show an error message rather than the children of the component.

Just like the Context API, we can scope this too! That gives us the ability to create a global handler and then specific handlers for each component tree that we want to handle special!

To learn more, ReactJS docs has a great write up on this: https://reactjs.org/docs/error-boundaries.html

Slots/Content Projection in JSX

In Angular, we have a concept called ‘slots’ which builds on Web Components spec. These directives allow us to insert chunks of external content into specific locations in our content. At the surface it’s quite a simple concept but under the hood its rather complex which the way it works from change detection to the rendering aspect.

When I first started using React, I couldn’t figure out how you accomplish this. After digging quite a bit, I realized what I was missing, in JSX we can declare components and pass them around like any other variable. When you need to do some sort of ‘slot’, you simply make it another prop in the component and presto! This is quite genius because it side-steps a lot of the trickiness around the change detection and projection of these components. Let’s take a quick look:

<MyComponent content={<OtherComponent />} />

Wow — easy!

Closing

There are so many other things I could highlight but these are some of my top favorites. I encourage you to experiment and see what all the possibilities are of all the frameworks we have today, its quite amazing whats available!

I hope you enjoyed the post, if you liked it follow me on Twitter and Github for more JavaScript tips/opinions/projects/articles/etc!