摘要:也就是說,只要一發(fā)生事件。和其他的庫共用由于方法的靈活性使得可以被嵌入到其他的應(yīng)用中。事實上,這就是在被使用的方式。在應(yīng)用中使用的層在組件中消費中和最簡單的方法是監(jiān)聽各種事件并手動進行強制更新。并且使用組件來渲染各個項。
注:由于譯者水平有限,難免會出現(xiàn)錯誤,希望大家能指出,謝謝。
react 可以被用在任何的web 應(yīng)用中。它可以被嵌入到其他的應(yīng)用中,要是你小心一點,其他的應(yīng)用也能被嵌入到react中。這篇文章將會從一些常用的使用場景入手,重點會關(guān)注與jQuery 和backbone 的交互。但是里面的思想在我們和其他庫交互時都是可以被參考的。
和操縱DOM的插件的交互react 感知不到它管理之外的dom 的變化。react的更新是取決于其內(nèi)部的表現(xiàn),如果同樣的DOM節(jié)點被其他可操作dom節(jié)點的插件更改了,react內(nèi)部狀態(tài)就會變的很混亂并且無法恢復(fù)了。
這并不意味著react 無法和那些操縱DOM 的插件一起共用,你只需要更加清楚每個插件做了什么。
最簡單的避免這種沖突發(fā)生的方式是阻止react 組件的更新。你可以通過渲染一個react 沒有必要去更新的元素,比如一個空的
如何處理這種問題為了更好的闡述這個問題,讓我們來對一個一般的jquery 插件添加一個wrapper。
首先,我們在這個節(jié)點上添加一個ref屬性。在componentDidMount 方法里,我們通過獲取這個節(jié)點的引用,將它傳給jquery 插件。
為了避免react 在渲染期間對這個節(jié)點進行改變, 我們在render() 方法里面返回了一個空的
.這個空的節(jié)點沒有任何的屬性或子節(jié)點,所以React 不會對該節(jié)點進行更新,這個節(jié)點的控制權(quán)完全在jQuery插件上。這樣就不會出現(xiàn)react 和jquery 插件都操作同樣的dom 的問題了。class SomePlugin extends React.Component { componentDidMount() { this.$el = $(this.el); this.$el.somePlugin(); } componentWillUnmount() { this.$el.somePlugin("destroy"); } render() { returnthis.el = el} />; } }需要注意的是,我們定義了componentDidMount() 和componentWillUnmount() 兩個生命周期的鉤子函數(shù)。這是因為大多數(shù)的jQuery插件都將事件監(jiān)聽綁定在DOM上,所以在componentWillUnmount 中一定要移除事件監(jiān)聽。如果這個插件沒有提供移除的方法,那你就要自己寫了。一定要記得移除插件所注冊的事件,否則可能會出現(xiàn)內(nèi)存泄露。
和jQuery 的選擇器插件共用為了對這些概念有更深入的了解,我們?yōu)镃hosen 插件寫了一個小型的wrapper。Chosen 插件的參數(shù)是一個
注意,雖然可以這樣用,但這并不是最好的方式。我們推薦盡可能的使用react組件。這樣在react應(yīng)用中可以更好的復(fù)用,而且會有更好的使用效果
首先,讓我們來看看Chosen 插件對DOM元素做了什么。
如果你在對一個這就是我們想要我們的Chosen 插件包裝完成的功能
function Example() { return (console.log(value)}> ); }為了簡單起見,我們使用一個非受控組件來實現(xiàn)它
首先,我們創(chuàng)建一個只有render方法的組件。在render方法中我們返回一個class Chosen extends React.Component { render() { return (); } }this.el = el}> {this.props.children} 需要注意的是,我們在
標(biāo)簽外加了一個 標(biāo)簽。這很有必要,因為我們后續(xù)會在標(biāo)簽后面添加一個傳入的節(jié)點。然而,就React而言, 標(biāo)簽通常只有一個孩子節(jié)點。這就是我們?nèi)绾未_保React 的更新不會和通過Chosen 插入的額外的DOM節(jié)點沖突的原因。很重要的一點是,如果你在React 流之外修改了DOM節(jié)點,你必須確保React 不會因為任何原因再對這些DOM節(jié)點進行操作。接下來,我們繼續(xù)實現(xiàn)生命周期的鉤子函數(shù)。我們需要在componentDidMount里使用
節(jié)點的引用來初始化Chosen.并且在componentDidUnmount 里面銷毀它。 componentDidMount() { this.$el = $(this.el); this.$el.chosen(); } componentWillUnmount() { this.$el.chosen("destroy"); }記住,react 不會對this.el 字段賦予任何特殊的含義。除非你之前在render方法里面對它進行賦值。
this.el = el}> 以上對于在render 里面獲取你的組件就足夠了,但是我們還希望值變化時能給實現(xiàn)通知。因為,我們通過Chosen 在
上 訂閱了jQuery 的change事件。 我們不會直接的將this.props.onChange傳給Chosen. 因為組件的屬性可能會一直改變,而且這里還包含著事件的處理。因為,我們聲明了一個handleChange方法來調(diào)用this.props.onChange.并且為它訂閱了jQuery的change事件中。也就是說,只要一發(fā)生change 事件。就會自動執(zhí)行handleChange 方法。
componentDidMount() { this.$el = $(this.el); this.$el.chosen(); this.handleChange = this.handleChange.bind(this); this.$el.on("change", this.handleChange); } componentWillUnmount() { this.$el.off("change", this.handleChange); this.$el.chosen("destroy"); } handleChange(e) { this.props.onChange(e.target.value); }最后,我們還有一件事要做。在React 中,由于屬性是可以一直改變的。例如,
組件能夠獲取不同的children 如果父組件狀態(tài)改變的話。這意味著在交互過程中,很重要的一點是,當(dāng)屬性改變時,我們需要手動的控制DOM的更新,不再需要react 來為我們管理DOM節(jié)點了。 Chosen 的文檔建議我們使用jQuery 的trigger() 方法來通知原始DOM元素的變化。我們將使React重點關(guān)注在
中的屬性this.props.children 的更新。但是我們同時也在componentDidUpdate 的生命周期函數(shù)里添加通知Chosen 他的children 列表變化的函數(shù)。 componentDidUpdate(prevProps) { if (preProps.children !== this.props.children) { this.$el.trigger("chosen:updated"); } }通過這種方式,當(dāng)通過React 管理的
節(jié)點改變的時候,Chosen 就會知道需要更新DOM元素了。 class Chosen extends React.Component { componentDidMount() { this.$el = $(this.el); this.$el.chosen(); this.handleChange = this.handleChange.bind(this); this.$(el).on("change", this.handleChange); } componentDidUpdate(prevProps) { if (prevProps.children !== this.props.children) { this.$el.trigger("chosen:updated"); } } componentWillUnmount() { this.$el.off("change", this.handleChange); this.$el.chosen("destory"); } handleChange(e) { this.props.onChange(e.target.value); } render() { return (和其他的View 庫共用); } }this.el = el}> {this.props.children} 由于ReactDOM.render()方法的靈活性使得React可以被嵌入到其他的應(yīng)用中。
由于React 通常被用來將一個React 節(jié)點渲染到某個DOM元素中,而且ReactDOM.render()可以被UI的各個獨立的部分多次調(diào)用,小到一個按鈕,大到一個app。
事實上,這就是React 在Facebook 被使用的方式。這使得我們可以在React 中一塊一塊的開發(fā)一個應(yīng)用,并且可以把它整合在現(xiàn)有的服務(wù)器渲染的模版中或者其他的客戶端代碼中。
使用React替換基于字符串的渲染在一些老的web 應(yīng)用,一種常見的方式是寫一大段DOM結(jié)構(gòu)作為字符串,然后使用$el.html(htmlString) 的方式插入到DOM節(jié)點中。如果你的代碼庫中有類似的場景,那么推薦你使用react。你只需要將使用字符串渲染的部分改成react 組件就可以了。
下面是一個jQuery 的實現(xiàn)$("#container").html(""); $("#btn").click(function() { alert("Hello!"); });改成react 的實現(xiàn)
function Button() { return ; } ReactDOM.render( , document.getElementById("container"), function() { $("#btn").click(function() { alert("Hello!"); }); } );接下來,你可以將更多的業(yè)務(wù)邏輯移到react組件中去并且采用更多react 實踐方式。例如,組件最好不要依賴id,因為同樣的組件可能會被渲染多次。而且,我們推薦使用react 的事件系統(tǒng),直接在組件
function Button(props) { return ; } function HelloButton() { function handleClick() { alert("Hello!"); } return ; } ReactDOM.render(, document.getElementById("container") ); 你可以有很多這樣獨立的組件,并且使用ReactDOM.render()方法將他們渲染到不同的DOM節(jié)點中。慢慢的,你在app 中使用越來越多的react 技術(shù),你就可以將這些獨立的組件整合成更大的組件。同時,將一些ReactDOM.render() 的調(diào)用移動到不同的層級中。
將React 嵌入到Backbone 的視圖中Backbone 的視圖就是典型的使用HTML 字符串,或者使用一些字符串模版函數(shù)來生成這樣的字符串,然后將之作為DOM元素的內(nèi)容。這種處理方式,也能被替換為使用React 組件渲染的方式。
下面,我們將會創(chuàng)建一個Backbone 的視圖ParagraphView. 我們會通過渲染一個React
組件,然后使用Backbone 提供的(this.el)方式將它插入到DOM元素中的方式來重寫B(tài)ackbone 的render() 方法. 當(dāng)然,我們也會使用ReactDOM.render()方法. function Paragraph(props) { return{props.text}
; } const ParagraphView = Backbone.View.extend({ render() { const text = this.model.get("text"); ReactDOM.render(, this.el); return this; }, remove() { ReactDOM.unmountComponentAtNode(this.el); Backbone.View.prototype.remove.call(this); } }); 很重要的一件事是,我們必須在remove方法中調(diào)用 ReactDOM.unmountComponentAtNode() 方法來解除通過react 注冊的事件和一些其他的資源。
當(dāng)一個組件從react樹中移除時,一些清理工作會被自動執(zhí)行。但是因為我們手動的移除了整個樹,所以我們必須要調(diào)用這個方法來進行清理工作。
和Model 層進行交互通常我們推薦使用單向數(shù)據(jù)流比如React state, Flux 或者Redux來管理react 應(yīng)用。其實,react 也能使用一些其他框架或者庫的Model 層來進行管理。
在react 應(yīng)用中使用Backbone 的model層在React 組件中消費Backbone中model和collections 最簡單的方法是監(jiān)聽各種change 事件并手動進行強制更新。
渲染models 的組件會監(jiān)聽 "change"事件,渲染collections 的組件會監(jiān)聽‘a(chǎn)dd’和‘remove’事件。然后,調(diào)用this.forceUpdate() 來使用新數(shù)據(jù)重新渲染組件。
下面的例子中,List 組件會渲染一個Backbone 容器。并且使用Item 組件來渲染各個項。
class Item extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange() { this.forceUpdate(); } componentDidMount() { this.props.model.on("change", this.handleChange); } componentWillUnmount() { this.props.model.off("change", this.handleChange); } render() { return{this.props.model.get("text")} ; } } class List extends React.Component { constructor(props) { super(props); this.handleChange = this.handleChange.bind(this); } handleChange() { this.forceUpdate(); } componentDidMount() { this.props.collection.on("add", "remove", this.handleChange); } componentWillUnmount() { this.props.collection.off("add", "remove", this.handleChange); } render() { return ({this.props.collection.map(model => (
); } } 從Backbone 的Models 中提取數(shù)據(jù)- ))}
上述的處理方式要求你的React 組件能夠感知到Backbone 的Models 和 Collections .如果你后續(xù)要整合其他的數(shù)據(jù)管理方案,你可能需要更多關(guān)注Backbone 的實現(xiàn)細節(jié)了。
解決這個問題的一個方法是,當(dāng)model 的屬性改變時,將它提取為普通的數(shù)據(jù),并將這段邏輯保存在一個多帶帶的地方。下面演示的是一個高階組件,這個組件將Backbone 的model層的屬性轉(zhuǎn)換為state,然后把數(shù)據(jù)傳遞給被包裹的組件。
通過這種方式,只有這個高階組件需要知道Backbone Models的內(nèi)部細節(jié)信息,大部分的組件對Backbone 都是透明的。
下面的例子中,我們會對Model 的屬性進行一份拷貝來作為初始state。我們注冊了change 事件(在unmounting 中取消注冊),當(dāng)監(jiān)聽到change事件的時候,我們用model 當(dāng)前的屬性來更新state。最后,我們要確保,如果model 的屬性自己改變的話,我們不要忘記從老的model上取消訂閱,然后訂閱新的model。
注意,這個例子不是為了說明和Backbone 一起協(xié)作的細節(jié),你更應(yīng)該通過這個例子了解到處理這類問題的一種通用的方式。
function connectToBackboneModel(WrappedComponent) { return class BackboneComponent extends React.Component { constructor(props) { super(props); this.state = Object.assign({}, props.model.attributes); this.handleChange = this.handleChange.bind(this); } componentDidMount() { this.props.model.on("change", this.handleChange); } componentWillReceiveProps(nextProps) { this.setState(Object.assign({}, nextProps.model.attributes)); if (nextProps.model !== this.props.model) { this.props.model.off("change", this.handleChange); nextProps.model.on("change", this.handleChange); } } componentWillUnmount() { this.props.model.off("change", this.handleChange); } handleChange(model) { this.setState(model.changedAttributes()); } render() { const propsExceptModel = Object.assign({}, this.props); delete propsExceptModel.model; return; } } } 為了闡述如何來使用它,我們會將一個react組件NameInput 和Backbone 的model 層結(jié)合起來使用,并且每次輸入發(fā)生改變時,就會更新firstName 屬性。
function NameInput(props) { return (); } const BackboneNameInput = connectToBackboneModel(NameInput); function Example(props) { function handleChange(e) { model.set("firstName", e.target.value); } return (
My name is {props.firstName}.); } const model = new Backbone.Model({ firstName: "Frodo" }); ReactDOM.render( , document.getElementById("root") ); 這些處理技巧不僅限于Backbone. 你也可以使用React 和其他的model 庫進行整合,通過在生命周期中訂閱它的變化,并且,選擇性的,將數(shù)據(jù)復(fù)制到react 的state中。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/88570.html
相關(guān)文章
2017年前端流行的數(shù)百個javascript庫,你會幾個?
摘要:有數(shù)百個免費的庫出來,為應(yīng)用程序選擇正確的框架變得非常困難。是流行的驅(qū)動技術(shù)之一,由于年創(chuàng)建。在這三個塊中,有幾個暴露低層接口的綁定。反應(yīng)由,和許多開發(fā)人員和個人的社區(qū)維護。誕生于年,是一個輕量級的框架。 有數(shù)百個免費的JS庫出來,為應(yīng)用程序選擇正確的JavaScript框架變得非常困難。一些開發(fā)商最終會拋棄,而其他開發(fā)者則迅速發(fā)展,并得到廣泛采用。許多開發(fā)人員只知道像jQuery和R...
《高性能JavaScript》(讀書筆記)
摘要:加載的模塊會以參數(shù)形式傳入該函數(shù),從而在回調(diào)函數(shù)內(nèi)部就可以使用這些模塊。異步加載,和,瀏覽器不會失去響應(yīng)它指定的回調(diào)函數(shù),只有前面的模塊都加載成功后,才會運行,解決了依賴性的問題。插件,可以讓回調(diào)函數(shù)在頁面結(jié)構(gòu)加載完成后再運行。 這次主要是對《高性能JavaScript》一書的讀書筆記,記錄下自己之前沒有注意到或者需要引起重視的地方 第一章 加載和執(zhí)行 js代碼在執(zhí)行過程中會阻塞瀏覽...
基于 Backbone + node 的個人簡歷生成器(個人學(xué)習(xí)總結(jié))
摘要:應(yīng)用的功能這個應(yīng)用是一個個人簡歷生成器。比較好的教程有這一個。這樣的命名污染問題自然顯而易見。而且發(fā)出多次請求也會影響性能。明顯不利于維護。然而我希望能夠不發(fā)生變化,因為是在文件的前提下的標(biāo)簽頁,不能換一個標(biāo)簽就重建一個。 為什么學(xué)習(xí)backbone?這是個好問題。在這個前端框架爆炸的年代,比起backbone,對開發(fā)來說有更多更好的選擇,react,vue,angular等等。但這些...
2017年前端框架、類庫、工具大比拼
摘要:相比于開發(fā)人員的數(shù)量,目前框架類庫和工具的數(shù)量似乎更多一些。本文將會討論目前最為流行的客戶端框架類庫和工具以及它們之間的基本差異。典型的類庫包括字符串處理日期元素事件動畫網(wǎng)絡(luò)請求等功能。所以不需要明確的區(qū)分類庫框架和工具。 相比于JavaScript開發(fā)人員的數(shù)量,目前JavaScript框架、類庫和工具的數(shù)量似乎更多一些。截至2017年5月,GitHub上的快速搜索顯示,有超過110...
發(fā)表評論
0條評論
ckllj
男|高級講師
TA的文章
閱讀更多
LINUX:程序和進程
閱讀 2346·2021-11-23 09:51
短信驗證碼平臺有哪些比較好用?需從這3個方面來決定!
閱讀 1152·2021-11-22 13:52
[11.11]CMIVPS年度大促VPS主機5折,香港大帶寬/直連線路月付3.5美元起
閱讀 3623·2021-11-10 11:35
Tmwhost,澳門VPS(7.5折優(yōu)惠),$5.62/月,1核/1G內(nèi)存/50G Raid5 SS
閱讀 1203·2021-10-25 09:47
Resultful API的攔截(過濾器——Filter)
閱讀 3008·2021-09-07 09:58
前端每日實戰(zhàn):145# 視頻演示如何用純 CSS 創(chuàng)作一個電源開關(guān)控件
閱讀 1073·2019-08-30 15:54
PHP基于Thinkphp5的砍價活動相關(guān)設(shè)計
閱讀 2830·2019-08-29 14:21
CSS形狀之border-radius
閱讀 3041·2019-08-29 12:20