2015-04-17 45 views
4

反應類被「共享」當我創建一個反應類的幾個實例(通過在同一類使用React.createElement),一些成員變量的實例(數組和對象是共享之間共享,字符串和布爾等等)。成員變量通過引用

對我來說,這種感覺可怕的,可怕的,錯誤的。這是一個錯誤還是有另一種方法來做我想做的事情?

請看看: http://jsbin.com/kanayiguxu/1/edit?html,js,console,output

+2

「(?爲什麼不是這個代碼工作「)必須包括所期望的行爲,一個特定的問題或錯誤,並在最短的代碼必要時尋求幫助調試問題」重現它:這可以通過這個例子來說明***在問題本身***沒有一個明確的問題說明的問題是不是其他讀者有用請參閱:如何創建[最小,完整,可驗證的示例](/幫助/ MCVE)「。 –

+0

我建議你張貼代碼的(相關)部分的SO,你可能還需要在JavaScript中檢查出範圍的JavaScript文件:http://www.smashingmagazine.com/2009/08/01/what-you需要了解JavaScript範圍/ –

+1

@TedNyberg:從描述來看,這與範圍無關。它很可能與原型和對象引用在原型上的差異有關。 –

回答

10

你應該做的是設置你的組件上的狀態,而不是有狀態的陣營組件上任意屬性是什麼。的

所以不是這樣:

var MyComponent = React.createClass({ 
    myArray: [1, 2, 3], 
    componentWillMount() { 
    this.myArray.push(this.myArray.length + 1); 
    }, 
    render() { 
    return (
     <span>{this.myArray.length}</span> 
    ); 
    } 
}); 

你應該這樣做:

var MyComponent = React.createClass({ 
    getInitialState() { 
    return { 
     myArray: [1, 2, 3] 
    }; 
    }, 
    componentWillMount() { 
    this.setState(state => { 
     state.myArray.push(state.myArray.length + 1); 
     return state; 
    }); 
    }, 
    render() { 
    return (
     <span>{this.myArray.length}</span> 
    ); 
    } 
}); 

的原因是所有的一個部件的狀態和數據應該駐留在this.statethis.props被控制並由React處理。

您使用的道具和狀態此得到的好處,就是陣營會知道什麼時候這些變化,並從它可以告訴當它的時間來重新渲染您的組件。如果您將狀態存儲爲任意屬性或全局變量,那麼React將不會知道這些更改的時間,並且無法爲您重新呈現。

的理由讓你所看到的行爲是組件的每個實例使用你給React.createClass()爲原型的對象。因此,組件的所有實例都具有myArray屬性,但屬於原型鏈,因此被所有實例共享。

如果你真的想要這樣的事情,而你想避免this.state,你應該使用像componentWillMount之類的東西,並在該方法中,分配屬性this。這將確保這些數據僅在特定實例上,而不在原型鏈上。

編輯

爲了進一步clearify,它可以很好的瞭解,傳遞給React.createClass()的對象不是在原型上實際的對象。 React做的是迭代該對象的所有屬性,並將它們複製到React元素對象的原型中。

var obj = { 
    myArray: [1, 2, 3], 
    title: 'My title', 
    componentWillMount() { 
    this.myArray.push(this.myArray.length + 1); 
    }, 
    render() { 
    return (
     <span>{this.myArray.length}</span> 
    ); 
    } 
} 

var MyComponent = React.createClass(obj); 

// This doesn't change the component, since 'obj' isn't used anymore 
// by React, it has already copied all properties. 
obj.title = 'New title'; 

// This however affects the component, because the reference to the array 
// was copied to the component prototype, and any changes to what the 
// reference points to will affect everyone who has access to it. 
obj.myArray.push(666); 
+0

感謝您的快速回復anders!在「componentWillMount」函數中爲「this」分配屬性對我來說聽起來頗爲「駭人聽聞」。但以同樣的方式,在我的用例中,變量也不會感覺像組件的道具或狀態。在我的情況下,我有一個處於狀態的消息數組,並且希望創建一個消息索引以更快地訪問它們或更快地檢查它們的存在(messagesIndex)。我會給你另一個例子:http://jsbin.com/guwipeyubu/1/edit?html,js,console,output – delijah

+1

是的,它的感覺hackish的原因是,它不是很習慣,而不是你「應該做的。我無法真正瞭解你的榜樣應該做什麼,但作爲一般的經驗法則;如果數據是應該由組件呈現的東西,那它肯定應該是一個道具或國家的一部分。如果它不是應該呈現的東西(即在render方法中使用),它可能不屬於組件。 –

+0

請接受這個答案,如果它滿意地處理您的問題。順便說一句,它是一個很好的答案。 – hazardous