Injected Component Markup: React vs Angular 2

Justin Tulk
3 min readNov 24, 2016

--

Building off my previous piece listing some of my initial reactions to Angular 2 after switching from a React project, I’ve got some thoughts about the way these frameworks go about injecting markup into the DOM (or shadow-DOM) and the effects.

Sample Use Case

Here’s a sample use case. I’ve got an array of usernames I want to display, and I’m going to display them via two components. The first is basically a <ul>, but here it’s a smart component that will handing fetching the data (how and from where doesn’t matter). The child component will be a dumb component, basically an <li> that just displays the name. I’ll use <div> elements though so I can scale down the CSS declarations for simplicity.

// the data
const usernames = ["Donald", "Barack", "George", "William"]
// the basic markup structure
<div class="list">
<div class="item">Donald</div>
<div class="item">Barack</div>
<div class="item">George</div>
<div class="item">William</div>
</div>
// the basic styles
.list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
.item {
flex: 0 0 25%;
}

React

The basic React implementation would look like this:

const Item = ({name}) => <div style={{'flex': '0 0 25%'}}>{name}</div>class List extends Component {
render(){
const usernames = ["Donald", "Barack", "George", "William"]
const listStyle = {
'display': 'flex',
'flex-direction': 'row',
'flex-wrap': 'wrap'
}
return (
<div style={listStyle}>
{usernames.map(item => <Item name={item} />)}
</div>
)
}
}

The resulting markup would match the expected markup exactly (save for the style declarations instead of CSS classes), because React replaces child components wholesale with the structure returned by the sub-component’s return().

Easy peasy.

Angular 2

Explaining how Angular 2 handles this will be more complicated. For one, I’m going to have to include both components up into their containing module, which I’m not demonstrating here. I’ll also exclude TypeScript checks.

First, the smart component.

@Component({
selector: 'my-list',
template: `
<style>
.list {
display: flex;
flex-direction: row;
flex-wrap: wrap;
}
</style>
<div class="list">
<my-item *ngFor="let item of items" [name]="item"></my-item>
</div>
`
})
export class ListComponent {
items = ["Donald", "Barack", "George", "William"];
constructor(){ }
}

And the dumb one.

@Component({
selector: 'my-item',
template: `
<style>
.item {
flex: 0 0 25%;
}
</style>
<div class="item">{{name}}</div>
`
})
export class ItemComponent {
@Input() name: string;
constructor(){ }
}

The resulting markup (in Chrome Inspector) would look like this:

<project-card-list>
<div class="list">
<my-item>
<div class="item">Donald</div>
<my-item>
<my-item>
<div class="item">Barack</div>
<my-item>
<my-item>
<div class="item">George</div>
<my-item>
<my-item>
<div class="item">William</div>
<my-item>
</div>
</project-card-list>

As you can see, the sub-component gets wrapped in a tag matching its selector. This bugs me for a couple of reasons:

  1. The flex-box layout still seems to work even though there’s a mediating tag. I have no idea why exactly (shadow DOM weirdness?). For how I expect this to work see this JSBin. On one hand, this is probably appropriate because it’s what I intended, but on the other hand I can’t figure out why the <my-item> tag seems to be ignored when calculating the layout, and I can’t find any documentation on this. If I set the my-itemtag todisplay: flexit breaks, but not otherwise. Can anyone explain this?
  2. Like everything else about Angular vs. React — the code always seems twice as verbose, and I hate, hate, hate this syntax: *ngFor="let item of items"when compared with React’s clean .map().
  3. There’s some other weirdness you can get into if you get rid of the containing <div class="item"> wrapper on the child component and try to style the my-item tag directly. For one, that class isn’t going to be touched by any CSS you specify in the child component, and while I think you can jump up the scope chain (:host maybe?) this seems really ugly and like something that’s best to be avoided.

--

--

Justin Tulk

Staff Software Engineer. Making computers do stuff since 2011.