Closed jordwalke closed 10 years ago
Yes! High on my personal wishlist :-). Op 26 nov. 2013 06:41 schreef "Jordan W" notifications@github.com:
Let's use ES6 classes to create React component classes. We've accumulated some custom concepts that don't lend themselves to using ES6 classes but we can still use them in conjunction with React components as ES6 classes, if the separation is performed as "enhancers" on top of completely pure ES6 classes:
class Typeahead extends ReactComponent { render() {
} }
// Enhancers ReactComponent ReactComponent.autoBindMethods(Typeahead); ReactComponent.validatePropTypes(Typeahead);
module.exports = Typeahead;
-
Blockers:
- Probably want to call the base class ReactComponent even though the base class of our components today is called ReactCompositeComponent. We just need to rename ReactCompositeComponent to ReactComponentand ReactComponent to ReactComponentBase.
- Right now React.createClass doesn't return the constructor. It returns the "convenience constructor" which can be invoked without new. We can unify the two concepts and eliminate convenience constructors altogether.
- Determine how to support autobinding (likely an "enhancer" as shown above).
- Get rid or (or figure out way to abstract out) special proprietary handling of overridden methods like componentWillMount, componentWillReceiveProps - there aren't classical OO equivalents.
- Of these proprietary handlers, some are for the purpose of validation (preventing people from overriding base class methods). Others add actual functionality. We can do whatever we have to to ensure validation, but the additional functionality should be factored out of the class hierarchy, into special "enhancers" as I've hinted at at the bottom of the previous example. It should be possible to program with pure, straight up ES6 classes.
- The main challenge with our proprietary handlers is how we allow multiple mixins to redefine properties, and ReactCompositeComponentwill attempt to intelligently merge their results. It is okay to factor all of that out into helper utilities, and we can supply a code mod that automatically updates your code that uses mixins.
This is a huge undertaking. Before anyone takes a shot at this - please lock down the API. For ES6 related questions, run ideas by @jeffmo https://github.com/jeffmo and @sebmarkbagehttps://github.com/sebmarkbagewho understand the direction of ES6. I'm happy to chat about the feasibility of potential changes to the React core, and practical ways to get started.
— Reply to this email directly or view it on GitHubhttps://github.com/facebook/react/issues/613 .
Just a heads up about some of the concerns regarding ES6 class support and how can can address them:
render
with inheritance that don't make sense and are addressed via simple composition). There's also risk of making mutation more convenient. It might make sense to start with ES6 classes simply as a better syntax for React component creation, intentionally limiting some use cases (limiting inheritance depth, making some React base class methods final) (only when used with React components of course - all non-React use of ES6 classes wouldn't be restricted).FWIW I've created a simple proof of concept using Traceur to transpile from ES6 class syntax to ES5: https://github.com/bjoerge/react-es6-class/
Passing source code with ES6 class syntax through React.transform seems to work pretty well (at least in this rather limited example), probably due to Esprima's experimental support for ES6.
:+1: since this will help work with other compile-to-javascript languages and frameworks such as typescript and F# (FunScript and WebSharper).
:+1:
+1
+1
One way to handle non-method properties of classes (mixins
, propTypes
, etc.) would be to use the speculative annotations that Angular is planning to use: https://docs.google.com/a/venmo.com/document/d/1uhs-a41dp2z0NLs-QiXYY-rqLGhgjmTf4iwBad2myzY/edit#heading=h.ambwele793xv
You then might end up w/ something like:
import {ReactComponent} from "react/ReactComponent";
import {WithMixins, PropValidate} from "react/util";
import props from "react/props";
import MyMixin from "app/components/MyMixin";
var props = {
myProp: props.fn.isRequired
};
@WithMixins(MyMixin)
@PropValidate(props)
class Component extends ReactComponent {
// ...
}
Of course, these won't actually be in ES6 (but are on the table for ES7), so you'd be introducing a required build step for this syntax (whether with Traceur's version or a sweetjs macro, etc). Devs who would like to opt-out of that step could either stick to React.createClass()
, or maybe use the syntax the original snippet showed, e.g.:
class Component extends ReactComponent {
// ...
}
Component.addMixins(MyMixin);
Component.propValidate(props);
:+1:
We can unify the two concepts and eliminate convenience constructors altogether.
:+1: people can be trusted with new
at this point.
special proprietary handling of overridden methods like componentWillMount, componentWillReceiveProps - there aren't classical OO equivalents.
super
should do the trick :
class ReactComponent{
componentWillMount(){
console.log('base implementation');
}
}
class Typeahead extends ReactComponent{
componentWillMount(){
super.componentWillMount();
// Additional implementation
}
}
or perhaps I am missing something.
see #1380
I'll close out this issue since most of the info here is stale.
Please don't use ES6 class or class inheritance at all, anywhere.
Specifically in the context of React, you'll be completely missing the point of reactive programming.
Super is a code-smell anywhere, but it's particularly abhorrent in reactive programming.
"Sometimes, the elegant implementation is just a function. Not a method. Not a class. Not a framework. Just a function." ~ John Carmack
I agree with @ericelliott, declare my components with classes feels so weird, using React.createClass feels sugar, the internals are abstracted in this function.
Maybe i'm missing something but are there good benefits for use ES6 classes in React?
At least i hope you dont deprecate createClass in the future
I agree that OO concepts such as super
and dynamic dispatch make code more difficult to reason about. Using JS ES6 classes could still be used just to group related functions together that operate on an expected form of data without needing to allocate separate instances of those functions per instance (using JS's prototype
- (which comes with all the dynamic dispatch downsides)). Accomplishing the same in JavaScript without in some way using prototype
would be difficult. Even in the pre-ES6 React form, React was still using prototypes, but we managed to ensure that people didn't abuse them. I believe it's possible to do the same with ES6 classes.
Export a factory instead of a class (like React does today), and you'll help users avoid a jungle full of pitfalls and gorillas.
@ericelliott Note that classic React factories created through createClass
are just OOP classes like ES6 classes. They support the same kind of inheritance through mixins. In fact, because it also supports multi-inheritance it opens up even more pitfalls. In fact, mixins is unfortunately seen as the primary way to do abstractions.
ES6 classes in React is not adding anything you couldn't already do. In fact it is constraining it further by encouraging object composition instead of mixins. It is an unfortunate marketing effect that this move is seen as encouraging OOP when it is really not.
My stance on progress in this space is that you can't take things away from developers until you've taught them the alternatives... at scale. (That includes myself.)
The class system provides an optional escape hatch when you need it rather than completely stopping you.
The primary feature that our class system provides is an "instance" handle this has several features.
1) It provides a certain level of familiarity and convenience. You can use this
as a middle man to refer to a group of arguments. This is a foot-gun but makes it easier to onboard new people.
2) The instance is an ID that you can use to refer to a place in the tree. It allows APIs like React.findDOMNode(component)
and third-party APIs that can unify around it.
3) It provides single or multiple inheritance features if someone needs to create an abstraction and just can't figure out how to do it using composition. This is unfortunately a very common problem.
If a developer can't figure out a way to do it, we don't want them to get stuck. Therefore, OOP is an escape hatch. At the same time we're trying to teach and encourage composition of components and higher order functions/components instead of OOP. You can still implement that on top of the class systems that we have. Then, when this practice is common enough, we can start deprecating old class systems.
However, we make that progress by teaching and encouragement - not by force.
As a phase two of this, we can start introducing more pure models. See the alternatives that we've been working on to replace "instances" as an abstraction model:
https://github.com/reactjs/react-future/blob/master/01%20-%20Core/03%20-%20Stateless%20Functions.js https://github.com/reactjs/react-future/tree/master/07%20-%20Returning%20State
As well as a declarative ways of updating state:
https://github.com/reactjs/react-future/tree/master/09%20-%20Reduce%20State
The stateless function example you linked is exactly how I want to write components! Ideally with PureRenderMixing behavior built in. Looking forward to that future.
@sebmarkbage I'm a little hazy on why you need class
to do any of that. Can you point me to examples of the instance handle use?
RE: provide inheritance options, see Prototypal Inheritance with Stamps.
There's currently a project underway to make stamps produced by Stampit immutable, as well.
Re: pitfalls -- In my experience, single inheritance has many more pitfalls than Object.assign
style mixins.
RE: Stateless functions - :+1:
Hi, I referred to link https://github.com/reactjs/react-future/blob/master/01%20-%20Core/03%20-%20Stateless%20Functions.js
Is prop validation needed for stateless components. Or it's meaningless(and wrong) to put prop validation as these stateless components are merely the functions and for concept sake called " react's stateless component" ?
Is prop validation needed for stateless components
It's never required for any components, but unless you're already using Flow, we suggest you to put propTypes
on all components. It's not different for functional components:
const MenuItem = ({ title }) => <div>{title}</div>;
MenuItem.propTypes = {
title: React.PropTypes.string
};
@gaearon Thanks. I was wondering that these stateless functions(components) looks simply like functions so how come React treats them as components!! And also, am I correct in saying that these stateless functions don't have life cycle methods like DidComponentMount, etc as they don't extend 'React.Component'. Because presence/absence of state can't be the only difference between usual components and stateless function components.
I was wondering that these stateless functions(components) looks simply like functions so how come React treats them as components!!
Starting from 0.14, React allows components to be declared as functions. This is useful for simple components that have no lifecycle methods or state, and in the future React might apply certain optimizations to them (but not today).
Please read the announcement from 0.14 release notes.
@gaearon Thanks. Now I know that jsx files having simple functions are taken as components by React. Thanks that helped.
Well reading above comments I don't know how to tell this. I know you're just against using oop in react applications. Lets forget about oop and go with (quoting @jordwalke) "ES6 classes simply as a better syntax for React component creation". Just to make the syntax better is it possible to support inheritance? I think it'd be much cleaner syntax than wrappers and mixins.
Just to make the syntax better is it possible to support inheritance? I think it'd be much cleaner syntax than wrappers and mixins.
This is the kind of thinking you get when you use class
, because class
affords extends
like balls afford throwing and chairs afford sitting, and this is where that thinking leads.
I can't believe that somebody actually written that nonsense and I can't believe that it's being referenced. If he can't use/doesn't know how to use oop paradigms doesn't mean he should write something titled "Goodbye, Object Oriented Programming".
The kind of thinking you mentioned is the kind of thinking that has led to the browser you're using, operating system you're using, and more than one third of all software has written so far. That kind of thinking which is "to reuse" has its roots in modernism and even the car you drive, the hardware you run your software on, the airplane you travel with, the phone you have in your pocket are using it.
Good for the human being that it has reached to a level that class
affords extends
for it like balls afford throwing.
This thread is not about the validity or success of OOP. React classes already support inheritance if you want it, we just don't recommend it after our experience with it.
There's nothing technical to address here so I'd recommend taking the philosophical discussion to Medium, Twitter or a nice Facebook group.
I'm sorry that discussion happened here.
It'd be great if you support inheritance, currently it works but as you know there are some issues with it. Is it possible to plan to solve these issues and support inheritance officially if it's not taking too much effort? It'd result in much cleaner code if nothing else.
@sebmarkbage My apologies. I'm hopeful that we move toward more functional components in the future so that lots of React users don't have to relearn inheritance pitfalls the hard way.
For those who like classes and want to make the best use of them with React, @gaearon wrote an excellent guide, "How to Use Classes and Sleep at Night".
Perhaps it would be useful to mention inheritance and some of Dan's recommendations in the documentation to help guide people down paths toward success (HOC) and help them avoid some pitfalls?
Let's use ES6 classes to create React component classes. We've accumulated some custom concepts that don't lend themselves to using ES6 classes but we can still use them in conjunction with React components as ES6 classes, if the separation is performed as "enhancers" on top of completely pure ES6 classes:
ReactComponent
even though the base class of our components today is calledReactCompositeComponent
. We just need to renameReactCompositeComponent
toReactComponent
andReactComponent
toReactComponentBase
.React.createClass
doesn't return the constructor. It returns the "convenience constructor" which can be invoked withoutnew
. We can unify the two concepts and eliminate convenience constructors altogether.componentWillMount
,componentWillReceiveProps
- there aren't classical OO equivalents.ReactCompositeComponent
will attempt to intelligently merge their results. It is okay to factor all of that out into helper utilities, and we can supply a code mod that automatically updates your code that uses mixins.