• 不使用 ES6
    • 声明默认属性
    • 初始化 State
    • 自动绑定
    • Mixins

    不使用 ES6

    通常我们会用 JavaScript 的 class 关键字来定义 React 组件:

    1. class Greeting extends React.Component {
    2. render() {
    3. return <h1>Hello, {this.props.name}</h1>;
    4. }
    5. }

    如果你还未使用过 ES6,你可以使用 create-react-class 模块:

    1. var createReactClass = require('create-react-class');
    2. var Greeting = createReactClass({
    3. render: function() {
    4. return <h1>Hello, {this.props.name}</h1>;
    5. }
    6. });

    ES6 中的 class 与 createReactClass() 方法十分相似,但有以下几个区别值得注意。

    声明默认属性

    无论是函数组件还是 class 组件,都拥有 defaultProps 属性:

    1. class Greeting extends React.Component {
    2. // ...
    3. }
    4. Greeting.defaultProps = {
    5. name: 'Mary'
    6. };

    如果使用 createReactClass() 方法创建组件,那就需要在组件中定义 getDefaultProps() 函数:

    1. var Greeting = createReactClass({
    2. getDefaultProps: function() {
    3. return {
    4. name: 'Mary'
    5. };
    6. },
    7. // ...
    8. });

    初始化 State

    如果使用 ES6 的 class 关键字创建组件,你可以通过给 this.state 赋值的方式来定义组件的初始 state:

    1. class Counter extends React.Component {
    2. constructor(props) {
    3. super(props);
    4. this.state = {count: props.initialCount};
    5. }
    6. // ...
    7. }

    如果使用 createReactClass() 方法创建组件,你需要提供一个单独的 getInitialState 方法,让其返回初始 state:

    1. var Counter = createReactClass({
    2. getInitialState: function() {
    3. return {count: this.props.initialCount};
    4. },
    5. // ...
    6. });

    自动绑定

    对于使用 ES6 的 class 关键字创建的 React 组件,组件中的方法遵循与常规 ES6 class 相同的语法规则。这意味着这些方法不会自动绑定 this 到这个组件实例。 你需要在 constructor 中显式地调用 .bind(this)

    1. class SayHello extends React.Component {
    2. constructor(props) {
    3. super(props);
    4. this.state = {message: 'Hello!'};
    5. // 这一行很重要!
    6. this.handleClick = this.handleClick.bind(this);
    7. }
    8. handleClick() {
    9. alert(this.state.message);
    10. }
    11. render() {
    12. // 由于 `this.handleClick` 已经绑定至实例,因此我们才可以用它来处理点击事件
    13. return (
    14. <button onClick={this.handleClick}>
    15. Say hello
    16. </button>
    17. );
    18. }
    19. }

    如果使用 createReactClass() 方法创建组件,组件中的方法会自动绑定至实例,所以不需要像上面那样做:

    1. var SayHello = createReactClass({
    2. getInitialState: function() {
    3. return {message: 'Hello!'};
    4. },
    5. handleClick: function() {
    6. alert(this.state.message);
    7. },
    8. render: function() {
    9. return (
    10. <button onClick={this.handleClick}>
    11. Say hello
    12. </button>
    13. );
    14. }
    15. });

    这就意味着,如果使用 ES6 class 关键字创建组件,在处理事件回调时就要多写一部分代码。但对于大型项目来说,这样做可以提升运行效率。

    如果你觉得上述写法很繁琐,那么可以尝试使用目前还处于试验性阶段的 Babel 插件 Class Properties。

    1. class SayHello extends React.Component {
    2. constructor(props) {
    3. super(props);
    4. this.state = {message: 'Hello!'};
    5. }
    6. // 警告:这种语法还处于试验性阶段!
    7. // 在这里使用箭头函数就可以把方法绑定给实例:
    8. handleClick = () => {
    9. alert(this.state.message);
    10. }
    11. render() {
    12. return (
    13. <button onClick={this.handleClick}>
    14. Say hello
    15. </button>
    16. );
    17. }
    18. }

    请注意,上面这种语法目前还处于试验性阶段,这意味着语法随时都可能改变,也存在最终不被列入框架标准的可能。

    为了保险起见,以下三种做法都是可以的:

    • 在 constructor 中绑定方法。
    • 使用箭头函数,比如:onClick={(e) => this.handleClick(e)}
    • 继续使用 createReactClass

    Mixins

    注意:

    ES6 本身是不包含任何 mixin 支持。因此,当你在 React 中使用 ES6 class 时,将不支持 mixins 。

    我们也发现了很多使用 mixins 然后出现了问题的代码库。并且不建议在新代码中使用它们。

    以下内容仅作为参考。

    如果完全不同的组件有相似的功能,这就会产生“横切关注点(cross-cutting concerns)“问题。针对这个问题,在使用 createReactClass 创建 React 组件的时候,引入 mixins 功能会是一个很好的解决方案。

    比较常见的用法是,组件每隔一段时间更新一次。使用 setInterval() 可以很容易实现这个功能,但需要注意的是,当你不再需要它时,你应该清除它以节省内存。React 提供了生命周期方法,这样你就可以知道一个组件何时被创建或被销毁了。让我们创建一个简单的 mixin,它使用这些方法提供一个简单的 setInterval() 函数,它会在组件被销毁时被自动清理。

    1. var SetIntervalMixin = {
    2. componentWillMount: function() {
    3. this.intervals = [];
    4. },
    5. setInterval: function() {
    6. this.intervals.push(setInterval.apply(null, arguments));
    7. },
    8. componentWillUnmount: function() {
    9. this.intervals.forEach(clearInterval);
    10. }
    11. };
    12. var createReactClass = require('create-react-class');
    13. var TickTock = createReactClass({
    14. mixins: [SetIntervalMixin], // 使用 mixin
    15. getInitialState: function() {
    16. return {seconds: 0};
    17. },
    18. componentDidMount: function() {
    19. this.setInterval(this.tick, 1000); // 调用 mixin 上的方法
    20. },
    21. tick: function() {
    22. this.setState({seconds: this.state.seconds + 1});
    23. },
    24. render: function() {
    25. return (
    26. <p>
    27. React has been running for {this.state.seconds} seconds.
    28. </p>
    29. );
    30. }
    31. });
    32. ReactDOM.render(
    33. <TickTock />,
    34. document.getElementById('example')
    35. );

    如果组件拥有多个 mixins,且这些 mixins 中定义了相同的生命周期方法(例如,当组件被销毁时,几个 mixins 都想要进行一些清理工作),那么这些生命周期方法都会被调用的。使用 mixins 时,mixins 会先按照定义时的顺序执行,最后调用组件上对应的方法。