Bomber
Bomber

Reputation: 10957

ReactJs component syntax, whats the difference?

I am learning Reactjs, I am trying to write a basic component, can anyone tell me why this component syntax:

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>
    );
  }
}

Is different to this component?

var HelloMessage = React.createClass({
render: function() {
    return <div>Hello {this.props.name}</div>;
  }
});

Why use export default class instead of just var HelloMessage = React.createClass({ ?

Upvotes: 4

Views: 196

Answers (3)

Kos
Kos

Reputation: 72261

First, there's also another option that you haven't mentioned:

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>
  );

This one is very terse and emphasises that your component is stateless.

Secondly, the class syntax notably doesn't allow using mixins. Some say this is a feature, not a bug, and we should actually move away from mixins.

Dan Abramov makes an argument that mixins don't compose well, and proposes higher order components as an alternative. "Higher order component" is a fancy term for a function that takes a React component class and returns another class that some behaviour added. Higher order components can be seen as "decorators". You apply them in order to a component and they will each still do their own thing without even needing to know about each other.

This looks like a good reason to leave behind the old syntax and move forward with classes.

Upvotes: 3

Dan Prince
Dan Prince

Reputation: 29989

The createClass syntax was the original way to create React components, but it seems like it's being phased out in favour of the class syntax and stateless functional components.

There are a few key differences to be aware of if you're upgrading a component from createClass a class.

Initial State & Default Props

With createClass you could declare methods that would return the initial state and default properties for a given component.

React.createClass({
  getInitialState() {
    return { foo: 'bar' };
  },
  getDefaultProps() {
    return { baz: 'qux' };
  },
  componentDidMount() {
    console.log(
      this.state, // => { foo: 'bar' }
      this.props  // => { baz: 'qux' }
    );
  }
});

Both have been changed for the class syntax. Instead, you assign your initial state inside the constructor.

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

And you declare the default props as a static property.

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

Mixins

The createClass syntax supports a concept called mixins, which allow you to provide other code which augments the existing lifecycle methods.

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

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

Any component using the logOnMount mixin will log a timestamp to the console whenever it is mounted.

There's no support for mixins with the class syntax, but you can use higher-order components to achieve the same things.

function logOnMount(Component) {
  return function(props) {
    console.log('Mounted!', new Date());
    return (
      <Component {...props} />
    );
  }
}

Autobinding

The createClass syntax provided some handy auto-binding so that you could safely pass component methods as callbacks and not have to worry about ending up with the wrong context for this.

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

The onClick handler will try and invoke this.foo with this set as the event that was triggered, but because this.foo was autobound to have the correct context, there's no error.

Here's the same example, but with classes.

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

The foo method ends up with this set to the event, which doesn't have a bar property.

To get around this, you'll need to explicitly bind the methods in the constructor, or invoke the method from inside an arrow function.

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

// or

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

Upvotes: 3

jonnystoten
jonnystoten

Reputation: 7133

The class syntax is new in ES2015, you can read about it on MDN.

The React.createClass function exists because javascript before ES2015 didn't have support for classes.

There are a couple of differences for react specifically, which are detailed in the react docs, but personally, I would use the new class syntax if you're able to.

Upvotes: 1

Related Questions