Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

关于初始化state的位置 #371

Open
HuaYJ1996 opened this issue Dec 30, 2019 · 0 comments
Open

关于初始化state的位置 #371

HuaYJ1996 opened this issue Dec 30, 2019 · 0 comments

Comments

@HuaYJ1996
Copy link

初始化state的方法

先说结论:state的初始化建议写在constructor中.

在阅读他人代码的过程中,发现了一种定义state的方式:

    export default class App extends Component {
        constructor(props) {
            super(props);
        }
        state = { key : true} // 看这里
        onClickBtn = () => {
            this.setState({
                key: !this.state.key
            })
        }
        render() {
            return (
                <div className="app-wrap">
                    <Button onClick={this.onClickBtn}>click</Button>
                    {this.state.key.toString()}
                </div>
            );
        }
    }

然而我所熟知的定义state的方法是酱婶的:

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {  // 看这里
            key : true
        }
    }
    onClickBtn = () => {
        this.setState({
            key: !this.state.key
        })
    }
    render() {
        return (
            <div className="app-wrap">
                <Button onClick={this.onClickBtn}>click</Button>
                {this.state.key.toString()}
            </div>
        );

}

经过一番缜密的思考(baidu)之后,发现它们在使用上并没有区别,同样可以使用this.setState方法去触发渲染.但是我总觉得事情没这么简单.

于是,在Babeljs上将两段代码执行之后的结果如下:

// 将state写在构造函数中
var App =
function (_Component) {
  _inherits(App, _Component);
  function App(props) {
    var _this;
    _classCallCheck(this, App);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(App).call(this, props));
    _this.state = { // 区别
      key: true
    };
    return _this;
  }
  _createClass(App, [{
    key: "render",
    value: function render() {
      return React.createElement("div", {
        className: "app-wrap"
      });
    }
  }]);
  return App;
}(Component);

// 将state定义为class的属性
var App =
function (_Component) {
  _inherits(App, _Component);
  function App(props) {
    var _this;
    _classCallCheck(this, App);
    _this = _possibleConstructorReturn(this, _getPrototypeOf(App).call(this, props));
    _defineProperty(_assertThisInitialized(_this), "state", { // 区别
      key: true
    });
    return _this;
  }
  _createClass(App, [{
    key: "render",
    value: function render() {
      return React.createElement("div", {
        className: "app-wrap"
      });
    }
  }]);
  return App;
}(Component);

可以看到两者的区别仅在于,前者使用_this.state={key:value}的形式定义属性,后者使用_defineProperty方法定义.而该方法的定义如下:

function _defineProperty(obj, key, value) {
    if (key in obj) {
        Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true });
    }
    else {
        obj[key] = value;
    }
    return obj;
}

可以看到,_defineProperty是利用Object.defineProperty方法将state属性和值赋给_this,这看起来和_this.state={key:value}没有区别.

为了寻找它们之间的优先级关系,有以下的代码:

class App extends Component {
    constructor(props) {
        super(props);
        this.state = {
            height : '1'
        }
        this.state = {
            width : '2'
        }
    }
    state = {
        length: '3'
    }
    state = {
        color: 'red'
    }
    render() {
        return (
            <div className="app-wrap">
                {JSON.stringify(this.state)}
            </div>
        );
    }
}

此时页面中显示的是{"width":"2"}.可知constructor中优先级较高.

类似的,经过一系列艰难(???)的实验得知,在constructor中定义的state的优先级高于class属性定义,同时,在各自的范围内,写在后面的定义会覆盖写在前面的定义.

综上,在代码混乱的情况下,作为属性定义的state有可能被construcor中的state覆盖掉.

总结:state的初始化建议写在constructor中.


Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant