-
Notifications
You must be signed in to change notification settings - Fork 87
Support Functional Components #85
Support Functional Components #85
Conversation
This is extremely beneficial for having clearer fixtures with their purpose explicitly stated vs. having to guess what they're testing.
This makes functional components _insanely clean_ and possible to use components **between different VDOM implementations** as long as the function signature is (props, context).
\o/ cc @martinbigio :) |
I guess I won't go into detail again about how bad of an idea this is. People are clearly in love with the syntax and don't give a fuck about the problems here, which is shortsighted. So I'll just say 👎 and unsubscribe. |
@ericclemmons what exactly happens when the react-likeness-detection goes wrong? As far as I understand:
|
@thejameskyle Can you link to wherever you listed the cons of this approach? I'd like to know. Tx |
So basically the way to enable functional components hot reload support is to transform them into |
@mik01aj You're right on the money.
That last rule I think will get rid of almost every false positive, unless you have something terrible like That's why I advise either a major version bump or perhaps a transform option to opt-in to functional HMR. |
@inakianduaga He intentionally unsubscribed, so it'd be best to reach him through other channels, not yank him back into the thread :) |
@jasonslyvia That's correct. This would be
|
You mean, you analyze all the return paths of a function? |
One thing that may be a good idea is to:
I'll let @gaearon weigh in, since this is his project and he's the one who encouraged me to send a PR rather than continue on ericclemmons/babel-plugin-react-pure-to-class#1. |
@mik01aj Actually, I analyze just the top-level If there are other return paths, I don't look at them. The ideal scenario is this: const Greeting = ({ message }) => (
<h1>Howdy there, {message}!</h1>
);
export default Greeting; This removes almost all ambiguity & complexity in parsing. If you had a terrible function like the one below, you'd lose out on HMR, but in no way can this be bulletproof :) const Greeting = ({ message }) => {
if (message) {
return <h1>Howdy there, {message}!</h1>;
}
return false;
} Should this be merged in, there'd be an explicit recommendation in the |
Great constructive feedback so far (mostly :D). Tests should be passing in CI shortly... |
Sweet, CI is passing and I improved the |
I thought about this some more and I remembered why I didn’t favor “convert ’em to classes” approach. There is an important correctness issue here. Namely, React doesn’t let functional components get I don’t see any good way around this. The only implementation that wouldn’t suffer from this problem (IMO) would be the one that kept functions as they are, and passed them to the transforms. Of course this would require changes in transforms themselves (so they can handle functions) but I don’t think this is such a big deal because we only have a couple of popular transforms, and they will be easy to fix. Thoughts? |
Hmm, I dunno. I'm not 100% sure what this line means:
It sounds like this is referring to the owner's // ./Greeting.js
// - This would become a Class
const Greeting = ({ name }) => (<h1>Howdy there, {name}!</h1>);
export default class App extends React.Component {
render() {
// Based on the blog post, this.refs.greeting = null, but after the transform,
// this.refs.greeting = (instanceof Greeting).
return <Greeting name="Dan" ref="greeting" />;
}
} Frankly, I dunno. I'm largely spent on this and the window of opportunity is closing for me. I don't see a good way around it either, besides:
class _Greeting12387 extends React.Component {
render() {
const { name } = this.props;
return <h1>Howdy there, {name}!</h1>
}
}
const Greeting = (args) => <_Greeting12387 {...args} />
Let me know what you think. The hacker in me says "We can figure this out!", but the full-time employee in me says, "My new React devs could really use this now" :D |
I’m sorry I didn’t mention this before. It’s something I had in the back of my mind when I decided not to pursue the “converting” approach but I didn’t really put my thoughts out in public.
This would work but the downside is that every component would effectively become two components from React’s point of view. This would make performance even worse than it is now, and make DevTools view confusing and annoying.
There is no centralized docs for this, and that is the problem. There are boilerplate projects and example projects using this plugin with a few transforms, sometimes as a preset. Wherever we put this, people most likely to hit this will not read it. Since we’ve been encouraging them to put the transform behind a dev flag, we can’t allow them to write code that works in dev and breaks in prod. Even the opposite is not as bad. I’m afraid this is a really big drawback of this approach. I really appreciate your effort and I’m sorry I didn’t realize this was a problem sooner. I think that the right way forward would be:
This would also make your implementation simpler because you wouldn’t need to transform them this much—only to wrap them. And it is trivial to adjust |
The Worst-case scenario (we're about to start up a new project that could benefit from this), I'll create a Let me know how it goes and when this can be updated. |
@ericclemmons Did that fork happen, by any chance? I understand the caveats and was interested in giving this a try. (I tried setting it up in my project by removing |
I've made a commit in my forks of |
I still want to add support for them here—just not by converting them to classes. |
@gaearon I was waiting on you:
|
Oh, I’m sorry, I should’ve made it clear I didn’t intend to work on this right away 😞 . Realistically I expect to have time to work on this in a month or two. |
I will close this PR per reasons above. Happy to see another one dealing with functions directly. |
For the rest following the thread, I will likely create a functional equivalent of https://github.com/danmartinez101/babel-preset-react-hmre for those of us that don't have 100% of our component state abstracted into a global. |
Not sure if this is snark 😉 As I said before I’m totally on board with supporting functional components in a way that does not introduce potential null references in the production that you don’t have in development. Because null references are bad and I don’t trust myself to remember which components are functional and which aren’t. It’s not good if a developer can refactor a class component to be functional, use My decision to close this PR has nothing to do with Redux or single state atom, and everything to do with the fragility of approach you are suggesting. Having issues in production because of hot reloading is going to harm its credibility. As I said before I’m happy to accept a PR that implements it in a reasonably safe way by wrapping functions instead of turning them into classes. |
Wasn't snark. I understand the reasoning, I was just updating the thread On Sun, Mar 6, 2016 at 7:17 PM Dan Abramov notifications@github.com wrote:
|
React Hot Loader 3 supports functional components without destroying the state. |
This is a better, long awaited solution. The problem for myself (and likely many others) is that I have no idea what needs to be done for Webpack to know how to hot-reload something on the client (without doing a browser reload). |
🎈 🎉 Hot Module Replacement for Stateless Functional Components is (almost) here! 🎉 🎈
Having rewritten this logic 2 times already in ericclemmons/babel-plugin-react-pure-to-class#1, this makes my 3rd time :) I'm running on fumes, so I'm not interested in any major cleanup, restructure, or other chore tasks in this PR, simply resolving any blockers & letting the community reap the benefits.
This can be released as v2.1.0, but perhaps v3.0.0 is best because this is a substantial feature and possibly a BC break because there's no attainable way to verify compatibility with the ecosystem, IMO.
Stateless Functional Components
React v0.14 introduced them in this blog post:
These are significantly cleaner in appearance, simplifies testing, and removes React-signatures making it possible to re-use JSX-style components with other VDOM implementations.
(I only mention this because i've been experimenting with shipping different VDOM builds to Mobile vs. Desktop users to save on bandwidth, but that's irrelevant to this PR.)
As such, it's encouraged to write SFCs as the roadblock of losing HMR is now removed.
Requirements
Because we have to rely on signatures to infer if a function is indeed a component, there are a few checks that have to pass:
Foo
, notfoo
orfooBar
).React
may be in scope. If not,import React from "react"
is automatically inserted (for re-use & terseness, as indicated above).Users, like myself, who'll enjoy automatic insertion of
React
into the scope should remove this ESLint rule:How it Works
react-transform
continues working as usual!Examples
Based on an impromptu Twitter survey, the following examples are supported (more in the fixture tests):
Tests
test/fixtures/code-functional-*
that match ideal scenarios.t.isArrowExpression
,t.isIdentifier
, etc.) to ensure only supported patterns are matched.require.ensure
with Webpack for code-splitting & lazy-loading of routes.@connect
ed components, and even@resolve
d components.propTypes
set.References
Alright, after all of this effort I'm spent.
🚬 🍺 🍰