solidjs / templates

Vite + solid templates
429 stars 120 forks source link

Routes no longer render if `<Show>`ing a rejected resource #149

Open spiffytech opened 1 week ago

spiffytech commented 1 week ago

In this sample code, a component uses <Show> to only show content once a resource has loaded. If that resource's Promise rejects, all routes cannot render anymore. Navigation will invoke a component function, but its body is never displayed.

Stackblitz reproduction

index.tsx

/* @refresh reload */
import { Show, Suspense } from 'solid-js';
import { render } from 'solid-js/web';
import { Router, Route } from '@solidjs/router';
import { createResource } from 'solid-js';

import './index.css';
import App from './App';

const root = document.getElementById('root');

const MyGoodComponent = (props: any) => {
  console.log('creating MyGoodComponent');

  const [data] = createResource(async () => {
    await new Promise((resolve) => setTimeout(resolve, 250));
    return 'successfully';
  });

  return (
    <Show when={data()} fallback={<p>Loading...</p>}>
      <p>
        Hello! You <span style="color: aqua;">{data()}</span> loaded data
      </p>
    </Show>
  );
};
const MyBadComponent = (props: any) => {
  console.log('creating MyBadComponent');
  const [data] = createResource(() => Promise.reject('Dummy error'));

  return (
    <Show when={data()} fallback={<p>Loading...</p>}>
      <p>
        Hello! You <span style="color: aqua;">{data()}</span> loaded data
      </p>
    </Show>
  );
};

render(
  () => (
    <Router root={App}>
      <Route path="/" component={MyGoodComponent} />
      <Route path="/one" component={MyGoodComponent} />w
      <Route path="/two" component={MyGoodComponent} />
      <Route path="/three" component={MyBadComponent} />
    </Router>
  ),
  root!
);

App.tsx

import { ParentComponent, createSignal } from 'solid-js';

import styles from './App.module.css';

const App: ParentComponent = (props) => {
  const [s, setS] = createSignal(0);
  setInterval(() => setS(s() + 1), 500);

  return (
    <div>
      <div style="background-color: #dcfce7;">
        <p>The count is: {s()}</p>
        <p>Nav</p>
        <ul>
          <li>
            <a href="/one">Good A</a>
          </li>
          <li>
            <a href="/two">Good B</a>
          </li>
          <li>
            <a href="/three">Broken</a>
          </li>
        </ul>
      </div>

      <hr />
      <div style="background-color: #ddd6fe; min-height: 200px;">
        {props.children}
      </div>
    </div>
  );
};

export default App;