JSFiddle - React, Tailwind, and code Playground

HTML

<script src="http://js.arcgis.com/3.11amd/"></script>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<link rel="stylesheet" href="http://js.arcgis.com/3.11/esri/css/esri.css">
<esri-map id="map" lat="45.523452" lng="-122.676207" zoom="12" basemap="topo">
    <esri-feature-layer url="https://services.arcgis.com/rOo16HdIMeOBI4Mb/arcgis/rest/services/Heritage_Trees_Portland/FeatureServer/0"></esri-feature-layer>
    <esri-feature-layer url="https://services.arcgis.com/rOo16HdIMeOBI4Mb/arcgis/rest/services/Portland_Parks/FeatureServer/0"></esri-feature-layer>
</esri-map>

CSS

html, body, #map {
    margin: 0;
    width: 100%;
    height: 100%;
}

JavaScript

var app = angular.module('demo', []);

app.directive('esriMap', function ($q) {
    return {
        restrict: 'E',
        scope: false,
        compile: function ($element, $attrs) {
            // remove the id attribute from the main element
            $element.removeAttr("id");

            // append a new div inside this element, this is where we will create our map
            $element.append("<div id=" + $attrs.id + "></div>");

            // since we are using compile we need to return our linker function
            // the 'link' function handles how our directive responds to changes in $scope
            return function (scope, element, attrs, controller) {
                // link function
            };
        },
        controller: function ($scope, $element, $attrs) {
            // only do this once per directive this deferred will be resolved with the map
            var mapDeferred = $q.defer();

            require([
                'esri/map'], function (Map) {
                var map = new Map($attrs.id, {
                    center: [$attrs.lng, $attrs.lat],
                    zoom: $attrs.zoom,
                    basemap: $attrs.basemap
                });

                mapDeferred.resolve(map);
            });

            // method returns the promise that will be resolved with the map
            this.getMap = function () {
                return mapDeferred.promise;
            };

            // adds the layer, returns teh promise that will be resolved with the result of map.addLayer
            this.addLayer = function (layer) {
                return this.getMap().then(function (map) {
                    return map.addLayer(layer)
                });
            };
        }
    }
});

app.directive('esriFeatureLayer', function ($q) {
    // this object will tell angular how our directive behaves
    return {
        // only allow esriFeatureLayer to be used as an element (<esri-feature-layer>)
        restrict: 'E',

       ...