国产av日韩一区二区三区精品,成人性爱视频在线观看,国产,欧美,日韩,一区,www.成色av久久成人,2222eeee成人天堂

文字

React可以用于任何Web應(yīng)用程序。它可以嵌入到其他應(yīng)用程序中,并且可以將其他應(yīng)用程序嵌入到React中。本指南將檢查一些更常見(jiàn)的用例,重點(diǎn)介紹與jQuery和Backbone的集成,但是可以將相同的思想應(yīng)用于將組件與任何現(xiàn)有代碼集成。

與DOM操作插件集成

React不知道在React之外對(duì)DOM做出的更改。它根據(jù)自己的內(nèi)部表示來(lái)確定更新,并且如果相同的DOM節(jié)點(diǎn)被另一個(gè)庫(kù)操縱,則React會(huì)感到困惑并且無(wú)法恢復(fù)。

這并不意味著將React與其他影響DOM的方式結(jié)合起來(lái)是不可能的,甚至是一定困難的,您只需要注意每個(gè)人正在做什么。

避免沖突的最簡(jiǎn)單方法是防止更新React組件。你可以通過(guò)渲染React沒(méi)有理由更新的元素來(lái)做到這一點(diǎn),比如空白<div />

如何解決這個(gè)問(wèn)題

為了演示這一點(diǎn),讓我們勾勒一個(gè)通用jQuery插件的包裝。

我們將附加一個(gè)ref到根DOM元素。在里面componentDidMount,我們會(huì)得到一個(gè)引用,所以我們可以將它傳遞給jQuery插件。

為了防止觸摸安裝后的DOM反應(yīng),我們會(huì)返回一個(gè)空<div />render()方法。該<div />元素沒(méi)有屬性或子元素,因此React沒(méi)有理由更新它,讓jQuery插件可以自由地管理DOM的這一部分:

class SomePlugin extends React.Component {  componentDidMount() {    
    this.$el = $(this.el);    
    this.$el.somePlugin();  }  componentWillUnmount() {    
        this.$el.somePlugin('destroy');  }  render() {    
            return <div ref={el => this.el = el} />;  }}

請(qǐng)注意,我們定義了兩個(gè)componentDidMountcomponentWillUnmount生命周期鉤子。許多jQuery插件將事件監(jiān)聽(tīng)器附加到DOM,因此將它們分開(kāi)是非常重要的componentWillUnmount。如果插件沒(méi)有提供清理方法,則可能需要提供自己的插件,記住刪除插件注冊(cè)的任何事件偵聽(tīng)器,以防止內(nèi)存泄漏。

與jQuery選擇插件集成

對(duì)于這些概念的更具體的例子,我們來(lái)為插件Chosen寫(xiě)一個(gè)最小包裝,它增加了<select>輸入。

注意:   僅僅因?yàn)檫@可能,并不意味著它是React應(yīng)用程序的最佳方法。我們建議您盡可能使用React組件。React組件更容易在React應(yīng)用程序中重用,并且通??梢愿玫乜刂破湫袨楹屯庥^。

首先,我們來(lái)看看選擇DOM對(duì)于什么。

如果您在<select>DOM節(jié)點(diǎn)上調(diào)用它,它會(huì)從原始DOM節(jié)點(diǎn)讀取屬性,將其隱藏為內(nèi)聯(lián)樣式,然后在其后面附加一個(gè)單獨(dú)的DOM節(jié)點(diǎn),并在其后面附帶自己的可視化表示<select>。然后它會(huì)觸發(fā)jQuery事件來(lái)通知我們有關(guān)更改。

假設(shè)這是我們用<Chosen>包裝器React組件爭(zhēng)取的API :

function Example() {  return (    <Chosen onChange={value => console.log(value)}>      
    <option>vanilla</option>      
    <option>chocolate</option>      
    <option>strawberry</option>    
    </Chosen>  );
    }

我們將把它作為一個(gè)不受控制的組件來(lái)簡(jiǎn)化。

首先,我們將創(chuàng)建一個(gè)空的成分render(),我們返回方法<select>裹著<div>

class Chosen extends React.Component {  render() {    
    return (      
    <div>        
        <select className="Chosen-select" ref={el => this.el = el}>          
        {this.props.children}        
        </select>      
    </div>    );  }
    }

注意我們<select>是如何包裹在一個(gè)額外的<div>。這是必要的,因?yàn)镃hosen會(huì)在<select>我們傳遞給它的節(jié)點(diǎn)之后追加另一個(gè)DOM元素。但是,就React而言,<div>總是只有一個(gè)孩子。這就是我們?nèi)绾未_保React更新不會(huì)與由Chosen附加的額外DOM節(jié)點(diǎn)發(fā)生沖突的原因。重要的是,如果您在React流的外部修改DOM,則必須確保React沒(méi)有理由觸摸這些DOM節(jié)點(diǎn)。

接下來(lái),我們將實(shí)現(xiàn)生命周期掛鉤。我們需要初始化選中的參考<select>節(jié)點(diǎn)componentDidMount,并將其拆分為componentWillUnmount

