2015-07-21 60 views
1

我有一些嵌套的React組件,其內部是一個大型的svg圖,其中有數百個(如果不是數千)linerect元素。爲了啓用一些應用程序範圍的行爲和外觀變化,我想改變最上面的組件的className。問題是,如果我這樣做,整個應用程序會重新渲染。如何避免反應重新渲染整個樹簡單的className更改?

我知道這種行爲在單向呈現流的意義上是有點意圖的,但我認爲React會更明智地重用它,並將DOM更改保持在最低限度。

這裏最簡單的例子:https://jsbin.com/rabofewawu/1/edit?html,js,output 正如你所看到的,每次按'這裏'時,SVG中的線條模式都會改變,但我只想讓背景顏色改變。

當我嘗試通過更改內部g元素的transform屬性來縮放和平移svg時,會出現類似但更極端的示例。使用d3,我只需更改屬性。隨着反應,我的render函數被調用,更新的狀態導致更新的transform屬性,整個組從頭開始重新渲染,而不是改變DOM屬性。

我錯過了什麼嗎? React如何實現我想要做的事情?

回答

2

這個功能有點把這個簡單的貌似無害的渲染功能:

render(){ 
    return <div>{Date.now()}</div>; 
} 

在陣營的心智模式,這將始終顯示當前數量每毫秒。 React概念上每秒更新無限次。渲染的輸入是世界上的一切,但我們碰巧只是使用時鐘。鑑於同一個世界,我們從渲染獲得相同的輸出,因此它是冪等的。

那麼廢話......我們沒有無限快速的電腦,所以我們需要妥協。而不是渲染的輸入是我們限制它的狀態和道具(和上下文)的所有東西。

在此限制設置中,使用Math.random或Date.now會違反規則。如果你需要使用這些輸出,它必須先通過狀態或道具。這看起來如何?那麼我們可以使用確定性的隨機數生成器並將種子存儲在狀態中。這裏有一個modified version of your component這樣做:

var MyComponent = React.createClass({ 
    displayName:"MyComponent", 

    getInitialState(){ 
    return { 
     seed: Math.floor(Math.random()*0xffffff) 
    }; 
    }, 

    render: function() { 
    // make a random number generator with the given seed 
    var rng = new Chance(this.state.seed); 
    function random(x){ 
     return rng.floating({min: 0, max: x, fixed: 7}) 
    } 

    var s=100, lines = []; 

    for (var i=0; i<100; i++) { 
     var line = { x1: random(s), y1: random(s), x2: random(s), y2: random(s) }; 

     lines.push(React.createElement("line", line)); 
    } 

    return React.createElement("svg", { height: s, width: s}, lines); 
    } 
}); 

超過每秒無限次渲染較少,而且只渲染某些組件是一種優化。優化不應該影響程序的行爲。

如果您需要不同的隨機數,您可以將種子設置爲不同的隨機數。使用real Math.random()這裏沒關係,因爲state是代碼中的結果或I/O操作,並且您響應某些其他I/O(例如,單擊處理程序)調用此setState。


時間是相似的;如果要渲染當前時間,請使用setTimeout和setState以及當前時間。然後,您可以在渲染中顯示它的樣子,包括將其傳遞給其他組件,並對其進行任何類型的數學運算。

+0

我認爲我選擇了一個糟糕的例子,使用時間,我只是想強調組件確實被重新渲染。這當然是,因爲它返回一個不同的DOM樹。儘管如此,你的提示讓我思考,真正的問題是:'svg'元素不是完全相同的標記(小數點後的第6或第7個數字),這是重新呈現的真正原因。 – lordvlad

+0

我的觀點是,重新渲染不應該導致任何問題。如果是這樣,你有非常脆弱的組件。 – FakeRainBrigand

相關問題