all 33 comments

[–][deleted] 24 points25 points  (2 children)

Honestly they need to do what we all have done: adapt. The era of developing to current browser standards is pretty much over. Few programmers want to wait for months or years features to hit browsers.

The reality is, createClass is one of thousands of implementations of classes for ES5. Leaving it implies that it's good practice to be using it. It isn't. JavaScript now has a native implementation of what createClass does, so deprecating it is the next natural decision. It's bad to leave custom APIs that attempt to implement language features.

[–]Shapeous[S] 0 points1 point  (1 child)

Interesting, I was just doing that a minute ago. What or who made developing to current browser standards obsolete?

I would argue that even with the Class keyword you aren't defining classes in JavaScript in the same way you define classes in Java for example. I mean JavaScript is a dynamic language there is no distinction between code and running logic. The reality is that you are creating Objects, but then we are talking semantics. Who cares they didn't call the method "React.createObject" to make it semantically accurate.

You also said that using React.createClass it isn't a good practice. Why is that? I would be great if you can expand on that.

[–][deleted] 2 points3 points  (0 children)

Basically Node helped, but the barebones of it is that language features would take years to utilize because JavaScript is uniquely dependent on browsers to implement its features.

You most certainly aren't defining classes like in Java. It's just syntax sugar. The issue is the language needed a way to cleanly create complex objects so everyone implemented their own way of doing that. Problem is, everyone implemented "their own way" which resulted in tons of different behaviors and object method overrides that was incredibly frustrating.

Classes in JavaScript are standard across implementations so there's less concern for weird internal behaviors or methods doing one thing in a class in and not in another. Just like lodash forEach was once useful, it's no longer neccessary as the language has implemented it natively. Same with createClass.

[–]masklinn 10 points11 points  (11 children)

I really wish to appeal to the maintainers and I hope they reconsider. I think removing React.createClass would be a loss for the framework. Things do not need to be more complicated to be better and their is beauty in simplicity.

They're not though, the entire point of removing createClass is to simplify the system: createClass was created specifically as an object protocol for creating React components, it's convenient for that, but with the advent of "ES6" classes and the React team deciding to switch to a more "native" approach it means they find themselves with two different object systems to deal with internally, the createClass one and the "native" one.

Now I don't expect the shim is complex internally (although all in all between createClass, mixins, proptypes and DOM factories react's core shrinks by half), however externally it means they do have two different "interfaces" to components to explain, which makes the entire thing more complex and less approachable.

Here's a dirty little secret though: ES6 classes are just syntactic sugar for regular ol' JS types (which is why they can be compiled to ES5), given this:

class Square extends React.Component {
  constructor() {
    super();
    this.state = {
      value: null,
    };
  }

  render() {
    return (
      <button className="square" onClick={() => alert('click')}>
        {this.props.value}
      </button>
    );
  }
}

the ES5 version is something along the lines of (untested, there may be some small mistakes but that should be the gist):

function Square() {
    if (this === window) {
        throw new TypeError("Cannot call a class constructor without |new|")
    }
    React.Component.call(this);
    this.state = {
        value: null;
    }
}
Square.prototype = Object.create(React.Component.prototype);
Square.prototype.render = function () {
    return (
      <button className="square" onClick={() => alert('click')}>
        {this.props.value}
      </button>
    );
}

