面试题:React.createClass 和 extends Component 有哪些区别?

React.createClass 与 extends Component 的区别

这是 React 发展过程中的一个重要变化,主要体现在 React 15.5 版本之前和之后的写法差异。

1. 语法定义区别

React.createClass (旧版)

// React 15.5 之前的写法
const MyComponent = React.createClass({
  // 必须定义 getInitialState
  getInitialState: function() {
    return {
      count: 0
    };
  },

  // 自动绑定 this
  handleClick: function() {
    this.setState({ count: this.state.count + 1 });
  },

  render: function() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
});

extends Component (新版)

// React 15.5 及之后的写法
class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    // 在构造函数中初始化 state
    this.state = {
      count: 0
    };
    // 需要手动绑定 this
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({ count: this.state.count + 1 });
  }

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

2. 主要区别详解

2.1 状态初始化

React.createClass:

const Component = React.createClass({
  getInitialState: function() {
    return { name: 'John' };
  }
});

extends Component:

class Component extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: 'John' };
  }
}

2.2 this 绑定

React.createClass – 自动绑定:

const Component = React.createClass({
  handleClick: function() {
    // this 自动绑定到组件实例
    console.log(this); // 组件实例
  },

  render: function() {
    return <button onClick={this.handleClick}>Click</button>;
  }
});

extends Component – 需要手动绑定:

class Component extends React.Component {
  constructor(props) {
    super(props);
    // 方式1:在构造函数中绑定
    this.handleClick = this.handleClick.bind(this);
  }

  // 方式2:使用类属性+箭头函数 (实验性语法,需要 Babel)
  handleClick = () => {
    console.log(this); // 组件实例
  }

  // 方式3:在 render 中绑定
  render() {
    return (
      <div>
        <button onClick={this.handleClick.bind(this)}>Click</button>
        {/* 或使用箭头函数 */}
        <button onClick={() => this.handleClick()}>Click</button>
      </div>
    );
  }
}

2.3 Props 类型验证

React.createClass:

const Component = React.createClass({
  propTypes: {
    name: React.PropTypes.string,
    age: React.PropTypes.number
  },

  getDefaultProps: function() {
    return {
      name: 'Anonymous',
      age: 18
    };
  }
});

extends Component:

class Component extends React.Component {
  static propTypes = {
    name: PropTypes.string,
    age: PropTypes.number
  };

  static defaultProps = {
    name: 'Anonymous',
    age: 18
  };
}

// 或者写在类外部
Component.propTypes = {
  name: PropTypes.string,
  age: PropTypes.number
};

Component.defaultProps = {
  name: 'Anonymous',
  age: 18
};

2.4 Mixins 支持

React.createClass – 支持 mixins:

const LogMixin = {
  componentDidMount: function() {
    console.log('Component mounted');
  }
};

const Component = React.createClass({
  mixins: [LogMixin],
  // ...
});

extends Component – 不支持 mixins:

// 不支持 mixins,需要使用高阶组件或 Render Props
const withLogging = (WrappedComponent) => {
  return class extends React.Component {
    componentDidMount() {
      console.log('Component mounted');
    }

    render() {
      return <WrappedComponent {...this.props} />;
    }
  };
};

class Component extends React.Component {
  // ...
}

export default withLogging(Component);

3. 生命周期方法差异

React.createClass

const Component = React.createClass({
  // 已废弃的生命周期
  componentWillMount: function() {},
  componentWillReceiveProps: function() {},
  componentWillUpdate: function() {},

  render: function() {
    return <div>Hello</div>;
  }
});

extends Component

class Component extends React.Component {
  // 新的生命周期(React 16.3+)
  static getDerivedStateFromProps(props, state) {
    // 返回更新的 state 或 null
    return null;
  }

  getSnapshotBeforeUpdate(prevProps, prevState) {
    // 在 DOM 更新前调用
    return null;
  }

  componentDidUpdate(prevProps, prevState, snapshot) {
    // 使用 getSnapshotBeforeUpdate 的返回值
  }

  render() {
    return <div>Hello</div>;
  }
}

4. 性能差异

React.createClass:

  • 包含更多的包装和检查
  • 性能稍差
  • 体积更大

extends Component:

  • 更接近原生 JavaScript 类
  • 性能更好
  • 体积更小

5. 现代 React 中的写法

使用 Hooks (React 16.8+)

import React, { useState } from 'react';

function MyComponent() {
  const [count, setCount] = useState(0);

  const handleClick = () => {
    setCount(count + 1);
  };

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={handleClick}>Increment</button>
    </div>
  );
}

使用类组件 (当前标准)

class MyComponent extends React.Component {
  state = {
    count: 0
  };

  handleClick = () => {
    this.setState({ count: this.state.count + 1 });
  };

  render() {
    return (
      <div>
        <p>Count: {this.state.count}</p>
        <button onClick={this.handleClick}>Increment</button>
      </div>
    );
  }
}

6. 迁移建议

从 React.createClass 迁移到 extends Component

// 旧代码
const OldComponent = React.createClass({
  getInitialState: function() {
    return { name: 'John' };
  },

  handleClick: function() {
    this.setState({ name: 'Jane' });
  },

  render: function() {
    return <button onClick={this.handleClick}>{this.state.name}</button>;
  }
});

// 新代码
class NewComponent extends React.Component {
  constructor(props) {
    super(props);
    this.state = { name: 'John' };
    this.handleClick = this.handleClick.bind(this);
  }

  handleClick() {
    this.setState({ name: 'Jane' });
  }

  render() {
    return <button onClick={this.handleClick}>{this.state.name}</button>;
  }
}

7. 总结对比表

特性React.createClassextends Component
语法工厂函数ES6 类
状态初始化getInitialState()constructor() 中的 this.state
this 绑定自动绑定需要手动绑定
PropTypes在对象内部定义静态属性或类外部定义
defaultPropsgetDefaultProps()静态属性
Mixins 支持支持不支持
性能稍差更好
推荐使用已废弃推荐(或使用函数组件+Hooks)

8. 最佳实践

  1. 新项目:使用函数组件 + Hooks
  2. 现有类组件:使用 extends Component 语法
  3. 避免使用React.createClass(已废弃)
  4. 绑定处理:使用类属性箭头函数或构造函数绑定
  5. 状态管理:考虑使用 Hooks 替代类组件状态

React 团队已经明确表示 React.createClass 已被废弃,建议所有新项目使用函数组件和 Hooks,或者至少使用 ES6 类组件语法。

THE END
喜欢就支持一下吧
点赞15 分享