-
Notifications
You must be signed in to change notification settings - Fork 88
Support Functional Components #57
Comments
If you only do the top level ones automatically and would require a comment above or inside other functions? |
No, comments are a gross for this. We get a ton of issues on Babel because of the Angular community using I would try everything possible before using comments. |
I'd choose a convention a la "let/const function bindings at top level with capital letter names and JSX immediately inside." In the first release I'd avoid trying to find factories altogether. I don't think that's a big problem. Avoiding false positives is more important than finding every possible case. You can look at eslint React plugin as an inspiration for the heuristics. |
@thejameskyle I think what @gaearon suggests makes sense and as of next iteration we can support a "manual hint" case when heuristic didn't work. What are other options yo see besides comments? Can generators be used? |
An additional heuristic can be "a function with propTypes assigned to it later". Though React is gradually phasing out propTypes in favor of flow, it seems like a nice heuristic for most code bases. |
Can we limit the heuristic to any function that returns JSX and has props as its first argument? |
Unfortunately, that would not cover the destructuring use case: (from https://facebook.github.io/react/blog/2015/10/07/react-v0.14.html#stateless-functional-components) // Or with destructuring and an implicit return, simply:
var Aquarium = ({species}) => (
<Tank>
{getFish(species)}
</Tank>
); |
The other issue that I didn't point out here is that many people do not use JSX in favor of something like hyperscript. |
@SpainTrain good point. I am even using destructuring in some of my stateless components. 😄 |
@thejameskyle Shouldn't the first pass be focused only on the most common and recommended way (JSX/ES6) of writing stateless components? |
So far proposed heuristics are:
This doesn't cover:
And it's sounds like it's okay for now. Subjectively this covers majority of the cases. We haven't yet discussed manual hinting, since I feel like it's a nice option. |
I think that going with something as basic as "let/const function bindings at top level with capital letter names and JSX immediately inside." is probably a great idea. Right now, people are just saying "Please support functional components!" Once you can say "They are supported as long as... xyz" then you will probably start getting people with issues letting you know when there is a scenario that "xyz" just doesn't work. |
How about TitleCase functions with a False positives would be constructors which handle creating more specialised instances which also happen to do something with React/JSX. |
Could be wrong, but a functional component could be defined as:
|
Regarding manual hinting, would something like this work: "HMR"; var Component = function() {
return <div />;
}
// or:
var Component = function() {
"HMR";
return <div />;
} It's not a comment, and this pattern is used for strict mode ( |
Can you elaborate a little, why return statement that isn't guarded with mentioned check is a good indicator of a component? |
How about the following for the heuristics?
|
My rationale is:
(Subscribed!) |
@ericclemmons agree with points, except |
One could poke holes through all of the heuristics listed in this thread. I'm guessing everyone here is basing it off of how they choose to personally write these components which is bound to cause issues. I'm convinced that this is a bad idea to support. |
I'm thinking it'd be a better idea to tell people not to use functional components and just run their code through: https://github.com/thejameskyle/babel-plugin-react-pure-components which will optimize it to functional components for them. I'll need to put more work into that though |
👍 @gaearon, works like a charm and recommend it to others for hotloading functional components as well as redux ! |
This is because it doesn't work with functrional components, instead using the recommendation made here gaearon/babel-plugin-react-transform#57 since it works with functional React components which is what the React team recommends themselves !
I don't understand. Has this answer been in front of us all along? And wasn't hmre needed for hot module replacement? And if I get it straight, I just remove the react-hmre babel preset and then HMR will still work, functional components will also work, but in exchange local state won't work? I wish I knew exactly how HMR worked internally. |
HMR is just something that allow you to write this kind of code if (module.hot) {
// do something when a file has been hot loaded
} babel-plugin-react-transform just insert some code using this Without this plugin, you can still use hot loading (as explained before) to rerender your entire app. This will be "ok" if you have a global store like redux (since you are not supposed with this approach to rely too much on local state). |
OK maybe we’ve been doing it from the wrong end all along: |
@gaearon didn't quite follow your last twitter comment. Could you explain how it's relevant? Edit: Found this medium post. Awesome read and all is clear now. :) https://medium.com/@dan_abramov/hot-reloading-in-react-1140438583bf#.fbkvfqotn |
As mentioned in https://github.com/reactjs/redux/pull/1455/files#r56386442, I would love to see a real world example of the "basic" (non-proxied) hot reloading with functional components in a project with Redux and react-router. I can get it to work for a single component but can't work out how to get the updates to bubble up to a single parent component properly and am generally a bit confused :) but would like to work with stateless/functional components and some kind of HMR if possible |
@tomduncalf don't have any open source project to show you at the moment, but you can take a look at this // src/index.js
import 'babel-polyfill'
import 'whatwg-fetch'
import React from 'react'
import ReactDOM from 'react-dom'
const mountEl = document.getElementById('root')
let render = () => {
const Root = require('./Root').default
ReactDOM.render(<Root />, mountEl)
}
if (module.hot) {
const renderApp = render
const renderError = (error) => {
const RedBox = require('redbox-react')
ReactDOM.render(
<RedBox error={ error } />, mountEl
)
}
render = () => {
try {
renderApp()
} catch (error) {
renderError(error)
}
}
module.hot.accept('./Root', () => {
setTimeout(render)
})
}
render() // src/Root.js
import React from 'react'
import { Provider } from 'react-redux'
import { Router } from 'react-router'
import { hashHistory } from 'react-router'
import { syncHistoryWithStore } from 'react-router-redux'
import pure from 'recompose/pure'
import createStore from './store'
import routes from './routes'
import './styles/styles.scss'
const store = createStore()
const history = syncHistoryWithStore(hashHistory, store)
const Root = () =>
<Provider store={ store }>
<Router history={ history } routes={ routes } />
</Provider>
export default pure(Root) // src/routes.js
import React from 'react'
import { IndexRoute, Route } from 'react-router'
import { App, Home, NotFound } from './components/app'
export default (
<Route path="/" component={ App }>
{ /* Main route */ }
<IndexRoute component={ Home } />
{ /* Routes */ }
{ /* Catch all route */ }
<Route path="*" component={ NotFound } status={ 404 } />
</Route>
) |
Thanks imran! I thought that was exactly what I did but there must be some subtle differences so I will try again :)
|
Sorry if I might be polluting this discussion with my lacking knowledge of how HMR is supposed to work, but could anyone explain to me why my attempt at a wrapper failed to solve this problem? https://gist.github.com/firstdoit/1fe09563cfe4dbb04246 The intended use was to simply wrap the export of any functional component and giving HMR a full React 'class' to play with. |
Any updates on this? It would be awesome to use functional components without ditching the benefits of this plugin. |
@webyak This will likely never happen. See #57 (comment) |
Not entirely “will never happen”. As I said in #57 (comment), supporting functional components will require a different approach but this doesn’t mean the benefits of this plugin are going away. You can track gaearon/react-transform-boilerplate#125 as something might happen there eventually, or read https://medium.com/@dan_abramov/hot-reloading-in-react-1140438583bf for more context. |
React Hot Loader 3 supports functional components without destroying the state. |
Thanks @gaearon, can't wait to try it out! |
So let me get it straight: react hot loader was deprecated in favor of react transform, which in turn is deprecated back in favor of react hot loader again? |
@amcsi React hot loader 3.0 is a combination of both React hot loader 1.0 and react transform. And it works with function component |
I don't quite get it, but all right. |
Yes. Both approaches were bad in different ways. I’m trying a third, mixed, approach, and it makes sense to brand it as React Hot Loader, as it doesn’t allow arbitrary transforms anymore.
It is absolutely orthogonal: you can use either |
Moving from #34.
As of
react@0.14
, plain functions can be used as components. In the future this will bring performance optimizations in React.Many people are already using these, there's even a Babel plugin (that I wrote) to transform pure component classes to pure component functions.
It would be great if
babel-plugin-react-transform
supported these. However, there is a pretty big concern.Since these are just plain functions, with JSX in them there is nothing that designates that it is a react component. i.e. in order to tell that a class is a react component, we can test that it extends
React.Component
, or that it has a matching interface.We can attempt to match them by treating "any function that has JSX in it will be treated as a component" i.e.:
However, this would also match the inner function in here:
So we can tighten things and say "only top level components", but then we run into wanting to support factories:
I could keep going for a while, you can put functions all over the place in JavaScript and no matter what we define as the rule here there will be exceptions. It's a matter of deciding what the heuristics should be that balances:
It might be possible to get around the obviousness problem by throwing compile errors when running into ambiguous scenarios.
The text was updated successfully, but these errors were encountered: