React components are first class
React components have a surprisingly simple property which sets them apart from the equivalents in other frameworks. Rather then being specified by name in a string based template, theyâre referenced as a value in Javascript.
import Hello from "./Hello";
<Hello>World</Hello>;
Since the name of the tag is actually just the name of a local variable, component references can be dynamically calculated, passed into other components as props and even manufactured on the fly.
The closest equivalent in Angular would be a directive, which are stored in an app wide namespace (along with directives from third party modules) and referenced by name.
<!-- "hello" was registered elsewhere as a directive -->
<hello>World</hello>
Avoiding namespace clashes is a relatively superficial advantage, but components as first class Javascript objects open up a huge amount of flexibility and composability. Observe a simple case of dynamically selecting a component in React:
const DynamicFoo = React.createClass({
render() {
const Foo = selectAFoo(this.props.type);
return <Foo>Bar</Foo>;
},
});
The simplest equivalent I can devise in Angular (without writing some sort of generic helper directive) is this:
app.directive("dynamicFoo", [
"$compile",
function ($compile) {
return {
scope: {
type: "=",
},
link(scope, element, attrs) {
// Without this watch, it won't update the
// component type after the initial render.
scope.$watch("type", function (type) {
const foo = selectAFoo(scope.type);
// This would be a bit nastier without template literals!
element.html(`<${foo}>Bar</${foo}>`);
$compile(element.contents())(scope);
});
},
};
},
]);
Under all of that boilerplate, weâre really just creating a dynamic template on the fly via string munging. Itâs not so bad in the case of a simple name swap, but what about dynamic attributes in React?
<Foo {...dynamicProps}>Bar</Foo>
The following Angular version isnât robust enough to seriously consider using in production for any number of reasons (hopefully obvious to experienced Angular developers), but itâs the simplest naive approach I can come up with.
const combined = dynamicProps.map((v, k) => `k="${v}"`).join(" ");
// turns {one: 1, two: 2} into 'one="1" two="2"'
element.html(`<foo ${combined}>Bar</foo>`);
Itâs also rather gross, while the React version is idiomatic.
The relative simplicity of Reactâs API does not come at the cost of power. In fact, its regularity and conceptual integrity enable a ton of useful patterns. Donât be so quick to jump into âsophisticatedâ registry patterns when the humble variable has so much to offer.