Typescript react component force-reloading entire page for trivial change
krainboltgreene opened this issue · comments
When I make a trivial change (1
to 2
) the hot reloader sees the change and reloads the page, instead of doing a patch. This is the message I see before the reload:
react_devtools_backend.js:2430 [HMR] Error: Aborted because ./lib/client/elements/Page/index.tsx is not accepted
Update propagation: ./lib/client/elements/Page/index.tsx -> ./lib/client/elements/index.ts -> ./lib/client/index.tsx -> 0
at hotApplyInternal (http://localhost:8080/browser-client.js?71fa7ddc8097054cc323:508:30)
at hotApply (http://localhost:8080/browser-client.js?71fa7ddc8097054cc323:362:19)
at http://localhost:8080/browser-client.js?71fa7ddc8097054cc323:337:22
overrideMethod @ react_devtools_backend.js:2430
./node_modules/webpack/hot/log.js.module.exports @ browser-client.js:218338
(anonymous) @ browser-client.js:218217
Promise.catch (async)
check @ browser-client.js:218210
(anonymous) @ browser-client.js:218229
emit @ browser-client.js:141324
reloadApp @ browser-client.js:217947
warnings @ browser-client.js:217496
(anonymous) @ browser-client.js:217715
sock.onmessage @ browser-client.js:217327
EventTarget.dispatchEvent @ browser-client.js:208639
(anonymous) @ browser-client.js:209357
SockJS._transportMessage @ browser-client.js:209355
EventEmitter.emit @ browser-client.js:208555
WebSocketTransport.ws.onmessage @ browser-client.js:211431
Versions:
- react ^16.14.0
- react-hot-loader ^4.13.0
- @hot-loader/react-dom ^16.14.0
- node 14.1.0
- npm 6.14.8
- macos 10.15.7
- chrome 87.0.4280.67
Demo application:
All correct:
- the update went like
./lib/client/elements/Page/index.tsx
->./lib/client/elements/index.ts
->./lib/client/index.tsx
->0
hot
boundary is installed only onlib/client/elements/Application/index.tsx
👉 just import "react-hot-loader/root";
at ./lib/client/elements/index.ts
to establish one more boundary and that's all.
Okay, so I figured out why it "used to work", turns out I can modify some components and get the expected hot reloading. I think the way I'm stacking my components is causing issues.
So at the root level I have:
render(
<BrowserRouter>
<Application />
</BrowserRouter>,
document.querySelector("#application")
);
And Application
looks like this:
export default hot(function Application (): JSX.Element {
return <ErrorBoundary>
<Router />
</ErrorBoundary>;
});
With Router
looking like this:
export default function Router (): JSX.Element {
return <Switch>
<Route exact path="/" component={LandingPage} />
</Switch>;
}
Finally, LandingPage
looks like:
export default function LandingPage (): JSX.Element {
return <Page as="LandingPage">
<h1>2</h1>
</Page>;
}
So amusingly, when I change LandingPage
I get the correct hot reloading result. When I change Page
I get the unexpected hot reloading.
I see now that anything inside the chain
pages/LandingPage/index.tsx -> pages/index.ts -> elements/Router/index.tsx -> elements/Application/index.tsx
gets hot reloaded correctly, anything that is "outside" that chain does not. I'm still trying to figure out why a change, to say elements/Link
looks like
Update propagation: ./lib/client/elements/Link/index.tsx -> ./lib/client/elements/index.ts -> ./lib/client/index.tsx -> 0
Why does ./lib/client/elements/index.ts -> ./lib/client/index.tsx
not include the steps where it hits LandingPage
, pages/index.ts
, Router
, then Application
?
Okay, I managed to get it working correctly by moving the hot()
call higher in the stack:
// client/index.tsx
const HotReloadedComponent = hot(() => <BrowserRouter><Application /></BrowserRouter>);
render(
<HotReloadedComponent />,
document.querySelector("#application")
);
Well, having hot
on the topmost level working only if you have react-dom
/react
referenced in any other branch.
As during HMR everything "below" hot
will be updated (destroyed and recreated again) - you probably need it a little below.
The simplest way is to move all the code for HotReloadedComponent
into a separate module, keeping dependencies for the top one, with render
at minimum.
Well I tried moving the HotReloadedComponent
into Application
and hit the same problem. I'll give making HotReloadedComponent
into it's own thing a try.