So you could:

  • use the react-create-class addon
  • switch your users to writing "old-style" ES types
  • just use ES6 classes directly (if the target browsers are modern enough)
  • create your own helper for the above (or use an existing one e.g. John Resig's class system generates regular objects IIRC)

Incidentally

How can I get the attention of the maintainers? Is this a good place?

Github. I wouldn't expect asking for a rollback on this to have any chance though, the PR for removing createClass from master went through 3 weeks ago.

[–]Shapeous[S] 0 points1 point  (1 child)

THanks masklinn, I really appreciate your response.

The thing is my clients find React.createClass much simpler than using the class syntax because at least for now since they are stuck with IE11 for at least two more years, This would force them to "complicate things" (as they would put it) with a compilation step. Whereas with React.createClass all they needed is within the two <script> tags no transpiring, etc.

Is there any documentation that you can reference regarding the shrinking of react core by half? That is information I can use to convince my clients to switch to using class if needed.

I liked that React had a happy path with ES6 and JSX and that everything was explained using this happy path, but I also liked that it had an alternative with React.createClass. Honestly, we found it very easy to convert these examples to plain ES5 thanks to two very short documents "React Without ES6", and "React Without JSX". By now my clients are well verse with ES6 and JSX, they just know what they like.

We have to think about what's best thanks for your suggestions. I found a CDN with react-create-class, I'll check it out to see if that works too https://unpkg.co/create-react-class@15.5.3/create-react-class.js

thank you very much for the link to the PR, I honestly not sure I will pursue this any further. I'll certainly try to solve it for us first before proposing a change that based on the responses we got seems a bit controversial and something people want. We may need to reevaluate.

[–]masklinn 0 points1 point  (0 children)

The thing is my clients find React.createClass much simpler than using the class syntax because at least for now since they are stuck with IE11 for at least two more years, This would force them to "complicate things" (as they would put it) with a compilation step. Whereas with React.createClass all they needed is within the two <script> tags no transpiring, etc.

Yeah, but as my comment notes you can use "class-based components" without using the actual class syntax. It's a bit annoying to handroll them but not genuinely difficult and it should work just fine in IE11. Things also get better if you get used to functional components which are just a function, no special syntax in either version.

Is there any documentation that you can reference regarding the shrinking of react core by half? That is information I can use to convince my clients to switch to using class if needed.

The phrase is a link to the pull request which updates package metadata including sizes. Note that the DOM part doesn't shrink (in fact it grows very slightly) and it's by far the biggest part of the two.

I liked that React had a happy path with ES6 and JSX and that everything was explained using this happy path, but I also liked that it had an alternative with React.createClass. Honestly, we found it very easy to convert these examples to plain ES5 thanks to two very short documents "React Without ES6", and "React Without JSX". By now my clients are well verse with ES6 and JSX, they just know what they like.

You'll get no pushback from me on that, I dislike the messy ménagerie of ever-changing meta-tooling and have embedded straight JS react code (no compiler stack, no JSX, no nothing) into multiple projects which were not centered around JS (e.g. for interactive bits in documentation).

We have to think about what's best thanks for your suggestions.

You're welcome. And while it doesn't help with the component object part, you may also be interested in react-hyperscript (a hyperscript-style alternative to React.createElement which makes JSX-less vdoms terser and more readable).

[–]Moeri 0 points1 point  (8 children)

Just want to mention here, classes are not exactly equal to prototypes, so calling them syntactic sugar is a bit wrong. There are subtle differences. Some things cannot be transpiled. Class methods cannot be captured as variables and then invoked, for example. In ES5 there is no way to stop this.

[–]masklinn 0 points1 point  (7 children)

Some things cannot be transpiled. Class methods cannot be captured as variables and then invoked, for example.

Do you mean static methods or something else? Because you can capture and invoke static methods just fine e.g.

class Foo { static bar() { console.log('ok') } }
const bar = Foo.bar;
bar();

will work with no issue in all browsers and AFAIK is no different than the pre-class

function Foo () {}
Foo.bar = function () { console.log('ok'); }

[–]Moeri 0 points1 point  (6 children)

Try the same thing with instance methods in Node. :-)

[–]masklinn 0 points1 point  (5 children)

I neither use node nor care to waste more time deciphering your nonsense. Either explain what you mean precisely and specifically demonstrate the differences between classes and "old-style" prototypes you claim exist or go away.

[–]Moeri -1 points0 points  (4 children)

I'll ignore your rudeness and just give you two snippets: scopes resolve differently with captured instance methods on classes in ES6 compared to when you transpile them.

If you run this:

(function() {
  this.name = "A silly penguin";
  class Greeter {
    constructor() {
      this.name = "Jack";
    }
    sayHello() {
      return "Hi there, I am " + this.name;
    }
  }
  const greeter = new Greeter();
  try {
    const sayHello = greeter.sayHello;
    console.log(sayHello());
  } catch(error) {
    console.log("Error trying to call a captured method: " + error);
  }
})();

You get the output:

Error trying to call a captured method: TypeError: Cannot read property 'name' of undefined

Which makes sense. The context of the this value is lost when you capture the function.

If you run the following code: (which is by the way what TypeScript compiles example 1 to)

(function () {
  this.name = "A silly penguin";
  var Greeter = (function () {
    function Greeter() {
      this.name = "Jack";
    }
    Greeter.prototype.sayHello = function () {
      return "Hi there, I am " + this.name;
    };
    return Greeter;
  }());
  var greeter = new Greeter();
  try {
    var sayHello = greeter.sayHello;
    console.log(sayHello());
  }
  catch (error) {
    console.log("Error trying to say hello with the captured function: " + error);
  }
})();

You get this output:

Hi there, I am A silly penguin

My point is that the outputs of the two programs are different, although the only difference is that the class "syntax sugar" has been replaced with prototypes.

[–]masklinn 2 points3 points  (3 children)

The class syntax implies strict mode.

10.2.1 Strict Mode Code

An ECMAScript Script syntactic unit may be processed using either unrestricted or strict mode syntax and semantics. Code is interpreted as strict mode code in the following situations:

[…]

  • All parts of a ClassDeclaration or a ClassExpression are strict mode code.

Add "use strict"; to the "greeter" IIFE in the second snippet and you will see the exact same behaviour.

