FormidableLabs / react-ssr-prepass

A custom partial React SSR renderer for prefetching and suspense
MIT License
592 stars 26 forks source link

using ssr-prepase after 1.3.0 react 17 #72

Closed trashhalo closed 3 years ago

trashhalo commented 3 years ago

Ive been reading the suspense test cases for a couple hours now and I just cannot get this to work.

I expect when this renders to see <h1 id="async-h1">hello</h1> but the thrown promise is bubbling all the way out and failing the build with a thrown object. I am sure I am doing something wrong here.

import React, {useState} from 'react';

function Inner({value}) {
    return (<h1 id="async-h1">{value}</h1>)
}

function Async() {
  const fetchThing = () => {
      throw Promise.resolve('hello');
  };
  const [value] = useState(fetchThing);
  return (<Inner value={value}></Inner>);
}

export default Async
kitten commented 3 years ago

Like in actual suspense, on the client-side, suspending is like swapping out the current rendering tree temporarily. That means that if your component instance stops suspending it will re-render, similar to what happens when you call setState during the initial mount syncronously, for instance. The component will continue rendering and pick up where it's left off. However, that means that the next time it renders you have to ensure it has proper data. It's not possible to continuously keep throwing a promise. To put it in other words, if a component always throws then it has no chance of ever rendering with data, which you can see in the tests: https://github.com/FormidableLabs/react-ssr-prepass/blob/a2660b455f992f43ce73b0fb271bf2df66772dfa/src/__tests__/suspense.test.js#L479-L481

So, if you're just testing this out, make sure that any one component instance throws once, writes to a cache, then resolves and re-renders with a synchronous values. This is basically the "read" pattern, where you either return a value or throw a promise that indicates when a synchronous value on calling read() is available.

trashhalo commented 3 years ago

Thank you, Will give it a shot tonight! It might make sense to add a usage example to the readme. Will gladly contribute one if I can get it to work locally.

trashhalo commented 3 years ago

Heres what I ultimately came up with that passes the test case.

https://github.com/snowpackjs/astro/compare/main...trashhalo:react-ssr-prepass?expand=1#diff-6b5a7c8d41ef0900ff3327af23a741b4af0ef53efae6280ece9b5fb41a98e95e

Feels pretty gross. I dont like how the cache lives on over multiple renders. Maybe a context value would do better? I tried to move cache into Async but then it just throws forever. I would imagine some of this would be hidden with hooks/components?