ANGULAR 2 FOR REACT DEVELOPERS
Now that Angular 2 is in beta, the time has come for us to drop everything and learn something new, again. The good news is, like React and Angular 1.x, Angular 2 is here to stay for a while so it’s a good investment to become productive with this new framework. React has been on top of the world as of recently, for good reasons, it’s a fantastic approach to building modern web apps. This post is catered to those who are neck-deep in React and what to make an easy transition to Angular 2. This is angular 2 for react developers.
Bootstrapping
Both React and Angular 2 can be used with normal ES5, but most folks use JSX + ES2015 with React and with Angular 2 it’s also recommended to use TypeScript.
> TypeScript is ES2015 + Optional Types
None of those technologies can run natively in any browser, so we must have a build step to compile down to browser ready code. Webpack and/or Gulp are the popular choices for the bundling and building our application code. Once you have your build process, we can bootstrap our app. As far as bootstrapping our first component, things will obviously be different between the two frameworks. If you’re in a hurry and just wanna get started, check out our Angular 2 webpack starter on github.
React
npm install react react-dom core-js
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
import 'core-js' // polyfills
import React, {Component} from 'react'
import {render} from 'react-dom';
class App extends Component {
render() {
return (
<h1>hello world</h1>
);
}
}
render(<App />, document.findElementById('app'));
|
|
1
2
3
4
5
6
7
8
9
10
11
|
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
|
Angular 2
npm install --save angular2 zone.js es6-shim es6-promise es7-reflect-metadata
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
// polyfills
import 'es6-shim';
import 'es6-promise';
import 'es7-reflect-metadata/dist/browser';
import 'zone.js/lib/browser/zone-microtask';
import 'zone.js/lib/browser/long-stack-trace-zone';
// angular2 libs
import {Component} from 'angular2/core';
import {bootstrap} from 'angular2/platform/browser';
@Component({
selector: '#app',
template: `
<h1>hello world</h1>
`
})
class App {}
bootstrap(App);
|
|
1
2
3
4
5
6
7
8
9
10
11
|
<!DOCTYPE html>
<html lang="en">
<head>
</head>
<body>
<div id="app"></div>
<script src="bundle.js"></script>
</body>
</html>
|
Conceptually nothing has changed as far as the minimal code needed to bootstrap a simple hello world component. Angular 2 requires a list of polyfills to run in the desired configuration. Some of which are already in evergreen browsers. Let’s walk through some of the difference between the two files. With React we use a bit of OOP, object-oriented programming, with extends to mix our App class with Component class. With Angular 2 we use composition over inheritance with the Component decorator to statically read our metadata (selector and template) as well as map its life-cycle API to our App class. The API for Angular 2 is more decoupled from our application code and the framework itself. Although the use decorators in Angular 2 vs extending in react is different, they carry out the same goal of allowing us to use methods provided in the framework. The selector can be any valid css selector, including a tag name, so we can think of it as document.querySelector(selector) where document is the parent component and selector is our component. The template takes advantage of ES2015 multiline strings and not JSX.
Storing state
Modern web development is all about managing state of our applications. In this example we’re going to simplify state management by going over local state and not things like [insert some flux library] that has many different opinions on how to store state. We’re talking more about state local to a component and not application state.
React
|
1
2
3
4
5
6
7
8
9
10
|
class App extends Component {
state = {message: 'hello'}; // be sure to have proper plugin for babel
render() {
return (
<div>{this.state.message}</div>
);
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
|
@Component({
selector: '#app',
template: `
<div>{{ state.message }}</div>
`,
})
class App {
state = {message: 'hello'};
}
|
There really isn’t much of a difference here. This is because both React and Angular 2 rely on standards for initializing state. The one thing that did change is the template interpolation. React uses { } where angular sticks to its origin, using {{ }}. Note that there are many ways to initialize state with Angular 2, this method closely relates to React.
Event handlers and state change
With React using JSX and Angular 2 using HTML, there are some differences between the two when it comes to handling DOM events triggered from components.
React
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class App extends Component {
state = {count: 0}; // be sure to have proper plugin for babel
handleClick(e) {
this.setState({count: this.state.count + 1});
}
render() {
return (
{/* must bind context */}
<button onClick={this.handleClick.bind(this)}>count</button>
{this.state.count}
);
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Component({
selector: 'app',
template: `
<div>
<button (click)="handleClick($event)">+1</button>
{{ state.count }}
</div>
`,
})
class App {
state = {count: 0};
handleClick(e) {
this.state.count++;
}
}
|
While React has mapped props on our JSX components to DOM events, Angular 2 uses the DOM event itself. Lets walk through the syntax of how Angular 2 accomplishes that. The (click) is telling angular that we want to bind to the click event on the target element and run the following expression. Although it may look funny,this is valid HTML. It’s not 2003 anymore, so we don’t really check for “valid” HTML anyway. If you simply cannot bear to use this syntax, you can swap out (click) with on-click. This goes for all events, not just click. We now just make a call to our handler handleClick(). Notice we must invoke the callback, unlike React which replies on a reference to the callback. This is because React is registering our handler as the callback for the event while Angular 2 invokes an expression with our component as the context. Making a call to setState() in react triggers an update for our component and if the state has changed, the component renders again. The same happens with Angular 2 except you can change the state directly since the framework is watching the component tree for any changes to its properties.
Data binding with unidirectional data flow
Unidirectional-way data flow makes it simpler for one to reason about application state, but sometimes you need two-way flow. This can’t be more true than when dealing with forms and user input or any other stateful component out there.
React
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class App extends Component {
constructor() {
super();
this.state = {text: ''};
}
onChange(e) {
this.setState({text: e.target.value});
}
render() {
return (
<input onChange={this.onChange.bind(this) value={this.state.value}}
{this.state.text}
);
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
@Component({
selector: 'app',
template: `
<div>
<input (change)="onChange($event)" [value]="state.text" >
{{state.text}}
</div>
`,
})
class App {
state = {text: ''};
onChange(e) {
this.state.text = e.target.value;
}
}
|
This basic approach of handling input changes isn’t too much different between the two frameworks. Both bind to events and then change state based of the input’s value. The main big difference is what event they are binding to. Angular 2 binds allows you to bind to any event emitted from the component such as native or custom events. With Angular 2 we must pass in the $event variable. Like Angular 1.x, the $event variable is created internally. React binds to the onChange event which internally binds to keyup. Angular 2 brings back ngModel which makes two-bindings even easier. We can also refactor our Angular 2 example to take more advantage of local variables in our templates. We can think of local variables as variables that live locally in our render function.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
@Component({
selector: 'app',
template: `
<div>
<input (change)="state.text = $event.target.value" [value]="state.text" >
{{state.text}}
</div>
`,
})
class App {
state = {text: ''};
}
|
Refs
With the release of React 0.14, we can assign refs using a new approach. Let’s compare how to use refs with both frameworks.
React
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
class App extends Component {
changeColor() {
this.box.classList.add('yellow');
}
render() {
return (
<div<
<button
onClick={this.changeColor.bind(this)}
ref={node => this.box = node}>
change
</button>
<div className="box"></div>
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
@Component({
selector: 'app',
template: `
<div>
<button (click)="changeColor(box)">change</button>
<div class="box" #box></div>
</div>
`,
})
class App {
changeColor(box) {
box.classList.add('yellow')
}
}
|
With React, we get access to the raw DOM node and assign it to a property on the component itself. With angular 2, we use the # followed by a variable name on the element we want to reference. This reference is local to the template so we must pass it in as an argument to get access to it. We can reason about why the Angular Team choose #. Including an id to an element gives us access to that element globally in our browser. We can get a reference to our div with window.myElement (if you didn’t know about this then you should try it out). Like React, the ref is also a raw DOM node.
Component composition
Both frameworks take the component approach to building web apps so being able to compose components to create more components is essential. Let’s take a look.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
class Sidebar extends Component {
render() {
return (
<div className="sidebar">
<h1>Side bar</h1>
</div>
);
}
}
class App extends Component {
render() {
return (
<div>
<Sidebar />
</div>
);
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
@Component({
selector: 'sidebar',
template: `
<div class="sidebar">
<h1>Side bar</h1>
</div>
`
})
class Sidebar {}
@Component({
selector: 'app',
directives: [
Sidebar // we must declare which components/directives are in our template since we don't have jsx do it for us
],
template: `
<div>
<sidebar></sidebar>
</div>
`,
})
class App {}
|
With Angular 2 we make another component using the @Component decorator just like with App. Defining a template the same way also. We then must add the new component to a list of directives to the container component that will use the new component in its template. This is because unlike JSX which just compiles down to function calls, Angular 2 templates need to be told what which components are used in their templates because we’re just using strings to write the templates. This comes in handy when testing as well since we can mock other components. Also, we can self close tags in react like <Sidebar />. We can’t do this yet in Angular 2 but soon.
Props
The concept of stateless components keeps things flexible and predictable. By passing down state from top-level components to child components we only need to worry about inputs of a stateless component through props on the components.
React
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
class Sidebar extends React.Component {
render() {
return (
<div className="sidebar">
<h1>{this.props.title}</h1>
</div>
);
}
}
class App extends React.Component {
constructor(){
super();
this.state = {title: 'Sidebar'};
}
render() {
return (
<div>
<Sidebar title={this.state.title} />
</div>
);
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
|
import { Component, Input } from 'angular2/core';
@Component({
selector: 'sidebar',
template: `
<div class="sidebar">
<h1>{{ title }}</h1>
</div>
`
})
class Sidebar {
@Input() title:string;
}
@Component({
selector: 'app',
directives: [
Sidebar
],
template: `
<div>
<sidebar [title]="state.title"></sidebar>
</div>
`,
})
class App {
state = {
title: 'Side bar'
}
}
|
First thing to note here is that we must import the @Input() decorator. Unlike @Component() that is decorating our class, @Input() is will be decorating a property of our class so its positioning inside the class next to or above the property is important. We’re also using typescript typing here to declare a property named title of the string type. We can now refer to this property in the template as {{ title }}. In the container component, we can pass in state using the bracket syntax on the component we want to pass state into, [title]="state.title".
Think of this as accessing properties on a JavaScript object using bracket notation. Where the object in this case is the actual component in the template instead.
|
1
2
3
4
|
var sidebar = new Sidebar();
sidebar[title] = state.title;
|
Dynamic elements
With JSX, we can use JS in your templates to iterate over collections and output valid JSX for rendering. Angular 2 takes an approach closer to angular 1.x to handle this.
> It’s worth noting that Angular 2 does support JSX but is looking for someone in the community to work with them on it.
React
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
|
class Sidebar extends Component {
render() {
return (
<div className="sidebar">
<h1>{this.props.title}</h1>
<ul>
{this.props.items.map(item => <li>{item}</li>})}
</ul>
</div>
);
}
}
class App extends Component {
constructor(){
super();
this.state = {
title: 'Sidebar',
navItems: ['home', 'profile', 'settings']
};
}
render() {
return (
<div>
<Sidebar
title={this.state.title}
items={this.state.navItems}
/>
</div>
);
}
}
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
@Component({
selector: 'sidebar',
template: `
<div class="sidebar">
<h1>{{ title }}</h1>
<ul>
<li *ngFor="#item of items">{{ item }}</li>
</ul>
</div>
`
})
class Sidebar {
@Input() title:string;
@Input() items:string[];
}
@Component({
selector: 'app',
directives: [
Sidebar
],
template: `
<div>
<sidebar
[title]="state.title"
[items]="state.items"
></sidebar>
</div>
`,
})
class App {
state = {
title: 'Side bar',
items: ['home', 'profile', 'settings']
}
}
|
Like angular 1.x, angular 2 has a directive we can use to repeat over data and create elements. The ngFor directive is similar to its older sister, ng-repeat. Because angular 2 uses <template> to clone element for performance reasons they, they created a shorthand to expand micro-syntax with *. That’s why we use *ngFor. Just like when using refs, we use the # followed by a variable name to create a local variable in the template. Like ES2015 iterators, we are using a for of loop to iterate over the collection, assigning the current element to the local variable we created.
Angular 2
|
1
2
3
4
5
6
7
8
9
10
|
<div class="sidebar">
<h1>{{title}}</h1>
<ul>
<template ngFor #item [ngForOf]="items">
<li>{{ item }}</li>
</template>
</ul>
</div>
|
Styles
There are so many ways to add styles to our components. With build tools like webpack, that lists grows longer and longer. Having css encapsulation is an important part of creating flexible components. React doest offer a built in solution so the community stepped up with CSS Modules. These styles are scoped the component using unique classnames to avoid collision. Angular has the same feature baked in.
React
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
import CSSModules from 'react-css-modules';
import styles from './styles.css'; // string
import React, {Component} from 'react';
class App extends Component {
render() {
return (
<div styleName='app'> {/* creates app__2gft5 */}
<div styleName='actions'> {/* creates app__actions__74tr */}
<button styleName='button'>click</button>
</div>
</div>
);
}
}
const Root = CSSModules(App, style);
render(<Root/>, document.findElementById('app));
|
Angular 2
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
@Component({
selector: 'app',
styles: [`
.app {
}
.app.actions {
}
.app.actions.button {
}
`],
template: `
<div class="app">
<div class="actions">
<button class="button">click</button>
</div>
</div>
`,
})
class App {}
bootstrap(App);
|
Using the styles array on the Component decorator, we can attach styles to the target component. Like with CSSModules, the class names are name spaced to avoid collision. Because the styles are just a string, we can do things like interpolation to make the styles dynamic.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
const APP_CLASS = 'app';
@Component({
selector: 'app',
styles: [`
.${APP_CLASS} {
}
.${APP_CLASS}.actions {
}
.${APP_CLASS}.actions.button {
}
`],
template: `
<div class="${APP_CLASS}">
<div class="actions">
<button class="button">click</button>
</div>
</div>
`,
})
class App {}
bootstrap(App);
|
Who uses regular css these days, with the the help of build tools like webpack, we can use preprocessors as well.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
import styles from './style.less';
@Component({
selector: 'app',
styles: [styles],
template: `
<div class="app">
<div class="actions">
<button class="button">click</button>
</div>
</div>
`,
})
class App {}
|
If you don’t like the computed dynamic class names that angular creates for your component’s elements, then you have the option to change that.
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
import { Component, Input, ViewEncapsulation} from 'angular2/core';
import styles from './style.less';
@Component({
encapsulation: ViewEncapsulation.Native,
selector: 'app',
styles: [styles],
template: `
<div class="app">
<div class="actions">
<button class="button">click</button>
</div>
</div>
`,
})
class App {}
|
The encapsulation property on the Component decorator allows us to change how our styles scoping behaves. First we need to import ViewEncapsulation. There are three values that we could use. The default is ViewEncapsulation.Emulated which outputs the funky namespaces class names. ViewEncapsulations.Native uses the shadow DOM. ViewEncapsulation.None scoping of the targets components styles.
Angular 2’s public API is pretty solid and won’t undergo any major changes soon. With the current syntax, the approach to building web apps is not much different than what React does right now. They both accomplish the same thing. Angular 2 provides so much more as well. We didn’t get to talk about life cycle events, actions, and advanced state management and how it relates to React. Stay tuned for that. In the mean time, check out our Angular 2 webapack starter on github for the fastest and best way to get started with angular 2 now.
原文地址:https://angularclass.com/angular-2-for-react-developers/
ANGULAR 2 FOR REACT DEVELOPERS的更多相关文章
- angular开发者吐槽react+redux的复杂:“一个demo证明你的开发效率低下”
曾经看到一篇文章,写的是jquery开发者吐槽angular的复杂.作为一个angular开发者,我来吐槽一下react+redux的复杂. 例子 为了让大家看得舒服,我用最简单的一个demo来展示r ...
- [译] Angular 2 VS. React: 血色将至
Angular 2 VS. React: 血色将至 原文链接:https://medium.com/@housecor/angular-2-versus-react-there-will-be-blo ...
- 如何选择前端框架:ANGULAR VS EMBER VS REACT
最近一段时间是令前端工程师们非常兴奋的时期,因为三大Web框架陆续发布新版本,让我们见识到了更强大的Web框架.Ember2.0在2个月之前已经发布,从1.0升级到2.0非常简单.几周之前React发 ...
- React vs Angular 2: 冰与火之歌
黄玄 · 3 个月前 本文译自 Angular 2 versus React: There Will Be Blood ,其实之前有人翻译过,但是翻得水平有一点不忍直视,我们不希望浪费这篇好文章. 本 ...
- Angular React 和 Vue的比较
Angular(1&2),React,Vue对比 一 数据流 数据绑定 Angular 使用双向绑定即:界面的操作能实时反映到数据,数据的变更能实时展现到界面. 实现原理: $scope变量中 ...
- vue入门 vue与react和Angular的关系和区别
一.为什么学习vue.js vue.js兼具angular.js和react的优点,并且剔除了他们的缺点 官网:http://cn.vuejs.org/ 手册:http://cn.vuejs.org/ ...
- 我从Angular 2转向Vue.js, 也没有选择React
译者按: 通过使用Angular的经历,作者已经完全转为Vue粉了!我们Fundebug目前还是用AngularJS 1,坦白说,学习曲线蛮陡的. 原文: Why we moved from Angu ...
- Angular、React.js 和Node.js到底选谁?
为了工作,程序员选择正确的框架和库来构建应用程序是至关重要的,这也就是为什么Angular和React之间有着太多的争议.Node.js的出现,让这场战争变得更加复杂,虽然有选择权通常是一件很棒的事情 ...
- 【转】前端框架天下三分:Angular React 和 Vue的比较
前端框架天下三分:Angular React 和 Vue的比较 原文链接:http://blog.csdn.net/haoshidai/article/details/52346865 前端这几年的技 ...
随机推荐
- 关于JFace中的向导式对话框(WizardDialog类)
向导式对话框是一种非常友好的界面,它能够引导用户一步步的输入信息.Eclipse的"新建项目",就是这样的向导式对话框. 在Eclipse中向导式对话框的开发是很简单的,它由Wiz ...
- 程序员,一起玩转GitHub版本控制,超简单入门教程 干货2
本GitHub教程旨在能够帮助大家快速入门学习使用GitHub,进行版本控制.帮助大家摆脱命令行工具,简单快速的使用GitHub. 做全栈攻城狮-写代码也要读书,爱全栈,更爱生活. 更多原创教程请关注 ...
- C#下解决DrawImage画出来的Image变大了的问题
如: private Image image= Resources.image1;//假设image1这张资源图是360×600这么大 private Graphics graphics; graph ...
- hibernate--could not initialize proxy - no Session--懒加载问题
今天在学习hibernate时,出现了以下错误: 错误分析: 如果我们取单个对象可以用get方法没有问题:但是如果我们取的的对象还有关联对象时用get就有问题,因为它不会把关联的对象取出来 参考博客: ...
- Webbrowers控件的小技巧
我最近接触webbrowers 这个控件比较多,感觉用起来比较顺手吧.可以做很多操作. 貌似很多网络模拟有时候都内置这个控件或者类似的控件,但这样子速度就不能跟那些单纯用API 构建数据包比了. 我一 ...
- unity3d环境安装指南: Unity 4.5.5 + Visual Studio 2010
1. UnitySetup-4.5.5.exe 官网下载最新版本4.X 安装exe文件 2. Unity 4.x Pro Patch.exe 复制exe到安装目录下 C:\Program Files ...
- JavaScript学习笔记(1)——JavaScript简介
JavaScript一种解释性脚本语言,是一种动态类型.弱类型.基于原型的语言,内置支持类型.它的解释器被称为JavaScript引擎,该引擎为浏览器的一部分.JavaScript最早是用 ...
- Java教程——int与Integer的区别
首先说一下int和Integer的区别: int 是基本数据类型,Integer是int的包装类.注意:后者的类型是"类".例如使用泛型,List<Integer> n ...
- SpringInAction读书笔记--第2章装配Bean
实现一个业务需要多个组件相互协作,创建组件之间关联关系的传统方法通常会导致结构复杂的代码,这些代码很难被复用和单元测试.在Spring中,对象不需要自己寻找或创建与其所关联的其它对象,Spring容器 ...
- 每天一个linux命令(1):more命令
more命令,功能类似 cat ,cat命令是整个文件的内容从上到下显示在屏幕上. more会以一页一页的显示方便使用者逐页阅读,而最基本的指令就是按空白键(space)就往下一页显示,按 b 键就会 ...