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

Handling different client and server content - not showing initial render #6190

Open
Ahmed-Abou-Emran opened this issue Jul 30, 2023 · 9 comments

Comments

@Ahmed-Abou-Emran
Copy link

Ahmed-Abou-Emran commented Jul 30, 2023

In the hydrateRoot page, it is mentioned that
"This way the initial render pass will render the same content as the server, avoiding mismatches, but an additional pass will happen synchronously right after hydration."

which means that the initial render on the playground should show "Is Server", but it shows directly "Is Client" which is very confusing for learners and doesn't show the real behavior.
I tired opening the sandbox in external window, and it indeed shows "Is Server" first and then changing to "Is Client" as expected.

In the Website:
hydrate root playground

In The sandbox (using the fork button):
hydrate root sandbox

@santoshy1101

This comment was marked as off-topic.

@Uuek

This comment was marked as off-topic.

@abdullah43577

This comment was marked as off-topic.

@Ahmed-Abou-Emran
Copy link
Author

Hi there
@abdullah43577 @santoshy1101 @Uuek
@abdullah43577,

As of now, nobody has been assigned to the task yet. I made an attempt to address the issue today. It appears that the playground is being statically rendered. When examining the page source, it shows that the initial page sent contains "is Client".
image

To resolve this, I explored methods to force dynamic rendering and discovered that we can utilize the following export statement:
export const dynamic = "force-dynamic"

and changed the SandPack component code to the following:
`

<!--
  HTML content inside <div id="root">...</div>
  was generated from App by react-dom/server.
-->
<div id="root"><h1>Is Server</h1></div>
import './styles.css';
import { hydrateRoot } from 'react-dom/client';
import App from './App.js';

hydrateRoot(document.getElementById('root'), <App />);
export const dynamic = 'force-dynamic';
import { useState, useEffect } from "react";

export default function App() {
  const [isClient, setIsClient] = useState(false);

  useEffect(() => {
    setIsClient(true);
  }, []);

  return (
    <h1>
      {isClient ? 'Is Client' : 'Is Server'}
    </h1>
  );
}
` However, I implemented it, but unfortunately, it doesn't seem to be working as intended. Further investigation is needed to find an effective solution.

Let me know if you have any suggestions or if I should proceed with additional debugging to fix the problem.

@abdullah43577
Copy link

It seems that the component is client side rendering from the start.

If I fully understand the issue, it's supposed to display is server when the component first mounts then the useEffect runs to re-render the component showing is client, but instead it shows only is client, right?

@nalladev
Copy link

I think the issue is as soon as the server render is shown the isClient is set to true. So the change happens instantly and we cant't see the isServer text

@nalladev
Copy link

i fixed the bug in above commit #6216 by adding a 1 second timeout for changing the isClient state now the transition between isServer to isClient text is distinguishable

@AmrAhmedA
Copy link

@Ahmed-Abou-Emran I think It is an iframe issue, the purpose of that demo is to prevent mismatch between the content on the server and the client. @joeljtomy indeed, adding an additional one second delay should fix the issue.

chrome-capture-2023-7-14 (1)

@rickhanlonii
Copy link
Member

I am seeing this work on the forked sandbox, but it should work on the site.

I don't like the timeout solution because the code should show an example of how it works in practice and you would never add a timeout for hydrateRoot. But if we wanted to pause it and call hydration afterwards, we could add a button and text like "This is the server rendered HTML before hydrateRoot is called" and a button to hydrate which calls hydrate root. I would also include a code comment that says not to call it in a button in a real app.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants