ReactJs组件语法,有何不同?

4

我正在学习Reactjs,并试图编写一个基本组件,有人可以告诉我为什么这个组件的语法是这样的:

import React, { Component } from 'react';
export default class AboutPage extends Component {
render: function() {
    const { page } = this.props;
    return (
        <div className="blog-post">
            <h2 className="blog-post-title">{page.title.rendered}</h2>
            <div dangerouslySetInnerHTML={this.createMarkup(page.content.rendered)} />
        </div>
    );
  }
}

这个组件不同于其他组件吗?
var HelloMessage = React.createClass({
render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

为什么要使用export default class而不是只使用var HelloMessage = React.createClass({


"instead of just" --- 它们并不是可以互换的。 - zerkms
3个回答

3

首先,还有一种选项您没有提到:

export default function AboutPage(props) {
  const { page } = props;
  const pageContentMarkup = createMarkup(page.content.rendered);
  return (
    <div className="blog-post">
      <h2 className="blog-post-title">{page.title.rendered}</h2>
      <div dangerouslySetInnerHTML={pageContentMarkup} />
    </div>
  );

这个代码非常简洁,强调了你的组件是无状态的。

其次,类语法显然不允许使用mixin。有人说这是一个特性,而不是一个bug,我们实际上应该远离mixin。

Dan Abramov提出,mixin不太容易组合,提出了高阶组件作为替代品。 "高阶组件"是一个复杂的术语,指的是一个函数,它接受一个React组件类并返回另一个添加了某些行为的类。 高阶组件可以被看作是“装饰器”。 您将它们按顺序应用于组件,它们将各自执行自己的任务,甚至不需要知道彼此的存在。

这看起来是放弃旧语法并使用类的好理由。


值得一提的是,你不能直接完全使用这个,因为它使用了 this.createMarkup。你需要将该方法从实例中移除,并在某处明确定义为一个函数。 - Dan Prince
@DanPrince 抱歉,我漏掉了那个 this。谢谢提醒!已经修改。 - Kos

3
“createClass”语法是创建React组件的最初方法,但现在看来正在逐渐被“class”语法和无状态函数式组件所取代。如果您想要将一个组件从“createClass”升级到“class”,那么需要注意一些关键的区别。

初始状态与默认属性

使用“createClass”,您可以声明方法来返回给定组件的初始状态和默认属性。
React.createClass({
  getInitialState() {
    return { foo: 'bar' };
  },
  getDefaultProps() {
    return { baz: 'qux' };
  },
  componentDidMount() {
    console.log(
      this.state, // => { foo: 'bar' }
      this.props  // => { baz: 'qux' }
    );
  }
});

两者都已经针对类语法进行了更改。相反,你需要在构造函数内分配初始状态。

class extends React.Component {
  constructor() {
    super();
    this.state = { foo: 'bar' };
  }
}

你需要将默认属性声明为静态属性。

class Qux extends React.Component {}
Qux.defaultProps = { baz: 'qux' };

混合

createClass 语法支持一种叫做混合的概念,它允许您提供其他代码来增强现有的生命周期方法。

const logOnMount = {
  componentWillMount() {
    console.log('Mounted!', new Date());
  }
};

React.createClass({
  mixins: [logOnMount]
});

任何使用logOnMount mixin的组件,每次挂载时都会将时间戳记录到控制台。 class语法不支持混入(mixins),但您可以使用高阶组件(higher-order components)来实现相同的功能。
function logOnMount(Component) {
  return function(props) {
    console.log('Mounted!', new Date());
    return (
      <Component {...props} />
    );
  }
}

自动绑定

createClass语法提供了一些方便的自动绑定方法,这样您就可以安全地将组件方法作为回调传递,并不必担心this上下文出现错误。

React.createClass({
  bar() {
    return true;
  },
  foo() {
    this.bar();
  },
  render() {
    return <button onClick={this.foo}>Click</button>;
  }
});

onClick处理程序将尝试使用触发的事件作为this来调用this.foo,但是由于this.foo已经自动绑定了正确的上下文,所以不会出错。

以下是相同的示例,但使用类。

class extends React.Component {
  bar() {
    return true;
  }
  foo() {
    this.bar(); // Error - undefined is not a function
  }
  render() {
    return <button onClick={this.foo}>Click</button>;
  }
}

foo方法最终将this设置为事件,该事件没有bar属性。

为了解决这个问题,您需要在构造函数中显式地绑定方法,或者从箭头函数内部调用该方法。

constructor() {
  this.foo = this.foo.bind(this);
}

// or

render() {
  return <button onClick={e => this.foo()}>Click</button>;
}

"class extends..."是ES6的,还是ES5也可以使用吗? - Tikkes
这只是一个匿名的Es6类。 - Dan Prince

1

class语法是ES2015中的新特性,您可以在MDN上了解它。

React.createClass函数存在是因为ES2015之前的JavaScript不支持类。

对于React来说,有一些具体的差异,详见react文档,但个人建议如果可以使用新的类语法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接