2016-07-31 42 views
1

我完全新手到ReactJS並沒有當我創建了一個有些奇怪的行爲反應用ReactJS在狀態ES6類:改變只有一次

https://jsfiddle.net/8f5tqr74/2/

class CounterViewModel { 
    constructor() { 
     this.value = 5; 
    } 

    tick() { 
     //cannot move logic of this method to sendTick complex logic will be here 
     this.value++; 
    } 

} 

var Counter = React.createClass({ 
    getInitialState: function() { 
     return new CounterViewModel(); 
    }, 

    sendTick: function() { 
     console.log("Before:",this.state); 

     var stateObj = this.state; 
     stateObj.tick(); 
     this.setState(stateObj); 
     console.log("After:",this.state); 
    }, 

    render: function() { 
     return <div> 
      {this.state.value} 
      <button onClick={this.sendTick}>Increase</button> 
     </div> 
    } 


}); 


ReactDOM.render(<Counter />, document.getElementById('container')); 

我的問題是 此代碼工作當我點擊按鈕 只有我第一次得到這個開發者控制檯

//first click 
Before: CounterViewModel {value: 5} 
After: CounterViewModel {value: 6} 
//second click 
Before: Object {value: 6} 

在第二次點擊後CLAS狀態s是刷新到對象,但我沒有在這個對象使操作

我的問題是:

1)爲什麼的setState後作出反應沖洗類對象的?

2)爲什麼在getInitialState後沒有React flush類對象?

3)如何將複雜的邏輯放入React中的狀態對象?我知道我可以重新創建對象,具有更高的價值和一切都將正常工作(見下面的代碼)

class CounterViewModel { 
    constructor(value) { 
     this.value = value; 
    } 
} 

var Counter = React.createClass({ 
    getInitialState: function() { 
     return new CounterViewModel(5); 
    }, 

    sendTick: function() { 
     this.setState(new CounterViewModel(this.state.value+1)) 
    }, 

    render: function() { 
     return <div> 
      {this.state.value} 
      <button onClick={this.sendTick}>Increase</button> 
     </div> 
    } 


}); 


ReactDOM.render(<Counter />, document.getElementById('container')); 

回答

2

陣營預計state是一個簡單的JS對象,這就是爲什麼你叫setState()後,它成爲一個對象的原因。

此外,setState不會立即發生變異this.state,這意味着當它在你的代碼打印

After: CounterViewModel {value: 6} 

state並沒有真正改變,如果您移動的console.log()回調函數的setState就像這個jsfiddle,你會發現,狀態變化後,state成爲一個普通的對象

Before: CounterViewModel {value: 5} 
After: Object {value: 6} 

那麼你如何解決這個問題?

你必須使用一個普通的對象作爲state,你必須把它當作一個不變對象。

var Counter = React.createClass({ 
    getInitialState: function() { 
     return {counter: new CounterViewModel()} 
    }, 

    sendTick: function() { 
     var stateObj = Object.assign(new CounterViewModel(),this.state.counter); // Deep clone 
     stateObj.tick(); 
     this.setState({counter: stateObj}); 
    }, 

    render: function() { 
     console.log(this.state); 
     return <div> 
      {this.state.counter.value} 
      <button onClick={this.sendTick}>Increase</button> 
     </div> 
    } 


}); 

working jsfiddle

+0

我建議您不要將可變計數器實例直接存儲在組件狀態中。相反,只需將計數器的「value」屬性複製到組件狀態 – naomik

+0

即可!但是這不符合第三個問題:「我怎樣才能把複雜的邏輯放入React中的狀態對象中:-P – QoP

2

的保護級別是正確的,希望做出反應的狀態是一種香草JavaScript對象。在我的回答偏離他/她的地方是我不會將CounterViewModel實例複製到組件的狀態。

它像你一樣使用獨立的類,所以與它進行交互會有點難看。爲什麼您使用class語法來處理其他代碼,但React組件的舊React語法?

import {Component} from 'react' 

class Counter extends Component { 
    constructor (props) { 
    // call parent constructor 
    super(props) 
    // create an instance of counter view model 
    // save it as a normal instance property (not the same as `this.props`) 
    this.counter = new CounterViewModel() 
    // set initial state using the instance's counter value 
    // do NOT copy the counter object directly to state 
    this.state = { counter: this.counter.value } 
    } 
    sendTick (event) { 
    // mutate your counter object 
    this.counter.tick() 
    // set the component state with the counter's value 
    this.setState({ counter: this.counter.value }) 
    } 
    render() { 
    return (
     <div> 
     {this.state.value} 
     // note the slight difference in the way I set onClick 
     // read more: https://facebook.github.io/react/blog/2015/01/27/react-v0.13.0-beta-1.html#autobinding 
     <button onClick={e=> this.sendTick(e)}>Increase</button> 
     </div> 
    ) 
    } 
} 

export default Counter