『壹』 react中,import導入文件怎麼理解,與css中的import有區別嗎
說說React
一個組件,有自己的結構,有自己的邏輯,有自己的樣式,會依賴一些資源,會依賴某些其他組件。比如日常寫一個組件,比較常規的方式:
- 通過前端模板引擎定義結構
- js文件中寫自己的邏輯
- CSS中寫組件的樣式
- 通過RequireJS、SeaJS這樣的庫來解決模塊之間的相互依賴,
那麼在React中是什麼樣子呢?
結構和邏輯
在React的世界裡,結構和邏輯交由JSX文件組織,React將模板內嵌到邏輯內部,實現了一個JS代碼和HTML混合的JSX。
結構
在JSX文件中,可以直接通過 React.createClass 來定義組件:
var CustomComponent = React.creatClass({
render: function(){
return (<div className="custom-component"></div>);
}
});
通過這種方式可以很方便的定義一個組件,組件的結構定義在render函數中,但這並不是簡單的模板引擎,我們可以通過js方便、直觀的操控組件結構,比如我想給組件增加幾個節點:
var CustomComponent = React.creatClass({
render: function(){
var $nodes = ['h','e','l','l','o'].map(function(str){
return (<span>{str}</span>);
});
return (<div className="custom-component">{$nodes}</div>);
}
});
通過這種方式,React使得組件擁有靈活的結構。那麼React又是如何處理邏輯的呢?
邏輯
寫過前端組件的人都知道,組件通常首先需要相應自身DOM事件,做一些處理。必要時候還需要暴露一些外部介面,那麼React組件要怎麼做到這兩點呢?
事件響應
比如我有個按鈕組件,點擊之後需要做一些處理邏輯,那麼React組件大致上長這樣:
var ButtonComponent = React.createClass({
render: function(){
return (<button>屠龍寶刀,點擊就送</button>);
}
});
點擊按鈕應當觸發相應地邏輯,一種比較直觀的方式就是給button綁定一個 onclick 事件,裡面就是需要執行的邏輯了:
function getDragonKillingSword() {
//送寶刀
}
var ButtonComponent = React.createClass({
render: function(){
return (<button onclick="getDragonKillingSword()">屠龍寶刀,點擊就送</button>);
}
});
但事實上 getDragonKillingSword() 的邏輯屬於組件內部行為,顯然應當包裝在組件內部,於是在React中就可以這么寫:
var ButtonComponent = React.createClass({
getDragonKillingSword: function(){
//送寶刀
},
render: function(){
return (<button onClick={this.getDragonKillingSword}>屠龍寶刀,點擊就送</button>);
}
});
這樣就實現內部事件的響應了,那如果需要暴露介面怎麼辦呢?
暴露介面
事實上現在 getDragonKillingSword 已經是一個介面了,如果有一個父組件,想要調用這個介面怎麼辦呢?
父組件大概長這樣:
var ImDaddyComponent = React.createClass({
render: function(){
return (
<div>
//其他組件
<ButtonComponent />
//其他組件
</div>
);
}
});
那麼如果想手動調用組件的方法,首先在ButtonComponent上設置一個 ref="" 屬性來標記一下,比如這里把子組件設置成 <ButtonComponent ref="getSwordButton"/> ,那麼在父組件的邏輯里,就可以在父組件自己的方法中通過這種方式來調用介面方法:
this.refs.getSwordButton.getDragonKillingSword();
看起來屌屌噠~那麼問題又來了,父組件希望自己能夠按鈕點擊時調用的方法,那該怎麼辦呢?
配置參數
父組件可以直接將需要執行的函數傳遞給子組件:
<ButtonComponent clickCallback={this.getSwordButtonClickCallback}/>
然後在子組件中調用父組件方法:
var ButtonComponent = React.createClass({
render: function(){
return (<button onClick={this.props.clickCallback}>屠龍寶刀,點擊就送</button>);
}
});
子組件通過 this.props 能夠獲取在父組件創建子組件時傳入的任何參數,因此 this.props 也常被當做配置參數來使用
屠龍寶刀每個人只能領取一把,按鈕點擊一下就應該灰掉,應當在子組件中增加一個是否點擊過的狀態,這又應當處理呢?
組件狀態
在React中,每個組件都有自己的狀態,可以在自身的方法中通過 this.state 取到,而初始狀態則通過 getInitialState() 方法來定義,比如這個屠龍寶刀按鈕組件,它的初始狀態應該是沒有點擊過,所以 getInitialState 方法裡面應當定義初始狀態 clicked: false 。而在點擊執行的方法中,應當修改這個狀態值為 click: true :
var ButtonComponent = React.createClass({
getInitialState: function(){
//確定初始狀態
return {
clicked: false
};
},
getDragonKillingSword: function(){
//送寶刀
//修改點擊狀態
this.setState({
clicked: true
});
},
render: function(){
return (<button onClick={this.getDragonKillingSword}>屠龍寶刀,點擊就送</button>);
}
});
這樣點擊狀態的維護就完成了,那麼render函數中也應當根據狀態來維護節點的樣式,比如這里將按鈕設置為 disabled ,那麼render函數就要添加相應的判斷邏輯:
render: function(){
var clicked = this.state.clicked;
if(clicked)
return (<button disabled="disabled" onClick={this.getDragonKillingSword}>屠龍寶刀,點擊就送</button>);
else
return (<button onClick={this.getDragonKillingSword}>屠龍寶刀,點擊就送</button>);
}
小節
這里簡單介紹了通過JSX來管理組件的結構和邏輯,事實上React給組件還定義了很多方法,以及組件自身的生命周期,這些都使得組件的邏輯處理更加強大
資源載入
CSS文件定義了組件的樣式,現在的模塊載入器通常都能夠載入CSS文件,如果不能一般也提供了相應的插件。事實上CSS、圖片可以看做是一種資源,因為載入過來後一般不需要做什麼處理。
React對這一方面並沒有做特別的處理,雖然它提供了Inline
Style的方式把CSS寫在JSX裡面,但估計沒有多少人會去嘗試,畢竟現在CSS樣式已經不再只是簡單的CSS文件了,通常都會去用Less、
Sass等預處理,然後再用像postcss、myth、autoprefixer、cssmin等等後處理。資源載入一般也就簡單粗暴地使用模塊載入器
完成了
組件依賴
組件依賴的處理一般分為兩個部分:組件載入和組件使用
組件載入
React沒有提供相關的組件載入方法,依舊需要通過 <script> 標簽引入,或者使用模塊載入器載入組件的JSX和資源文件。
組件使用
如果細心,就會發現其實之前已經有使用的例子了,要想在一個組件中使用另外一個組件,比如在 ParentComponent 中使用 ChildComponent ,就只需要在 ParentComponent 的 render() 方法中寫上 <ChildComponent /> 就行了,必要的時候還可以傳些參數。
疑問
到這里就會發現一個問題,React除了只處理了結構和邏輯,資源也不管,依賴也不管。是的,React將近兩萬行代碼,連個模塊載入器都沒有提供,更與Angularjs,jQuery等不同的是,他還不帶啥腳手架…沒有Ajax庫,沒有Promise庫,要啥啥沒有…
虛擬DOM
那它為啥這么大?因為它實現了一個虛擬DOM(Virtual DOM)。虛擬DOM是干什麼的?這就要從瀏覽器本身講起
如我們所知,在瀏覽器渲染網頁的過程中,載入到HTML文檔後,會將文檔解析並構建DOM樹,然後將其與解析CSS生成的CSSOM樹一起結合產
生愛的結晶——RenderObject樹,然後將RenderObject樹渲染成頁面(當然中間可能會有一些優化,比如RenderLayer樹)。
這些過程都存在與渲染引擎之中,渲染引擎在瀏覽器中是於JavaScript引擎(JavaScriptCore也好V8也好)分離開的,但為了方便JS
操作DOM結構,渲染引擎會暴露一些介面供JavaScript調用。由於這兩塊相互分離,通信是需要付出代價的,因此JavaScript調用DOM提
供的介面性能不咋地。各種性能優化的最佳實踐也都在盡可能的減少DOM操作次數。
而虛擬DOM幹了什麼?它直接用JavaScript實現了DOM樹(大致上)。組件的HTML結構並不會直接生成DOM,而是映射生成虛擬的
JavaScript DOM結構,React又通過在這個虛擬DOM上實現了一個 diff
演算法找出最小變更,再把這些變更寫入實際的DOM中。這個虛擬DOM以JS結構的形式存在,計算性能會比較好,而且由於減少了實際DOM操作次數,性能會
有較大提升