react的非DOM操作

來源:互聯網
上載者:User

標籤:自訂群組件   rip   pre   父節點   嵌套   應用   message   end   判斷   

  1. 非dom屬性?
    dangerouslySetInnerHTML,ref,key
    非dom標準屬性,也就是說dom標準裡面沒有規定的屬性,react引入了三個非dom屬性,如上。

    dangerouslySetInnerHTML:字面意思,危險的設定內部html,這個屬性的作用就是在jsx中,直接插入html代碼。我們為什麼用這個屬性插入html代碼呢?而不是在編寫代碼的時候直接寫入呢?因為有的時候我們在編寫代碼的時候,無法確實要插入什麼代碼,也就是說這部分html代碼是動態產生的。或者說不是由我們來編寫的,為什麼這中行為是危險的呢?有一個詞語叫做跨站攻擊,之所以會產生跨站攻擊,就是因為有這樣的直接寫入代碼功能,我們舉個例子,如果頁面上要顯示一個內容,這個內容來自於使用者的輸入,假設使用者的輸入中包含了代碼,比如說js代碼,html代碼,如果我們不經過檢測就直接使用,把這個dom插入到頁面中,那麼其他人訪問頁面的時候,就會執行這個人寫入的代碼,由於我們無法判斷這個使用者的意圖,所以他有可能寫入很危險的代碼,比如說添加一個串連,串連到一個木馬,那麼訪問這個頁面的使用者,就會在不知不覺中中病毒或者下載木馬,這是非常危險的,但是有些時候我們確實需要動態寫入代碼,所以react還是提供了這個屬性,只是明確的在名字裡面告訴你這個屬性是很危險的,盡量不要去使用。

    ref:reference的縮寫,父組件引用子組件,我們在編寫組件的時候,經常會用到嵌套的情況,父組件如果嵌套了子組件,父組件引用子組件的時候,就需要用ref,在實際的使用中ref其實是在父組件中維護了很多引用,每一個引用都引用到了一個對應的子組件,這樣我們在父組件中就可以通過這些引用來操作子組件。為什麼我們不能操作父組件的父組件呢?這個其實不是代碼問題,而是設計問題,在react中我們使用組件的目的就是使代碼模組化,每個組件只需要考慮自己自身的功能,邏輯,不需要關心誰在使用它,因此組件不需要引用他本身的父組件,父組件和組件之間的互動式通過屬性的傳遞來實現的,我們後面會說。但是這樣的傳遞是單向的,也就是說,屬性總是由上往下傳遞,下面的組件不會對上面的組件進行控制,這是為了讓邏輯更加清晰,

    key:提高渲染效能。react特點之一就是效能好,這是因為他去除了手動的dom操作,完全由自動來實現,但是自動實現就說明他有一套演算法,也就說在頁面發生變化的時候,react需要應用這套演算法來判斷如何高效的修改頁面,以反映出對應的變化,這個演算法通常被稱為diff,也就是different的縮寫,表示計算兩個狀態之間的差異。


  2. react diff演算法
           
                                react diff演算法的流程圖
       首先需要明確我們現在進行比較的是兩個組件,react中所有的東西都是組件,所以我們只要明白了兩個組件之間是如何比較的,其他的結構都可以分解成組件進行比較。
    最左側是開始,開始以後第一個判斷就是節點是否相同,相同的意思就是div和div是相同的,div和p就是不同的,或者說我們自訂的HelloMessage和HelloMessage是相同的,HellowMessage 和HelloWorld就不是相同的組件,節點如果相同才會進行後面的比較,如果節點不同,react會直接拋棄舊的節點,產生一個全新的節點,在這裡react是基於一個假設,如果兩個節點不同,那麼他們的內容很大程度不同。如果節點不同我們就直接結束比較,產生全新的節點,如果節點相同,下一步需要判斷的是,這個幾點是自訂的節點還是dom的標準節點,也就是說,他是div還是HelloWorld,如果說不是自訂的節點,是標準的節點,那麼react下一步需要做的就是比較兩個節點的屬性,比如說class,id等,如果屬性完全相同,就說明兩個節點是相同的,結束比較;如果屬性不同,就把不同的屬性記下來,並應用改動,比如說多了一個新屬性,就加入一個新屬性,少了一個屬性就刪掉一個屬性,類似這樣的操作。也就是react並不會刪掉舊的節點,只會在他上面進行操作。若果是自訂的節點,react會重新渲染他,我們後面會學習屬性和狀態,一個組件有很多狀態,如果是同一個自訂群組件,那麼新組件可能只是舊組件的一個狀態,所說reac會 把新的狀態傳入到舊的組件中,然後比較組件的渲染結果,並進行改動,也就是說react仍然不會重建組件,而是在舊的組件上進行改動,這就是diff演算法的整個流程。那麼key到底有什麼用呢?key作用主要體現在節點的比較,假設我們有一個類似列表的節點,也就是父節點裡面有多個子節點,那麼如果沒有key的時候,我們進行改動,react會比較傻的從左至右進行比較,比如說在改動之前只有節點1,在改動之後我們插入一個節點2,變成了節點2,節點1,那麼react執行的操作是,刪除節點1,添加節點2,添加節點1,也就是說,react無法判斷新狀態中的節點1是不是就狀態中的節點1,所以他只能把不同的全部刪掉,即使他們可能相同,這樣就導致效能上的問題,那麼引入key的目的就是給每個節點加上唯一的標識,這樣的話react通過比較key,就可以知道到底哪些節點是原有節點,哪些節點是新加入的節點,針對我們剛才說的例子, 節點1變成了節點2節點1,這時候,react只需要做一個操作,就是插入節點2,因為節點1的key是一樣的,說明他們兩個是同一個節點,沒有變化。
        瞭解這個原理,對於我們編寫react組件有什麼啟示呢?
        第一點就是如果兩個組件非常類似,那就盡量把他們寫成一個組件,因為我們在流程中看到,兩個不相同的組件一定會被重建,即使他們的內容非常的相似,。第二個啟示就是如果使用類似的列表來展示元素的話,那麼元素盡量加上key,這樣可以極大地提高效率,避免不必要的效能損耗。


  3. 如何使用非dom屬性?
    dangerously的執行個體
    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>hello world</title></head><body>    <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.js"></script>    <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script>    <script type="text/jsx">        var style={           color:"red",           border:"1px solid #f09",        };        var rawHTML={           __html:"<h1>I am inner HTML</h1>"        };        var HelloWorld=React.createClass({        render: function(){           return <p>Hello,world</p>        }        });        React.render(<div style={style} dangerouslySetInnerHTML={rawHTML}></div>,document.body);    </script></body></html>


    ref執行個體,要注意通過引用拿到的並不是這個dom節點本身,也就說我們並不能進行dom之間的操作,比如說設定文本,這樣是不行的,我們拿到的只是一個虛擬dom節點,也就是react展示給我們的dom節點,如果想要拿到真正的dom節點,還需要調用一個方法,後面我們會說,不過react並不會鼓勵我們這樣去做,除非在特殊的情況下,我們需要操作dom節點,其他情況react會協助我我們進行操作,

    這個例子不全,後面我們會繼續講解。

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>hello world</title></head><body>    <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.js"></script>    <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script>    <script type="text/jsx">        var style={           color:"red",           border:"1px solid #f09",        };        var rawHTML={           __html:"<h1>I am inner HTML</h1>"        };        var HelloWorld=React.createClass({        render: function(){           this.refs.childp                      return <p ref="childp">Hello,world</p>        }        });        React.render(<div style={style} dangerouslySetInnerHTML={rawHTML}></div>,document.body);    </script></body></html>


    key執行個體:注意在每個組件的內部,key的值必須是不同的,注意是組件內部!兩個組件之間就沒有這個限制了。
    記住兩點:1,內容類別似的組件盡量合并稱為同一個組件,2清單類型的元素,一定要加上唯一的key,做到這兩點,就能避免很多效能問題。

    <!DOCTYPE html><html lang="en"><head>    <meta charset="UTF-8">    <title>hello world</title></head><body>    <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/react.js"></script>    <script type="text/javascript" src="http://cdn.bootcss.com/react/0.13.2/JSXTransformer.js"></script>    <script type="text/jsx">        var style={           color:"red",           border:"1px solid #f09",        };        var rawHTML={           __html:"<h1>I am inner HTML</h1>"        };        var HelloWorld=React.createClass({        render: function(){            return             <ul>                <li key="1">1</li>                <li key="2">2</li>                <li key="3">3</li>            </ul>        }        });        React.render(<div style={style} dangerouslySetInnerHTML={rawHTML}></div>,document.body);    </script></body></html>

react的非DOM操作

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.