Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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({ ?

like image 877
Bomber Avatar asked Mar 12 '23 19:03

Bomber


2 Answers

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>;
}
like image 173
Dan Prince Avatar answered Mar 16 '23 04:03

Dan Prince


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.

like image 43
Kos Avatar answered Mar 16 '23 03:03

Kos