I’m not sure if this is a react-hot-loader thing or a react-proxy thing, so I’ll start here.
I’m the maintainer of a library for React that consists of a few React components generated by a factory function. These components are causing the following error on first mount:
React Hot Loader: this component is not accepted by Hot Loader.
Please check is it extracted as a top level class, a function or a variable.
Click below to reveal the source location: …
The components are class components, but they have no state and their source will never change. I’m assuming that means they don’t need to be wrapped in RHL’s state-preserving magic. As a library author, is it possible to opt out of the wrapper/patch?
This message also means, that RHL will not only not-accept this element, but also will remount all the nested tree. So - it is better to fix it, and usually it is not just easy, but may speed up whole application a but.
I checked the sources, and could not found any red flags, like a double-nested HOCs, which may trigger this error.
Could you provide any example, or just an error message?
@theKashey the error occurs in our production application, but I’ll try to get an isolated example that I can share up this weekend.
@meyer - no need of isolated example - any example will be ok. This is the most common problem :( we know how to trace and fix it
@theKashey the class is generated by TypeScript. Not sure if that would cause issues. The transpiled factory function looks like this (with boilerplate omitted):
var cache = getStyleCache();
function factory(displayName, defaultProps) {
var tagName = 'div';
return (
(_a = /** @class */ (function(_super) {
__extends(JsxstyleComponent, _super);
function JsxstyleComponent(props) {
var _this = _super.call(this, props) || this;
_this.component = props.component || tagName;
_this.className = cache.getClassName(props, props.className);
return _this;
}
JsxstyleComponent.prototype.componentWillReceiveProps = function(props) {
this.component = props.component || tagName;
this.className = cache.getClassName(props, props.className);
};
JsxstyleComponent.prototype.render = function() {
var _a = this.props,
props = _a.props,
style = _a.style,
children = _a.children;
return createElement(
this.component,
__assign({}, props, { className: this.className, style: style }),
children
);
};
return JsxstyleComponent;
})(Component)),
(_a.defaultProps = defaultProps),
(_a.displayName = displayName),
_a
);
var _a;
}
var Box = factory('Box');
// etc.
We’re using RHL with webpack + the babel plugin:
[
require.resolve('babel-plugin-transform-class-properties'),
require.resolve('babel-plugin-transform-object-rest-spread'),
require.resolve('babel-plugin-syntax-dynamic-import'),
options.hot && require.resolve('react-hot-loader/babel'),
]
The patch is being included right before the entrypoint file:
[
options.hot && require.resolve('react-hot-loader/patch'),
require.resolve('./app'),
]
As far as an example goes, what would work best for you? Code snippets or a working demo?
@meyer - the code looks fine. Could you provide an error message from RHL?
@theKashey here you go:
patch.dev.js:141 React Hot Loader: this component is not accepted by Hot Loader.
Please check is it extracted as a top level class, a function or a variable.
Click below to reveal the source location:
Ć’ JsxstyleComponent(props) {
var _this = _super.call(this, props) || this;
_this.component = props.component || tagName;
_this.className = cache.getClassName(props, props.classN…
warnAboutUnnacceptedClass @ patch.dev.js:141
resolveType @ patch.dev.js:160
patchedCreateElement @ patch.dev.js:182
render @ Button.tsx:172
...
@meyer - do you have others calls to factory expect this one? Somewhere in Button.tsx?
@theKashey I don’t. Components are imported from jsxstyle throughout the codebase (including in Button.tsx), but the factory function is called once, when the jsxstyle module is imported. The _first_ import call occurs in Button.tsx, and that’s the source of the error.
Here’s all 100 LOC if you want to take a closer look: https://github.com/smyte/jsxstyle/blob/103c076/packages/jsxstyle/jsxstyle.tsx
Edit: the factory function is called multiple times; could that be the source of the problem?
RHL throws cos it thinks that you are providing some class it should, but could not replace. The reason is simple - the source code the same. Actual implementation depends on the scope variable, but code is the same.
As result - on second element render it will throw.
Should throw on the first render, should not throw on hot module replace. Please check am I right.
There is one thing I could do (and will do) - use displayName to differ Classes.
There is one thing you could do (you better skip) - overload Class.toString to return different codes for different Components.
@theKashey ahhhhhh, I see. yeah, HMR works just fine with this error. It’s mainly a cosmetic thing. The component appears to reload correctly.
We will fix it in next release. 🍻
@meyer - this should be fixed in next version, as long it does not compare classes in that way.
Could you please double check?
@meyer please reopen a new issue if you experienced some problem with React Hot Loader v4.
@neoziro @theKashey I accidentally upgraded from v3 to v4 and have not noticed this issue. I think it’s fixed. Thanks!
Most helpful comment
We will fix it in next release. 🍻