componentDidMount() {  this.$el = $(this.el);  this.$el.chosen();}componentWillUnmount() {  this.$el.chosen('destroy');}

在CodePen上試用它。

請(qǐng)注意,React不會(huì)為該this.el字段賦予特殊含義。它只能工作,因?yàn)槲覀円郧?code>ref在該render()方法中從a分配了該字段:

<select className="Chosen-select" ref={el => this.el = el}>

這足以讓我們的組件渲染,但我們也希望得到關(guān)于值更改的通知。為此,我們將訂閱由Chosen管理的jQuery change事件<select>。

我們不會(huì)this.props.onChange直接通過(guò)選擇,因?yàn)榻M件的道具可能隨時(shí)間而改變,并且包括事件處理程序。相反,我們將聲明一個(gè)handleChange()調(diào)用方法this.props.onChange,并將其訂閱到j(luò)Query change事件中:

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);}

在CodePen上試用。

最后還有一件事要做。在React中,道具可以隨時(shí)間變化。例如,<Chosen>如果父組件的狀態(tài)更改,組件可以獲得不同的子項(xiàng)。這意味著在集成點(diǎn),我們手動(dòng)更新DOM以響應(yīng)prop更新非常重要,因?yàn)槲覀儾辉僮孯eact為我們管理DOM。

Chosen的文檔建議我們可以使用jQuery trigger()API來(lái)通知它對(duì)原始DOM元素的更改。我們將讓React負(fù)責(zé)this.props.children內(nèi)部更新<select>,但我們還將添加一個(gè)componentDidUpdate()生命周期掛鉤,通知Chosen關(guān)于子列表中的更改:

componentDidUpdate(prevProps) {  if (prevProps.children !== this.props.children) {    this.$el.trigger("chosen:updated");  }}

這樣,當(dāng)<select>由React管理的孩子發(fā)生變化時(shí),Chosen會(huì)知道更新其DOM元素。

Chosen組件的完整實(shí)現(xiàn)如下所示:

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('destroy');  
      }  
  handleChange(e) {    
      this.props.onChange(e.target.value);  }  render() {    
          return (      
              <div>        
              <select className="Chosen-select" ref={el => this.el = el}>          
              {this.props.children}        
              </select>      
              </div>    );  
              }
         }

在CodePen上試用它。

與其他視圖庫(kù)集成

由于靈活性,React可以嵌入到其他應(yīng)用程序中ReactDOM.render()。

雖然React在啟動(dòng)時(shí)通常用于將單個(gè)根React組件加載到DOM中,ReactDOM.render()但也可以為UI的獨(dú)立部分多次調(diào)用,該部分可以像按鈕一樣小,也可以與應(yīng)用程序一樣大。

事實(shí)上,這正是Facebook如何使用React。這讓我們可以在React中逐個(gè)編寫(xiě)應(yīng)用程序,并將其與我們現(xiàn)有的服務(wù)器生成的模板和其他客戶端代碼結(jié)合使用。

用React替換基于字符串的渲染

舊Web應(yīng)用程序中的一種常見(jiàn)模式是將DOM的塊描述為字符串,并將其插入到DOM中,如下所示:$el.html(htmlString)。代碼庫(kù)中的這些點(diǎn)非常適合引入React。只需將基于字符串的渲染重寫(xiě)為React組件即可。

所以下面的jQuery實(shí)現(xiàn)...

$('#container').html('<button id="btn">Say Hello</button>');$('#btn').click(function() {  alert('Hello!');});

...可以使用React組件重寫(xiě):

function Button() {  return <button id="btn">Say Hello</button>;}ReactDOM.render(  <Button />,
  document.getElementById('container'),  function() {    $('#btn').click(function() {      alert('Hello!');    });  });

從這里開(kāi)始,您可以開(kāi)始將更多邏輯轉(zhuǎn)移到組件中,并開(kāi)始采用更常見(jiàn)的React實(shí)踐。例如,在組件中,最好不要依賴(lài)ID,因?yàn)榭梢远啻武秩鞠嗤慕M件。相反,我們將使用React事件系統(tǒng),并將點(diǎn)擊處理程序直接注冊(cè)到React <button>元素上:

function Button(props) {  
    return <button onClick={props.onClick}>Say Hello</button>;
    }function HelloButton() {  function handleClick() {    
        alert('Hello!');  }  
        return <Button onClick={handleClick} />;
        }ReactDOM.render(  <HelloButton />,
  document.getElementById('container'));

在CodePen上試用它。

您可以擁有任意數(shù)量的此類(lèi)隔離組件,并使用ReactDOM.render()它們將它們呈現(xiàn)給不同的DOM容器。逐漸地,當(dāng)您將更多應(yīng)用程序轉(zhuǎn)換為React時(shí),您將能夠?qū)⑺鼈兘M合成更大的組件,并將一些ReactDOM.render()調(diào)用移動(dòng)到層次結(jié)構(gòu)中。

在骨干視圖中嵌入React

主干視圖通常使用HTML字符串或字符串生成模板函數(shù)來(lái)為其DOM元素創(chuàng)建內(nèi)容。這個(gè)過(guò)程也可以用渲染React組件來(lái)替換。

