Skip to content
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

First component loses state on first hot reload #489

Closed
kwohlfahrt opened this issue Aug 27, 2021 · 8 comments · Fixed by #505
Closed

First component loses state on first hot reload #489

kwohlfahrt opened this issue Aug 27, 2021 · 8 comments · Fixed by #505
Labels
question Further information is requested

Comments

@kwohlfahrt
Copy link

If I modify a functional component, on the first hot reload, the first component loses its internal state. Subsequent reloads are OK. It seems to depend on the order the components are imported in, so may be related to #455. Changing the order of imports of FunctionDefault and FunctionNamed changes which one is affected, but one of them always is.

Steps to reproduce:

  1. Apply the diff below to the current git repository (319e650). This adds some state to the two functional components, and deletes the class components.
  2. Start the dev server with yarn start
  3. Load the page in the browser, and click the button a few times to modify the state.
  4. Modify the functional components, for example: sed -E 's/more/less/g' -i ./*.tsx

Patch

diff --git a/examples/typescript-with-tsc/src/App.tsx b/examples/typescript-with-tsc/src/App.tsx
index c7def2a..dbd820a 100644
--- a/examples/typescript-with-tsc/src/App.tsx
+++ b/examples/typescript-with-tsc/src/App.tsx
@@ -9,8 +9,6 @@ const LazyComponent = lazy(() => import('./LazyComponent'));
 function App() {
   return (
     <div>
-      <ClassDefault />
-      <ClassNamed />
       <FunctionDefault />
       <FunctionNamed />
       <Suspense fallback={<h1>Loading</h1>}>
diff --git a/examples/typescript-with-tsc/src/FunctionDefault.tsx b/examples/typescript-with-tsc/src/FunctionDefault.tsx
index f886ae3..8022beb 100644
--- a/examples/typescript-with-tsc/src/FunctionDefault.tsx
+++ b/examples/typescript-with-tsc/src/FunctionDefault.tsx
@@ -1,5 +1,12 @@
+import { useState } from "react";
+
 function FunctionDefault() {
-  return <h1>Default Export Function</h1>;
+  let [state, setState] = useState(1);
+
+  return (<>
+    <h1>Default Export Function{"!".repeat(state)}</h1>
+    <button onClick={() => setState(state => state + 1)}>more</button>
+  </>);
 }
 
 export default FunctionDefault;
diff --git a/examples/typescript-with-tsc/src/FunctionNamed.tsx b/examples/typescript-with-tsc/src/FunctionNamed.tsx
index b807a43..35b1127 100644
--- a/examples/typescript-with-tsc/src/FunctionNamed.tsx
+++ b/examples/typescript-with-tsc/src/FunctionNamed.tsx
@@ -1,3 +1,10 @@
+import { useState } from "react";
+
 export function FunctionNamed() {
-  return <h1>Named Export Function</h1>;
+  let [state, setState] = useState(1);
+
+  return (<>
+    <h1>Named Export Function{"!".repeat(state)}</h1>
+    <button onClick={() => setState(state => state + 1)}>more</button>
+  </>);
 }

Observed result

The page updates, but the state of the first component is lost (i.e. reset to the initial state). The second component maintains its state. This only occurs on the first hot reload, subsequent modifications to the components correctly preserve state.

Expected result

Both functional components should maintain their state after the modification causes a hot reload.

@pmmmwh
Copy link
Owner

pmmmwh commented Sep 4, 2021

This seems like it's only an issue of react-refresh-typescript but not the official Babel plugin.

@Jack-Works Maybe you could help on this? I'm unfamiliar with how the TS custom transformer API works.

@Jack-Works
Copy link
Contributor

Hi, I see this but I'm not available recently. I'll add this to my TODO list but I'm not able to fix it in a short time. 👀

@pmmmwh pmmmwh added the question Further information is requested label Sep 4, 2021
@Jack-Works
Copy link
Contributor

Yes I can reproduce this.

@Jack-Works
Copy link
Contributor

It seems like in the first time rendering, the signature function I'm calling

image

Is a mock one. (maybe react-refresh-webpack-plugin didn't setup complete at this stage?)

image

@Jack-Works
Copy link
Contributor

Therefore the function signature is not reported to the react-refresh runtime at the first load

@Jack-Works
Copy link
Contributor

As you can see the code I generated for the working version and non-working version is exactly the same. So I guess there isn't much thing I can do to fix this problem

image

@Jack-Works
Copy link
Contributor

@pmmmwh So the problem is

webpack_require.$Refresh$.signature = webpack_require.$Refresh$.runtime.createSignatureFunctionForTransform;

This code is called too late. Therefore react-refresh missed the first component signature

@pmmmwh
Copy link
Owner

pmmmwh commented Sep 13, 2021

Hey, thanks for the debugging. I've identified a fix!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
question Further information is requested
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants