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

[Bug?]: Hydration Mismatch during Development. Nesting element within an object will break hydration. #1475

Closed
2 tasks done
edygar opened this issue May 14, 2024 · 4 comments
Labels
bug Something isn't working

Comments

@edygar
Copy link

edygar commented May 14, 2024

Duplicates

  • I have searched the existing issues

Latest version

  • I have tested the latest version

Current behavior 😯

Route throws consistently when accessing it during development, any time the route is accessed. Production build seems to work fine. Anticipating this question, it doesn't influences at all, restarting the server doesn't affect it..

image

Expected behavior 🤔

It shouldn't throw.

Steps to reproduce 🕹

Steps:

  1. Create a route with the following code:
import type { JSX } from "solid-js";

const ReproduceSteps = (props: {
  test: { propertyBesidesElement: JSX.Element; element: JSX.Element };
}) => {
  return (
    <button onClick={() => console.log(props.test)}>
      {props.test.propertyBesidesElement}
    </button>
  );
};
export default function BugReport() {
  return (
    <ReproduceSteps
      test={{ propertyBesidesElement: "test", element: <div>test</div> }}
    />
  );
}
  1. Run the project in dev mode
  2. Access the route

Context 🔦

I've reduced it to the minimal reproducible code. Let me know if anything else is required. Couldn't find this same bug on other issues so I decided to report.

Your environment 🌎

System:
OS: MacOS Sonoma 14.4.1
CPU: Apple M1 Pro (16 GB of Memory)
Binaries:
Node: v20.10.0 - $HOME/.volta/bin/node
pnpm: 8.14.0 - $HOME/.volta/bin/pnpm
npmPackages:
"@solidjs/meta": "^0.29.3",      
"@solidjs/router": "^0.13.3",    
"@solidjs/start": "^1.0.0-rc.1", 
"solid-js": "^1.8.17",           
"vinxi": "^0.3.11"
@edygar edygar added the bug Something isn't working label May 14, 2024
@peerreynders
Copy link

Context: Original Discord discussion.

TLDR: Feels that requiring a render thunk

import type { JSX } from 'solid-js';

const ReproduceSteps = (props: {
  test: {
    propertyBesidesElement: () => JSX.Element;
    element: () => JSX.Element;
  };
}) => {
  return (
    <button onClick={() => console.log(props.test)}>
      {props.test.propertyBesidesElement()}
    </button>
  );
};

export default function App() {
  return (
    <ReproduceSteps
      test={{
        propertyBesidesElement: () => 'test',
        element: () => <div>test</div>,
      }}
    />
  );
}

to support SSR is poor DX.

@ryansolid
Copy link
Member

The reason is that technically every time you call props.test you are remaking the DOM elements. Some are being inserted and the others aren't, and aren't being found. In the past we were more lenient here creating new DOM elements in these cases and just warning. But this isn't a good pattern anyway as you are basically doing wasted work by rendering twice. If you access props multiple times we recommend using children.

@edygar
Copy link
Author

edygar commented May 14, 2024

Got it:

Screenshot 2024-05-14 at 16 24 14

vs:

Screenshot 2024-05-14 at 16 26 29

Conclusion: _tmpl$2( ) fit into the heuristic, compiler turned this property into a lazily computed one, so the object is rebuilt every time the property is accessed, hence a new element is created, hydration mismatch. So, the solution is to simply wrap the props.test reading, through a memo (createMemo).

But I'm accessing only once in the Entire ReproduceSteps server's runtime. Why did it throw anyways?

@edygar
Copy link
Author

edygar commented May 14, 2024

Also, I see this as very risk approach, I don't to be recreating "consumer" elements all the time. Besides @peerreynders's recommendation, and "3 Patterns to Write Declarative, More Readable SolidJS Components", what are the alternatives? What is the best one to compose layouts off of consumer provided elements?

I intend to contribute on the documentation, xD to put a very big warning there against this pattern, which I'm very used from React-based codebases.

@edygar edygar closed this as completed May 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

3 participants