-
Notifications
You must be signed in to change notification settings - Fork 801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support decorators #279
Comments
Please do! Also make sure you’re using |
Ok, the "decorators" branch in zdavis/react-hot-boilerplate shows the problem pretty clearly. See zdavis/react-hot-boilerplate@7b510aa. This commit adds a new component called "DecoratedCounter". The decorated counter is decorated with @connect, which just wraps a component around the decorated component. The Counter component is also wrapped with connect, but without using decorator syntax. When DecoratedCounter is hot reloaded, it loses its internal state. This is not the case for the Counter component. Let me know if there's anything else I can do to help! |
I think this comes down to our babel plugin needing to be aware of decorators, otherwise it only wraps the decorated hoc, not the original component that was decorated |
I wonder if a simple way to fix this would be to insert our own “registering” decorator as the innermost one if we see a decorated class. |
Yeah that sounds like it'd work |
@liady we had the same problem over at @terminalcloud but I figured out a way to get things to work in the meantime. By my understanding of the code, react-hot-loader/babel goes through your modules, finding any variable or class declarations, checking if they are components, and registering them for reloading later. In order for stateful reloading to work, react-hot-loader must know about the full path of components from the root to your stateful component. If even one link in this chain is missing that subtree will be completely remounted. In our case we use two decorators, // WILL NOT WORK
export default connect()(view(() => <div/>))
// WILL NOT WORK
const View = view(() => <div>)
export default connect()(View)
// WORKS
const View = () => <div/>
const ElmView = view(View)
export default connect()(ElmView) in the first example, react-hot-loader doesn't know about the actual component or the intermediate one created by This workaround is pretty cumbersome imo, but it does work for now... |
@reem to be clear, those don't look like decorated components, but are higher-order components, so this is more likely related to #378, although a similar issue. Unfortunately it's a really tricky one, since right now the best that the Babel plugin can do is to look for top-level references. One idea would be to "expand" the code, to recursively turn your first example into the last example (split out currying?), but that sounds like it'd be riddled with edge cases. |
@calesce I'm not exactly sure what you mean, what's an example of a decorator that would cause a problem and is not a higher order component? This sort of thing is where a true multi-phase compiler with a middle representation between AST and output representation is really helpful - the AST can be transformed into a radically simplified middle layer where all expressions are already split into their smallest possible pieces and you have a true CFG to work with (where all conditionals, loops, etc. have all been turned into jumps). Then implementing a "decorator" for all values of some type is much much easier, because you can detect them directly instead of relying on parsing, which is going to be inherently fragile. |
Decorators are a stage-2 JavaScript proposal, denoted with What's different is that you can have something like: @connect(mapStateToProps)
export default class App extends React.Component {...} that doesn't get reloaded, but this does: export default connect(mapStateToProps)
(class App extends React.Component {...}) I'm not familiar with the exact decorator semantics to tell you why, I haven't dug enough into this specific issue.
Ha, yeah that sure would be nice, I'm guessing you have Rust in mind. 😉 |
You got me :P Your examples are a little odd to me because in my testing it appears that:
actually does not get reloaded, only:
does. This would explain why decorators don't work, because the |
Yeah you're right, my mistake. I typically write it out like in your latter example. It looks like with decorators, you can't have a reference to the original class, which is why @gaearon suggested having the plugin insert a decorator that registers it with the RHL runtime. Another approach might be running the |
I think it's all actually the same problem: if you don't have a top level variable or It really seems like the only way to conclusively solve this is to do something like override |
This is a most important thing to be solved in future. And the hardest puzzle to solve. Currently, there are two ways:
First one is a bit tricky - currently, on module update, you will require new sources, and render It is also possible just to require the new sources and re-render the old application. And RHL will replace all the React components by the new ones. Magic. PS: You can do it manually by placing module.hot.accept. |
I've just shown the warning about the use of Decorators in RHL readme. Am I wrong ? Or is my way to use decorator that prevents this issue ? Here is a repo https://github.com/lgra/lg-webpack with a kind of React app template with WebPack and RHL. It can be run with vscode debug tool, or npm start. When modifying render method of decorated component, state seems to be preserved, even if the method itself is enhanced by the decorator (in the example, the render method of web_modules/app/group, enhanced by @renderDuration). |
Look like it working just because you dont "decorate" classes (like HOC), but you modify their prototypes. Thus it is the same class and you had it as a top level variable. |
Understand! Thanks a lot. |
<div>
<h1>Hello, world!!!!</h1>
{children}
</div> In does create {children} prop for a |
Sounds fixed in v4.0.0-beta.5. |
@neoziro I have this warning now after each update (I use Not sure what is it though |
@mqklin you can ignore it, we will switch these warnings to debug mode. |
Yes I can ignore warnings, but still cannot hot reload composed codes. Is there any workaround or progress about this issue? |
Just yesterday we desided not to do anything. #821. |
Really awesome to see this fixed! We're excited to try out the new version of RHL. Thank you all for your work on it! |
I would like to support the project on opencollective, but can't find it there |
@mqklin yes, I just submitted it, I keep you in touch! |
Cool! Glad I can support the project as much as I can. Hope I will be able to give back more! Thank you for you work! |
(This may or may not be something you want to address with v3; if not, please just close this)
Our project uses decorators to connect components to the redux store. I think this is fairly common. For example, you see it a lot in erikras/react-redux-universal-hot-example, which uses Babel 6 and the "transform-decorators-legacy" Babel plugin, since Babel has decided to postpone decorator support until its more mature. For example:
https://github.com/erikras/react-redux-universal-hot-example/blob/master/src/containers/Chat/Chat.js#L4
This worked fine with v2, but with v3 components that are decorated like this seem to lose their internal state when they're hot-reloaded.
If you want to look at this, let me know and I'll put together a sample repo that shows the problem. Thanks so much for your work on this! It's great to see all the activity on this project right now.
best,
Zach
The text was updated successfully, but these errors were encountered: