Welche Webtechnologie passt zu mir?
Alexander Casall@sialcasa
Software Architekt &Scrum Product Owner
Webentwicklung
DAS richtige Webframework
Webframeworks
https://github.com/mraible/history-of-web-frameworks-timeline
Server-seitiges Rendering vs
Client-seitiges Rendering aka Single Page Applications (SPA)
Rendering
Rendering
Server
Client
Server side rendering
Client siderendering
GET http://catcontent.com
RenderingServer
Client
GET
<html> … </html>
GET<html> … </html>
GET<html> … </html>
Server Side Rendering
Rendering
Rendering
Server
Client
Server side rendering
Client siderendering
GET http://catcontent.com
Rendering
Server
Client
GET
<html> <script> </script> </html>
GET
{ "cat": { "name":"grumpy“ } }
GET
{ "cat": { "name":"garfield“ } }
Client Side Rendering
Vorteile• Caching der
gerenderten Templates • Dokumenten-Ansatz
• Hohe User Experience • Ein Programmiermodell
im Client (klare Trennung der Aspekte)
RenderingServer
Client
Rendering
Server
Client
Nachteile• Seiten müssen erneut
übertragen werden • Serverseitige Sessions
notwendig (stateful)
• Initialer Ladeaufwand • SEO kritischer • Zusätzliche API
Schicht (e.g. REST) • Unvorhersehbare
Performance
RenderingServer
Client
Rendering
Server
Client
Single Page Applications
https://github.com/mraible/history-of-web-frameworks-timeline
SPAs
Angular 2 vs. React
als Rich Client Platform zu verstehen
in TypeScript geschriebenes SPA Framework
verfolgt Komponentenansatz
Angular
Typescript
Optional statisch getypt interfaces, enums, generics, access modifiers …
interface ICar{ engine: string; color: string; }
class Car implements ICar {
constructor (public engine: string, public color: string) {}
private drive(direction:Direction) : boolean{ return false; //unfall }
}
Transpiliert zu JavaScript
Komponenten
Komponentenansatzheader component
category component
discount component
content component
suggestionsoverview component
suggestion component
webshop component
highlight component
@Component({ selector: 'category', templateUrl: 'category.component.html', styleUrls: ['category.component.css'], }) export class CategoryComponent { title = 'categorycomponent works!'; }
Struktur einer Komponente
@Component({ selector: 'categories', template: '<h1> {{title}} </h1>', styleUrls: ['category.component.css'], }) export class CategoryComponent { title = 'categorycomponent works!'; }
Template
Styles
TypeScript
Struktur einer Komponente
Ein genauerer Blick auf Templates
@Component({ selector: 'categories', template: `<ul>
<li *ngFor="let category of categories"> {{category.name}} </li> </ul>`,
styleUrls: ['category.component.css'], }) export class CategoryComponent {
var categories: Categories[] = [ { "id": 1, "name": "jackets" }, { "id": 2, "name": "trousers" }, { "id": 3, "name": "planes" } ];
}
Structural Directive
<— Binding
@Component({ selector: 'categories',
template: '<button [style.color] = "cool ? 'red': 'green'" (click)="toggleCoolness()">Coolness</button>'
}) export class CategoryComponent {
cool = false;
switchCoolness(){ this.cool = !this.cool;
}
}
Style Bindings
Unidirektionales Binding@Component({ selector: 'categories', template: `<h1> {{title}} </h1>`, styleUrls: ['category.component.css'], }) export class CategoryComponent { title = 'Display this!'; }
Bidirektionales Binding & Events
@Component({ selector: 'categories', template: '<input [(ngModel)]="input"
(click)="addPlus()">' styleUrls: ['category.component.css'], }) export class CategoryComponent {
input = 'initial Value';
addPlus(){ title += '+';
}
}
https://angular.io/docs/ts/latest/guide/template-syntax.html#!#binding-syntax
Verschachtelung
@Component({ selector: 'webshop', template: `
<header/> <categories/> <discounts/> <content/> <suggestions/> `
}) export class WebshopComponent {
}
Verschachtelung der Komponenten
Komponentenansatzheader component
category component
webshop component
@Component({ selector: 'webshop', template: `
<header/> <categories/> <discounts/> <content/> <suggestions/> `
}) export class WebshopComponent {
}
@Component({ selector: 'categories', templateUrl: 'category.component.html' }) export class CategoryComponent { }
Komponentenansatzheader component
category component
webshop component
Kommunikation zwischen Parent / Child?
@Component({ selector: 'parent',
template: '<child [text]="displayInChild"></child>' }) export class ParentComponent {
displayInChild = 'Text of Parent!' }
Daten von Parent zu Child über Binding
@Component({ selector: 'child',
template: '<label>{{text}}</label>'‚ }) export class ChildComponent {
@Input() text : String }
@Component({ selector: 'parent', template: '<child (close)="onEvent($event)"> </child>' }) export class ParentComponent {
onEvent(input: String) {…} }
Daten von Child zu Parent über Events
@Component({ selector: 'child',
template: '<label (click)="close.emit('closeme')">Text</label>'‚ }) export class ChildComponent {
@Output() close : EventEmitter<String>
}
Weitere Kommunikationsarten zwischen Parent / Child möglich
https://angular.io/docs/ts/latest/cookbook/component-communication.html
Services für Datenzugriffe
Services
@Injectable() export class CategoryService { getCategories() : Category[]{ … } }
Component
Service
Dependency Injection
CategoryService
CompA
@Component({ …, providers:[CategoryService] }) export class CompA {}
CompB CompC
@Component({…}) export class CompB {
//Constructor Injection constructor (private _service:
CategoryService){}
doSomeThing(){ this._service.getCategories(); } }
CompC sieht genau so aus, und bekommt die gleiche Instanz des Services
CategoryService
CompA
CompB CompC
@Component({ providers:[CategoryService], … }) export class CompB {
//Constructor Injection constructor (private _service:
CategoryService){}
doSomeThing(){ this._service.getCategories(); } }
CompC sieht genau so aus, und bekommt die eine eigene Instanz des Services
CategoryService
React
• SPA Library
• verfolgt Komponenten Ansatz
• beschränkt sich im Kern auf Strukturierung und Rendering von Komponenten
React
Struktur einer Komponente
class HelloWorldItem extends React.Component{ constructor(props){ super(props); this.state.counter = 1;
}
render(){ return React.createElement('div', {}, React.createElement('label', ...), ); } }
Struktur einer Komponente
class HelloWorldItem extends React.Component{ constructor(props){ super(props); this.state.counter = 1;
}
render(){ return ( <div>
<label>{this.props.title}</label> </div>
) } }
JSX
class HelloWorldItem extends React.Component{ constructor(props){ super(props); this.state.counter = 1;
}
render(){ return ( <div>
<label>{this.props.title}</label> </div>
) } }
Struktur einer Komponente
Input von parent
Interner Zustand
Render wird aufgerufen, wenn props oder state neu gesetzt wird
Ein genauerer Blick auf JSX
class HelloWorldList extends React.Component{
constructor(props){ super(props); }
render(){ return ( <div> <ul> {this.props.items.map((i,index) => <li key={index}>{i}</li> )} </ul> </div> ) } }}
JavaScript statt Template Syntax
class MyComponent extends React.Component { constructor(props) { super(props); this.onInputChanged = onInputChanged.bind(this);
}
onInputChanged(event) { this.setState({input: event.target.value});
}
render() { return ( <div> <input type="text" value={this.state.input} onChange={this.onInputChanged}/>
</div> );
} }
Eventhandling
class MyComponent extends React.Component { render() { var header = <h1>MyHeader</h1>; var footer = <p>Footer 2016</p>; var greeting;
if(this.props.loggedIn) { greeting = <p>Hallo {this.props.name}</p>;
} else { greeting = <p>Hallo Gast</p>;
}
return ( <div> {header} {greeting} {footer}
</div> );
} }
JSX in erweiterter Ausprägung
Render wird aufgerufen, wenn props oder state neu gesetzt wird
Verschachtelung
Verschachtelung der Komponenten
class Webshop extends React.Component{ constructor(props){ super(props); } render() { return (
<div> <Header/> <Categories/> <Discounts/> <Content/> <Suggestions/> </div>
); } }
class Webshop extends React.Component{ constructor(props){ super(props); } render() { return (
<div> <Header/> <Categories/> <Discounts/> <Content/> <Suggestions/> </div>
); } }
class Categories extends React.Component
Kommunikation zwischen Parent / Child?
class Parent extends React.Component{ … render() { return (
<div> <Child items={this.state.items}/> </div>
); }}
class Child extends React.Component{ render() { return ({
this.props.items.map((i,index) => <div>{i}</div>
) }); }}
Daten von Parent zu Child über Props
class Parent extends React.Component{ … render() { return (
<div> <Child someAction={this.callBack.bind(this)}/> </div>
);}
callBack(){//Do something} }
class Child extends React.Component{ render() { return (
<div> <input type="button" onClick={this.props.someAction}/>
</div> ); }}
Callback Funktionen von Child zu Parent
Wie sieht die Architektur abseits der Komponenten aus?
(äquivalent Services, DI)
Redux
Component
Actions
Reducer
Reducer
Reducer
State
Middleware
(state, action) => state
Bekannte Konzepte Teilweise uneindeutiger Datenfluss
Neue Konzepte Eindeutiger Datenfluss
ABER
Es existiert ein Redux Binding für Angular 2
Kurzes Resümee
Was React (nicht) ist
• Reacts Hauptanspruch ist die Strukturierung der Anwendung
• React ist eine sehr gute Rendering-Bibliothek
• React ist keine Rich Client Platform
• React ist keine Komponenten Bibliothek
Was Angular (nicht) ist
• Angulars Hauptanspruch ist die Strukturierung der Anwendung
• Angular ist eine Rich Client Platform
• Angular ist keine Komponenten Bibliothek
Welche Unterschiede existieren?
• React setzt auf JSX
• Angular setzt auf Templates (Lernaufwand)
• Angular bietet Uni - und Bidirektionales Binding
• React nutzt render() wenn State / Props neu gesetzt wird
• React eher funktional, Angular eher OOP
Anwendungen gehen über den Komponentenansatz hinaus
AnwendungsentwicklungLifecycle Hooks für Komponenten
Backend-Anbindung Dependency Injection Access-Management
Formular-Handling & (Async)-Validation Accessibility
Security Controls Routing
i18n Mobile
Komplexes Focus Management UI Tests
Lifecycle Hooks für Komponenten
Backend-Anbindung
Dependency Injection
Access-Management
Formular-Handling & (Async)-Validation
Accessibility
KernfunktionDrittanbieterNicht vorhanden
Security
Controls
Routing
i18n
Mobile
Komplexes Focus Management
UI Tests
KernfunktionDrittanbieterNicht vorhanden
Beispiel Routing
Routing
Routing
Routing @ Angular
const contentRoutes:RouterConfig =[{
path:‘highlight',component:HighlightComponent},
{path:’catalogue',component:CatalogueComponent,]}
];
export const appRouterProviders =[provideRouter(routes)];
Routing deklarieren
@Component({ selector: 'content', template: `
<a routerLink="/highlight">Highlights</a> <a routerLink="/catalogue">Katalog</a>
<router-outlet></router-outlet>
` }) export class ContentComponent {}
Routing
Routing @ React via 3rd Party lib
https://github.com/ReactTraining/react-router
Routing deklarieren
render(( <Router history={browserHistory}> <Route path="/" component={App}> <Route path="about" component={About}/> <Route path="users" component={Users}> <Route path="/user/:userId" component={User}/> </Route> <Route path="*" component={NoMatch}/> </Route> </Router> ), document.getElementById('root'))
Routing nutzen
const Users = React.createClass({ render() { return (
<div> <Link to={`/user/${user.id}`}>{user.name}</Link>
</div> ) } })
= =Routing Routing
Kurzes Resümee
React (Stack) Angular 2
Ok, genug Funktionen - was ist mit Zukunftssicherheit?
Zukunftssicherheit
• Welche Aspekte sind wichtig?
• Stand im Produktlebenszyklus
• Strategie des Vendors
• Marktsituation
Produktlebenszyklus
Einführung
ReifeWachstum Degeneration
Hinweis
Man sollte bedenken, dass jede Third-Party Library wieder auf Ihr Zukunftssicherheit zu prüfen ist.
Wie setzt der Vendor die Bibliotheken ein
Wie setzt Google ein?
• Google Adwords (in Entwicklung)
• GreenTea (Googles internes CRM)
• Google Fiber (https://fiber.google.com/about/)
Wie setzt Facebook ein?
• in Facebook (z.B. Chat, Kommentare)
• WhatsApp Webapp
Release Politik /Versionierung
Release Strategie Angular
SemVer
http://angularjs.blogspot.de/2016/10/versioning-and-releasing-angular.html?m=1&utm_campaign=NG-Newsletter&utm_medium=email&utm_source=NG-Newsletter_169
angularjs.blogspot.de/2016/10/versioning-and-releasing-angular.html?m=1&utm_campaign=NG-Newsletter&utm_medium=email&utm_source=NG-Newsletter_169
Versioning React
https://facebook.github.io/react/blog/2016/02/19/new-versioning-scheme.html
SemVer seit 0.14.7. —> 15.0.0ohne expliziten Releasezyklus
Marktsituation
Freelancer auf Gulp
0
125
250
375
500
Freelancer auf GULP
442
2030
react angular2 angular
Projekte auf Gulp
0
12,5
25
37,5
50
Projekte auf Gulp
47
33
react angular2 angular
Community auf Stackoverflow
0
2250
4500
6750
9000
Stackoverflow created:1m
8.476
6.736
3.999
react angular2 angular
Kurzes Resümee
Resümee Marktsituation
• Beide Technologien ermöglichen die Entwicklung komplexer Anwendungen
• React ist eine Bibliothek
• Angular 2 ist ein Framework (RCP)
Resümee Marktsituation
• Versioning gleich
• Angular hat transparente Releasezyklen
• Marktsituation rund um Angular etwas besser
Welche Entscheidung haben wir getroffen?
Wie sind wir bei unserer Entscheidung vorgegangen?
Beide Technologien sind relevant und wir sollten uns
mit ihnen auskennen.
Wenn Greenfield Projekt, dann Angular
MERKE
Wer Webanwendungen baut muss lernen permanent zu lernen.
https://www.similartech.com/compare/angular-js-vs-react-js
Why Do People Hate Client-Side JavaScript?Everyone is different, and if you asked 100 different haters I’m
sure they would have 100 different flavors of Hatorade™.
https://webmasters.googleblog.com/2014/05/understanding-web-pages-better.html
export default class Counter extends Component { constructor(props) { super(props); }
render() { const { counter, increment, decrement, addTreatments } = this.props;
return ( <View style={{flex: 1, alignItems: 'center', justifyContent: 'center' }}> <Text>{counter}</Text> <TouchableOpacity onPress={decrement} style={styles.button}>
<Text>down</Text> </TouchableOpacity>
<TouchableOpacity onPress={addTreatments} style={styles.button}> <Text>Load</Text> </TouchableOpacity> </View> ); } }
React Native
@Component({ selector: 'list-test', template: ` <GridLayout rows="*"> <ListView [items]="items"> <template let-item="item"> <item-component [data]="item"></item-component> </template> </ListView> </GridLayout> ` }) export class ListTest {
items : Array<String>
constructor(private restClient : RestClient) { restClient.loadTreatments().subscribe(resp => console.log(resp)) //this.items =
} }
Nativescript
Recommended