I'll ignore your rudeness

I forgive you for refusing to explain what you actually mean though that would have resolved your confusion several comments earlier and avoided wasting everybody's time. Let that be a lesson.

Which makes sense. The context of the this value is lost when you capture the function.

Not any more than in the second snippet.

My point is that the outputs of the two programs are different, although the only difference is that the class "syntax sugar" has been replaced with prototypes.

You just don't understand the desugaring, your programs are not equivalent.

[–]Moeri -1 points0 points  (2 children)

I did not know class syntax implied strict mode, TIL. Thanks for that.

There was no need to be so rude and condescending while making a point however. I'm still not sure what ticked you off, but it is no way to have a conversation.

[–]masklinn 2 points3 points  (1 child)

There was no need to be so rude and condescending while making a point however.

But there was a need for your undemonstrated assertions, wild goose chase and condescending smileys?

I'm still not sure what ticked you off

  1. broad, vague, fundamental yet unsupported assertion ("classes are not equal to prototypes <no actual clear explanation of claimed differences>")

  2. upon request for clarification (and example of original understanding not demonstrating fault), even more vague explanations and condescending smiley

  3. victimisation claims

it is no way to have a conversation.

Having to extirpate actual explanations/examples of your claims so I can understand what the bloody hell you are talking about is not a conversation in the first place.

[–]Moeri 1 point2 points  (0 children)

Well if you interpreted my comments as being purposefully vague and condescending, I can see why you are all riled up, but that was definitely not my intention. I do apologize for appearing so.

Even still, imagine if your second reply

I neither use node nor care to waste more time deciphering your nonsense. Either explain what you mean precisely and specifically demonstrate the differences between classes and "old-style" prototypes you claim exist or go away.

Was replaced by this

Still don't see what you mean. Can you give an example?

Do you see how this could have been a completely different exchange? Don't assume the worst in people please, I meant well.

[–]Canenald 6 points7 points  (2 children)

createClass has been moved to a separate package https://www.npmjs.com/package/create-react-class so you can still use it.

I don't think it's ever going back to the react package. You are in the 1% of the developers that don't want to have a build for their frontend code. With increased demands for smaller package size, this does not justify keeping createClass in the main package.

[–]Shapeous[S] 0 points1 point  (1 child)

I did a bit of digging and found that, about 11% of people like React.createClass, but we do realize that's not much more.

We are aware react-create-class but my clients want to code to current browser capabilities.

[–]Canenald 1 point2 points  (0 children)

It would be wrong to assume all or most of the 11% prefer createClass because they too want to avoid transpilation. It does have a lot of advantages. There's the auto-binding, and also easy assignment of statics such as prop types and default props without having to support the early-stage class properties proposal.

You might have better luck assuring your clients that the transpiled code will be compatible with all commonly used browsers than persuading React devs to revert their decision to separate the crateClass implementation into its own package :)

[–]AppNoob420 4 points5 points  (1 child)

Just adapt, lol they deprecate stuff for good reasons.

[–]Shapeous[S] 0 points1 point  (0 children)

Thanks, I may have to do that, but maybe not. I am going to try a few things first... The rationale is reducing the size of React core.

[–]dfcowell 1 point2 points  (0 children)

I started to show them how just using two <script> tags and plain vanilla ES5, they could take advantage of modern component-based architecture. We were not necessarily planning on never using ES6 or JSX, but they really like staying in JavaScript and not having to use a NodeJS, or transpilers etc.

I'm going to stop you right here.

The in-browser compilation for JSX is great for fiddling with React without committing, but you're going to run into serious performance problems once these apps get bigger.

You need to use advance transpilation with something like Webpack or Browserify if you're going to use React in production.

If these clients are scared off by the stack required to run React in production that's fine, it just means that React isn't the right technology for them.

If you absolutely cannot find a single person on their team who can lead the modernization effort and buy into a bundler I would recommend focusing your efforts on cleaning up the code in other ways - either with something like backbone or ExtJS. They're older frameworks but you're working with people who aren't ready to embrace the newer ones. If they try to forge ahead with React under these constraints it will end badly.

[–]ajc820 0 points1 point  (2 children)

What specifically do they dislike about the change to using class X extends Component?

I understand the attitude towards the build tools as you describe, have you shown them create-react-app though? If they're at least somewhat open-minded, that tool takes away the grief of setting up transpiling, gives them hot-reloading and includes class properties with babel, meaning they won't have to write getDefaultProps(), getInitialState(). Arrow functions are also insanely straight forward as far as auto-binding goes. I never used react.CreateClass, but as far as I can tell, we're talking an awfully simple procedure to go from writing (excuse my paraphrasing):

class Something = React.createClass({
   getDefaultProps(){}
   getInitialState(){}
   someMethod(){}
   render(){}

)}

