ES6类处于状态的ReactJS:只更改一次

ReactJS with ES6 class in state: change only once

本文关键字:一次 于状态 ES6 状态 ReactJS      更新时间:2023-09-26

我对ReactJS完全陌生,当我创建计数器应用时,有一点奇怪的行为

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}

在第二次点击中,状态类被刷新到Object,但我没有在这个对象中进行操作

我的问题是:

1) 为什么React在setState之后刷新对象的类?

2) 为什么React不在getInitialState之后刷新类对象?

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

React期望state是一个普通的JS对象,这就是为什么在调用setState()后它会变成对象的原因。

此外,setState不会立即突变this.state,这意味着当它打印在代码中时

After: CounterViewModel {value: 6}

state并没有真正改变,如果你像这个jsfiddle一样将console.log()移动到setState的回调函数中,你会注意到在状态改变后,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>
    }

});

工作jsfiddle

QoP是正确的,React希望状态是一个普通的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