模組引用
在ES5裡,如果使用CommonJS標準,引入React包基本通過require進行,代碼類似這樣:
//ES5
var React = require("react-native");
var {
Image,
Text,
View,
} = React; //引用不同的React Native組件
在ES6裡,import寫法更為標準
//ES6
import React, {
Image,
Text,
View,
} from 'react-native';
注意React Native 0.12之後的版本才支援import文法
匯出單個類別模組
在ES5裡,要匯出一個類給別的模組用,一般通過module.exports來匯出
//ES5
var MyComponent = React.createClass({
...
});
module.exports = MyComponent;
在ES6裡,通常用export default來實現相同的功能:
//ES6
export default class MyComponent extends React.Component{
...
}
引用類的時候ES5和ES6也有區別:
//ES5
var MyComponent = require('./MyComponent.js');
//ES6
import MyComponent from './MyComponent.js';
定義組件
在ES5裡,通常通過React.createClass來定義一個組件類,像這樣:
//ES5
var Todo = React.createClass({
render: function() {
return (
<view>
<text></text>
</view>
);
},
});
在ES6裡,我們通過定義一個繼承自React.Component的class來定義一個組件類,像這樣:
//ES6
class Todo extends React.Component {
render() {
return (
<view>
<text></text>
</view>
);
}
}
定義組件的方法
從上面的例子裡可以看到,給組件定義方法不再用 名字: function()的寫法,而是直接用名字(),在方法的最後也不能有逗號了。
//ES5
var Todo = React.createClass({
componentWillMount: function(){
},
render: function() {
return (
<view></view>
);
},
});
//ES6
class Todo extends React.Component {
componentWillMount() {
}
render() {
return (
<view></view>
);
}
}
定義組件的屬性類型和預設屬性
在ES5裡,屬性類型和預設屬性分別通過propTypes成員和getDefaultProps方法來實現
//ES5
var Video = React.createClass({
getDefaultProps: function() {
return {
autoPlay: false,
maxLoops: 10,
};
},
propTypes: {
autoPlay: React.PropTypes.bool.isRequired,
maxLoops: React.PropTypes.number.isRequired,
posterFrameSrc: React.PropTypes.string.isRequired,
videoSrc: React.PropTypes.string.isRequired,
},
render: function() {
return (
<view>
);
},
});
</view>
在ES6裡,可以統一使用static成員來實現
//ES6
class Video extends React.Component {
static defaultProps = {
autoPlay: false,
maxLoops: 10,
}
static propTypes = {
autoPlay: React.PropTypes.bool.isRequired,
maxLoops: React.PropTypes.number.isRequired,
posterFrameSrc: React.PropTypes.string.isRequired,
videoSrc: React.PropTypes.string.isRequired,
}
render() {
return (
<view>
);
}
}
</view>
注意: 對React開發人員而言,static成員在IE10及之前版本不能被繼承,而在IE11和其它瀏覽器上可以,這有時候會帶來一些問題。React Native開發人員可以不用擔心這個問題。
初始化state
ES5:
//ES5
var Video = React.createClass({
getInitialState: function() {
return {
loopsRemaining: this.props.maxLoops,
};
},
})
6可以這樣實現:
//ES6
class Video extends React.Component {
state = {
loopsRemaining: this.props.maxLoops,
}
}
ES6也可以在建構函式中初始化:
//ES6
class Video extends React.Component {
constructor(props){
super(props);
this.state = {
loopsRemaining: this.props.maxLoops,
};
}
}
把方法作為回調提供
ES5中React.createClass會把所有的方法都bind一遍,這樣可以提交到任意的地方作為回呼函數,而this不會變化。但官方現在逐步認為這反而是不標準、不易理解的。
//ES5
var PostInfo = React.createClass({
handleOptionsButtonClick: function(e) {
// Here, 'this' refers to the component instance.
this.setState({showOptionsModal: true});
},
render: function(){
return (
<touchablehighlight onpress="{this.handleOptionsButtonClick}">
<text>{this.props.label}</text>
</touchablehighlight>
)
},
});
ES6中,需要通過bind來綁定this引用,或者使用箭頭函數(它會綁定當前scope的this引用)來調用
//ES6
class PostInfo extends React.Component
{
handleOptionsButtonClick(e){
this.setState({showOptionsModal: true});
}
render(){
return (
<touchablehighlight onpress="{this.handleOptionsButtonClick.bind(this)}">this.handleOptionsButtonClick(e)}
>
<text>{this.props.label}</text>
</touchablehighlight>
)
},
}
箭頭函數實際上是在這裡定義了一個臨時的函數,箭頭函數的箭頭=>之前是一個空括弧、單個的參數名、或用括弧括起的多個參數名,而箭頭之後可以是一個運算式(作為函數的傳回值),或者是用花括弧括起的函數體(需要自行通過return來傳回值,否則返回的是undefined)。
// 箭頭函數的例子
()=>1
v=>v+1
(a,b)=>a+b
()=>{
alert("foo");
}
e=>{
if (e == 0){
return 0;
}
return 1000/e;
}
需要注意的是,不論是bind還是箭頭函數,每次被執行都返回的是一個新的函數引用,因此如果你還需要函數的引用去做一些別的事情(譬如卸載監聽器),那麼你必須自己儲存這個引用
// 錯誤的做法
class PauseMenu extends React.Component{
componentWillMount(){
AppStateIOS.addEventListener('change', this.onAppPaused.bind(this));
}
componentDidUnmount(){
AppStateIOS.removeEventListener('change', this.onAppPaused.bind(this));
}
onAppPaused(event){
}
}
// 正確的做法
class PauseMenu extends React.Component{
constructor(props){
super(props);
this._onAppPaused = this.onAppPaused.bind(this);
}
componentWillMount(){
AppStateIOS.addEventListener('change', this._onAppPaused);
}
componentDidUnmount(){
AppStateIOS.removeEventListener('change', this._onAppPaused);
}
onAppPaused(event){
}
}
從這篇文章中,還可以學到一種心的做法:
// 正確的做法
class PauseMenu extends React.Component{
componentWillMount(){
AppStateIOS.addEventListener('change', this.onAppPaused);
}
componentDidUnmount(){
AppStateIOS.removeEventListener('change', this.onAppPaused);
}
onAppPaused = (event) => {
//把方法直接作為一個arrow function的屬性來定義,初始化的時候就綁定好了this指標
}
}
Mixins
ES5中,經常使用mixin來為類添加一些新的方法,譬如PureRenderMixin,
var PureRenderMixin = require('react-addons-pure-render-mixin');
React.createClass({
mixins: [PureRenderMixin],
render: function() {
return <div classname="{this.props.className}">foo</div>;
}
});
官方推薦開發人員在ES6中,儘快放棄Mixin的編寫方式,用新的編碼方式:
//Enhance.js
import { Component } from "React";
export var Enhance = ComposedComponent => class extends Component {
constructor() {
this.state = { data: null };
}
componentDidMount() {
this.setState({ data: 'Hello' });
}
render() {
return <composedcomponent {...this.props}="" data="{this.state.data}">;
}
};
//HigherOrderComponent.js
import { Enhance } from "./Enhance";
class MyComponent {
render() {
if (!this.data) return <div>Waiting...</div>;
return <div>{this.data}</div>;
}
}
export default Enhance(MyComponent); // Enhanced component
</composedcomponent>
用一個“增強函數”,來某個類增加一些方法,並且返回一個新類,這無疑能實現mixin所實現的大部分需求。
ES6+帶來的其它好處
結合使用ES6+的解構和屬性延展,我們給孩子傳遞一批屬性更為方便了。這個例子把className以外的所有屬性傳遞給div標籤:
class AutoloadingPostsGrid extends React.Component {
render() {
var {
className,
...others, // contains all properties of this.props except for className
} = this.props;
return (
<div classname="{className}">
<postsgrid {...others}="">
<button onclick="{this.handleLoadMoreClick}">Load more</button>
</postsgrid></div>
);
}
}
下面這種寫法,則是傳遞所有屬性的同時,用覆蓋新的className值:
<div {...this.props}="" classname="override">
…
</div>
這個例子則相反,如果屬性中沒有包含className,則提供預設的值,而如果屬性中已經包含了,則使用屬性中的值
<div classname="base" {...this.props}="">
…
</div>
{ Comments on this entry are closed }
Git基礎命令整理
by WEB全棧工程師 on 2015 年 04 月 04 日
安裝Git
下載 git OSX 版
下載 git Windows 版
下載 git Linux 版
建立新倉庫
建立新檔案夾,開啟,然後執行
git init
以建立新的 git 倉庫。
檢出倉庫
執行如下命令以建立一個本地倉庫的複製版本:
git clone /path/to/repository
如果是遠端伺服器上的倉庫,你的命令會是這個樣子:
git clone username@host:/path/to/repository
工作流程
你的本地倉庫由 git 維護的三棵“樹”組成。第一個是你的 工作目錄,它持有實際檔案;第二個是 暫存區(Index),它像個快取區域,臨時儲存你的改動;最後是 HEAD,它指向你最後一次提交的結果。
添加和提交
你可以提出更改(把它們添加到暫存區),使用如下命令:
git add
git add *
這是 git 基本工作流程的第一步;使用如下命令以實際提交改動:
git commit -m "代碼提交資訊"
現在,你的改動已經提交到了 HEAD,但是還沒到你的遠端倉庫。
查看Git的狀態,輸入
git status
git log
推送改動
你的改動現在已經在本地倉庫的 HEAD 中了。執行如下命令以將這些改動提交到遠端倉庫:
git push origin master
可以把 master 換成你想要推送的任何分支。
如果你還沒有複製現有倉庫,並欲將你的倉庫串連到某個遠程伺服器,你可以使用如下命令添加:
git remote add origin
如此你就能夠將你的改動推送到所添加的伺服器上去了。
分支
分支是用來將特性開發絕緣開來的。在你建立倉庫的時候,master 是“預設的”分支。在其他分支上進行開發,完成後再將它們合并到主分支上。
建立一個叫做“magentonotes_dev”的分支,並切換過去:
git checkout -b magentonotes_dev
切換回主分支:
git checkout master
再把建立的分支刪掉:
git branch -d magentonotes_dev
除非你將分支推送到遠端倉庫,不然該分支就是 不為他人所見的:
git push origin
更新與合并
要更新你的本地倉庫至最新改動,執行:
git pull
以在你的工作目錄中 擷取(fetch) 並 合并(merge) 遠端的改動。
要合并其他分支到你的當前分支(例如 master),執行:
git merge
在這兩種情況下,git 都會嘗試去自動合并改動。遺憾的是,這可能並非每次都成功,並可能出現衝突(conflicts)。 這時候就需要你修改這些檔案來手動合并這些衝突(conflicts)。改完之後,你需要執行如下命令以將它們標記為合并成功:
git add
在合并改動之前,你可以使用如下命令預覽差異:
git diff
git merge --no-ff -m "merge with no-ff" dev #以普通模式合并分支
git stash #儲存工作現場
git stash list #查看工作現場
git stash apply #恢複工作現場,但工作現場的內容並不刪除
git stash drop #刪除工作現場
git stash pop #這條命令 恢複現場,並刪除現場
git stash apply stash@{0} #恢複指定的現場
多人協作
git remote #查看遠程分支
git remote -V #查看更詳細的遠程分支資訊
git push origin master #把master分支推送到遠程
標籤
為軟體發布建立標籤是推薦的。這個概念早已存在,在 SVN 中也有。你可以執行如下命令建立一個叫做 1.0.0 的標籤:
git tag 1.0.0 1b2ffd63ff
git tag -d #刪除標籤
git tag -a -m "commit info..." #指定標籤的資訊
git tag -s -m "commit info..." #使用PGP簽名標籤
git push origin #推送本地的一個標籤
git push origin --tags #可以推送全部未推送的本地標籤
git push origin :refs/tags/ #刪除一個遠端標籤
1b2e1d63ff 是你想要標記的提交 ID 的前 10 位字元。可以使用下列命令擷取提交 ID:
git log
你也可以使用少一點的提交 ID 前幾位,只要它的指向具有唯一性。
替換本地改動
假如你操作失誤(當然,這最好永遠不要發生),你可以使用如下命令替換掉本地改動:
git checkout --
此命令會使用 HEAD 中的最新內容替換掉你的工作目錄中的檔案。已添加到暫存區的改動以及新檔案都不會受到影響。
假如你想丟棄你在本地的所有改動與提交,可以到伺服器上擷取最新的版本曆史,並將你本地主分支指向它:
git fetch origin
git reset --hard origin/master
git reset --hard HEAD^ #復原上一個版本
git reset --hard commit_id #復原指定ID的版本
git log #查看提交曆史
git log --pretty=online #顯示一行資訊的提交曆史
git reflog #查看曆史命令
git diff HEAD -- 檔案名稱 #查看檔案差異
git checkout -- 檔案名稱 #撤銷修改,檔案修改後還沒有被放到暫存區,撤銷修改就回到和版本庫一模一樣的狀態;
實用Tips
內建的圖形化 git:
gitk
彩色的 git 輸出:
git config color.ui true
顯示記錄時,每個提交的資訊只顯示一行:
git config format.pretty oneline
互動式添加檔案到暫存區:
git add -i
忽略特殊檔案:
在Git工作區的根目錄下建立一個特殊的.gitignore檔案,然後把要忽略的檔案名稱填進去,Git就會自動忽略這些檔案。
配置模板:
https://github.com/github/gitignore
配置別名:
每個倉庫的Git設定檔都放在.git/config檔案中,每個倉庫的Git設定檔都放在.git/config檔案中。
git config --global alias.st status
git config --global alias.co checkout
git config --global alias.ci commit
git config --global alias.br branch
git config --global alias.unstage 'reset HEAD'
git config --global alias.last 'log -1'
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
git config --global --unset alias.st #取消別名
串連非22連接埠ssh的git伺服器
1
git clone ssh://git@hostname:port/local/xxx.git