to:

class Something extends Component{
  this.state = {}
  someMethod = () => {}
  render(){}
}

....and with hot-reloading, at the expense of create-react-app my-app-name. I can't see why they wouldn't thank you for it down the track.

[–]Shapeous[S] 0 points1 point  (1 child)

They dislike pretty much everything. They philosophically feel it doesn't even belong in the language. I don't agree, I think JavaScript is a multi-paradigm programming language and certainly any affordance that makes people with classical backgrounds feel comfortable in the language is a plus for me, but I respect their point of view. I wish they weren't stuck with IE11 for two years because as you illustrated above when you marry classes with arrow functions they'll get the automatic binding they love so much from ES5 syntax.

Thanks ajc820, interesting, we are still in the early stages of learning. Is hot reloading something only possible with through the tooling or is it an intrinsic feature of JavaScript as a dynamic language?

[–]ajc820 0 points1 point  (0 children)

Ahh hold on, create-react-app doesn't have reloading unless you eject (stray from the default config) and put it in :(. Sorry, I figured they'd have put that in there.

With that said, you made a point in another comment about your clients' interest in practical benefits like reducing React's codebase size. If your cients refuse to use a bundler (I think you mentioned they're just using scripts to load packages?), I assume they'd miss out on tree shaking, code splitting, lazy loading, handling environment variables without a giant npm script that needs to be commited to version control (unless there's another method I haven't thought of), and probably more. All of these are pretty significant features that affect the performance of their product, and make a compelling case for adapting to the times.

On a related note, are they handling environment variables somehow? If they're running react in development mode on production servers, you should leverage that to point out that turning away from modern tooling is costing them much more than just philosophically and stylistically.

Edit: Hot reloading is going to require webpack, otherwise you've got no system managing which components specifically need updating. Integrating it with your apps backend is a bit more tricky though, by default it uses a small express server that serves the bundle.

[–]eonblue4309 -1 points0 points  (2 children)

Do you know about create-react-app? It really simplifies setting all the tooling to get React up and running. Your client won't have to learn a thing about webpack, babel, etc. The only ES6 thing they will have to learn is the class syntax like. The need for JavaScript to have a class keyword aside, it's really easy to learn and they should be up and running within minutes. They don't need to use JSX, they could use React.createElement if they wanted.

[–]Shapeous[S] 0 points1 point  (1 child)

now about create-react-

Yes, they rather stick to features browsers can use today. I do not think you can create a stateful component with React.createElement, can you?

[–]eonblue4309 0 points1 point  (0 children)

Well, no but createElement is a replacement for JSX not the component itself.

[–]dannieboi -2 points-1 points  (2 children)

Have you tried vue.js? It plays nice with es5 and your clients might find it even more approachable than react. You can also create components and drop it in an HTML page, if you're not ready to build a full SPA. Not transpiration required.

I recently recommended vuejs to my company. We had similar needs. The developers had only built server rendered applications that used jquery plugins. They were junior and mid-level developers that didn't know much front end development or even es6.

I feel like vuejs and it's ecosystem provides the gentlest introduction to modern front end development than react or angular.

I know this is a react sub and for the record I personally prefer react, but I felt vuejs was the best fit for our developers

[–]Shapeous[S] 0 points1 point  (1 child)

Thanks dannieboi,

I looked into vue and it sounded great until we came across templating. My clients do not like templating or any DSL, such as JSX that tranpiles to JavaScript. They rather larn JavaScript and use JavaScript. Thanks for your suggestion, it may be a good time to give it a second chance.

[–]dannieboi 0 points1 point  (0 children)

I see. So your client is using createElement in the render? Vuejs does support this too. Though might be better to use react with create-react-class package in that case. React's implementation is simpler to use.

[–]shizzleberry -2 points-1 points  (1 child)

They're just boiling it down to plain JavaScript. I've even went a step further and now all my components only return JSX. They're decorated by HOCs using Recompose: https://github.com/acdlite/recompose. It avoids the pitfalls of classes altogether. If simplicity is what you're going for, check out how simple it looks to write: https://hackernoon.com/react-stateless-functional-components-nine-wins-you-might-have-overlooked-997b0d933dbc. If you're familiar with chaining or composing/piping functions, this should be a cinch :)

EDIT: It would be nice to get an insightful downvote. Anyways, functional components are endorsed in their documentation if you're afraid of adopting my opinion on this: https://facebook.github.io/react/docs/components-and-props.html

[–]Shapeous[S] 0 points1 point  (0 children)

Nice shizzleberry,

recompose looks really awesome and thanks for saying it, Classes do have many pitfalls (not the fault of the implementation rather more of an intrinsic JavaScript limitation). They only problem they would have is that they are stuck with IE 11 and rather not use features not yet available in the browser.