React Without ES6

一般来说,会将React组件定义为JavaScript的类(class):

  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的classAPI和createReactClass()很相似,不过也有一些不同。


声明默认的Props

无论使用 function 还是 ES6 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. });

设定初始状态

通过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. });

自动绑定(Autobinding)

如果通过ES6的class声明的组件,其中的方法遵循ES6的class中相同的语义,因此他们不会自动绑定到实例上。所以必须在构造函数中使用.bind(this)绑定到实例上。

  1. class SayHello extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {message: 'Hello!'};
  5. // This line is important!
  6. this.handleClick = this.handleClick.bind(this);
  7. }
  8. handleClick() {
  9. alert(this.state.message);
  10. }
  11. render() {
  12. // Because `this.handleClick` is bound, we can use it as an event handler.
  13. return (
  14. <button onClick={this.handleClick}>
  15. Say hello
  16. </button>
  17. );
  18. }
  19. }

如果通过,createReactClass(),则不需要将所有的方法绑定到this:

  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类构建组件,会增加一些样板代码,但是在大型的应用程序中,上升空间会好一些。

如果样板代码有一些无法接受,你可以使用Babel的实验性语法Class Properties来解决:

  1. class SayHello extends React.Component {
  2. constructor(props) {
  3. super(props);
  4. this.state = {message: 'Hello!'};
  5. }
  6. // WARNING: this syntax is experimental!
  7. // Using an arrow here binds the method:
  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. }

请注意,这种语法是实验性的,语法可能会改变,或者该提案不会进入语言的标准。

如果想要安全的使用事件处理函数,你有几个的选择:

  • 在构造函数中绑定事件处理方法

  • 使用箭头函数的功能,如:onClick={(e) => this.handleClick(e)}

  • 继续使用 createReactClass


Mixins

注意: ES6不支持mixin,因此,如果组件使用ES6 class构建,则不支持使用 mixins

我们在使用mixins的库中也发现了很多问题,不建议在新的代码中使用这些

本节仅供参考

有时候有很大不同的组件可能会共享一些常见的功能。有时称为cross-cutting concernscreateReactClass可以允许你使用传统的mixins.

一种简单的情况是希望在一段时间内更新自己的组件。虽然使用setInterval()能够简单的实现,但是当你不需要它并且要节省内存时,清楚这个定时器非常重要。

React提供生命周期函数,让你知道组件何时创建和销毁。可以创建一个简单的mixins,使用这些方法提供一个简单的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], // Use the mixin
  15. getInitialState: function() {
  16. return {seconds: 0};
  17. },
  18. componentDidMount: function() {
  19. this.setInterval(this.tick, 1000); // Call a method on the 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,并且多个mixin定义了相同的生命周期方法(即,组件被销毁时,几个mixin需要进行一些清理工作),所有的生命周期方法都会被调用。所有定义的mixin的方法列表,都会在组件中被调用。