下面,我們將創(chuàng)建一個(gè)名為Backbone的視圖ParagraphView。它將覆蓋Backbone的render()函數(shù),將React <Paragraph>組件渲染到由Backbone(this.el)提供的DOM元素中。在這里,我們也在使用ReactDOM.render()

function Paragraph(props) {  return <p>{props.text}</p>;}
const ParagraphView = Backbone.View.extend({  render() {    
    const text = this.model.get('text');
    ReactDOM.render(<Paragraph text={text} />, this.el);    
    return this;  
    },  remove() {
    ReactDOM.unmountComponentAtNode(this.el);
    Backbone.View.prototype.remove.call(this);  }});

在CodePen上試用它。

我們也呼吁是非常重要ReactDOM.unmountComponentAtNode()remove方法,以便作出反應(yīng)注銷(xiāo)事件處理程序,并與組件樹(shù)相關(guān)的其他資源,當(dāng)它被分離。

當(dāng)一個(gè)組件一個(gè)React樹(shù)中被移除時(shí),清理會(huì)自動(dòng)執(zhí)行,但因?yàn)槲覀円謩?dòng)移除整個(gè)樹(shù),所以我們必須把它稱(chēng)為這個(gè)方法。

與模型層集成

雖然通常建議使用單向數(shù)據(jù)流,例如React狀態(tài),F(xiàn)lux或Redux,但React組件可以使用其他框架和庫(kù)中的模型層。

在React組件中使用Backbone模型

使用React組件的Backbone模型和集合的最簡(jiǎn)單方法是偵聽(tīng)各種更改事件并手動(dòng)強(qiáng)制更新。

負(fù)責(zé)渲染模型的組件將監(jiān)聽(tīng)'change'事件,而負(fù)責(zé)渲染集合的組件將監(jiān)聽(tīng)'add''remove'事件。在這兩種情況下,都需要this.forceUpdate()使用新數(shù)據(jù)調(diào)用組件。

在下面的示例中,List組件呈現(xiàn)Backbone集合,使用該Item組件呈現(xiàn)單個(gè)項(xiàng)目。

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 <li>{this.props.model.get('text')}</li>;  }
            }
        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 (      
                    <ul> 
                    {this.props.collection.map(model => 
                    ( <Item key={model.cid} model={model} />))
                    }      
                    </ul>    
                    );  }
                    }

在CodePen上試用它。

從主干模型中提取數(shù)據(jù)

上述方法要求您的React組件知道Backbone模型和集合。如果您后來(lái)計(jì)劃遷移到另一個(gè)數(shù)據(jù)管理解決方案,則可能需要盡可能少地將有關(guān)Backbone的知識(shí)集中在代碼中。

解決這個(gè)問(wèn)題的一個(gè)辦法是在模型的屬性發(fā)生變化時(shí)將模型的屬性作為普通數(shù)據(jù)提取出來(lái),并將這個(gè)邏輯放在一個(gè)地方。以下是一個(gè)高階組件,它將Backbone模型的所有屬性提取到狀態(tài)中,并將數(shù)據(jù)傳遞給包裝組件。

這樣,只有高階組件需要了解Backbone模型內(nèi)部,并且應(yīng)用程序中的大多數(shù)組件都可以不依賴(lài)于Backbone。

在下面的例子中,我們將復(fù)制模型的屬性以形成初始狀態(tài)。我們訂閱change事件(并取消訂閱卸載),當(dāng)它發(fā)生時(shí),我們用模型的當(dāng)前屬性更新?tīng)顟B(tài)。最后,我們確保如果model道具本身發(fā)生變化,我們不會(huì)忘記退訂舊模型,并訂閱新模型。

請(qǐng)注意,這個(gè)例子并不意味著在使用Backbone方面是詳盡的,但它應(yīng)該給你一個(gè)關(guān)于如何以一種通用的方式來(lái)解決這個(gè)問(wèn)題的想法:

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 <WrappedComponent {...propsExceptModel} {...this.state} />;    }  
            }
}

為了演示如何使用它,我們將NameInputReact組件連接到Backbone模型,并在firstName每次輸入更改時(shí)更新其屬性:

function NameInput(props) {  return (    
    <p>      
    <input value={props.firstName} onChange={props.handleChange} />      <br />
      My name is {props.firstName}.    </p>  );}
      const BackboneNameInput = connectToBackboneModel(NameInput);function Example(props) {  function handleChange(e) {
        model.set('firstName', e.target.value);  }  return (    
        <BackboneNameInput
      model={props.model}
      handleChange={handleChange}    />  );}
      const model = new Backbone.Model({ firstName: 'Frodo' });
      ReactDOM.render(  <Example model={model} />,
      document.getElementById('root'));

在CodePen上試用它。

這項(xiàng)技術(shù)不限于Backbone。您可以通過(guò)訂閱其生命周期掛鉤中的更改并將數(shù)據(jù)復(fù)制到本地React狀態(tài),從而將React用于任何模型庫(kù)。

上一篇: 下一篇: