matt
matt

Reputation: 1066

JSX vs component class instancing

Can somebody explain to me the difference between the following two statements?

let test1 = new CustomComponent();

and

let test2 = <CustomComponent />

The debugger is Chrome gives me:

for test1
CustomComponent {props: undefined, context: undefined, refs: Object, updater: Object, state: Object…}

for test2
Object {$$typeof: Symbol(react.element), key: null, ref: null, props: Object, type: function…}

And how can I get a variable of type of test2, from of variable of the type of test1 ?

Upvotes: 6

Views: 501

Answers (3)

Vasi
Vasi

Reputation: 1227

Case 1: let test1 = new CustomComponent();

In this case you have created an instance of a component. But this is not a React Instance. Your console output looks like an object, but this is not a React Component object. It's just like a instance of a class.

Case 2: let test2 = <CustomComponent />

In this case same things have happened. But React takes responsibility, that created instance of it as React Component object and render it.

You have obviously seen the difference between two outputs.

test2 output has type attribute with value of $$typeof: Symbol(react.element) .

But there is no type attribute in test1 output.

I hope your doubts is solved.

Upvotes: 2

Adam LeBlanc
Adam LeBlanc

Reputation: 962

So.

let test1 = new CustomComponent(); is just a regular javascript thing, same thing happens as calling new thing() any other time. Nothing special.

let test2 = <CustomComponent /> this is an JSX statement, and babel does some magic. It compiles <CustomComponent /> into React.createElement(CustomComponent , null). So, as you can see it is nothing like calling new, it's calling a React function that creates an element, that react knows how to deal with.

Babel has a REPL tool that you can use to see what it's doing to your source code if you ever want to see quickly what's going on under the hood.

Upvotes: 8

Chris
Chris

Reputation: 59531

These are two entirely different things, and I honestly cannot see any use case where you would be using the first case. But you sure ask an interesting question...

Finally, to create elements, use React.createElement(), JSX, or an element factory helper. Don’t write elements as plain objects in the real code—just know that they are plain objects under the hood.


new RequirementSection()

This creates an creates an instance of your class and that's pretty much it. You end up with a "dummy" class that doesn't have any of the React logic whatsoever, such as lifecycle methods.

This means that you would have to invoke each class method manually.

Demo:

In this demo we have two components, MyApp and Test. I've made the Test component so that when it's created a local flag variable is set to false, but before mounting, it's set to true.

As you can see, the flag doesn't get updated from the lifecycle and remains falsey.

class MyApp extends React.Component {
  render() {
    let test = new Test();
    return <div>{test.render()}</div>;
  }
}

class Test extends React.Component {
  constructor() {
    super();
    this.flag = false;
  }
  componentWillMount() {
    this.flag = true;
  }
  render() {
    return <div>{this.flag ? "flag is true" : "flag is false"}</div>;
  }
}


ReactDOM.render(<MyApp />, document.getElementById("myApp"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>


<RequirementSection />

As you probably know, this is the most common way of using React. This is JSX and basically translates into:

React.createElement(RequirementSection, null);`

Here, RequirementSection is the class object. What this returns is a ReactElement, which in contrast to the previous example, does include React logic.

Demo:

This demo is similar to the former one, with the difference that we are now using JSX to create a React Element, instead of just instancing a class object.

Indeed, the lifecycle method does run, and the component update the flag to true.

class MyApp extends React.Component {
  render() {
    let test = <Test />;
    return <div>{test}</div>;
  }
}

class Test extends React.Component {
  constructor() {
    super();
    this.flag = false;
  }
  componentWillMount() {
    this.flag = true;
  }
  render() {
    return <div>{this.flag ? "flag is true" : "flag is false"}</div>;
  }
}


ReactDOM.render(<MyApp />, document.getElementById("myApp"));
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="myApp"></div>


Further reading

You may find one of the following links interesting:

Upvotes: 2

Related Questions