#Help with `Switch` and `Match`

13 messages · Page 1 of 1 (latest)

modest skiff
#

I have an element

export function ResultHeader(props: {
  loading: () => boolean;
  searchItem: () => string;
  results: () => string[];
  header: () => string;
}) {
  return (
    <div class="result-header no-select">
      <Switch fallback={props.header()}>
        <Match when={props.loading()}>
          <p>Looking up what beats "{props.searchItem()}"</p>
        </Match>
        <Match when={!props.searchItem()}>{null}</Match>
        <Match when={!props.results().length}>
          <p>No items found that beat "{props.searchItem()}"</p>
        </Match>
      </Switch>
    </div>
  );
}

but i somehow get in a state where i get both loading state and non-loading state. loading state should not appear

<div data-hk="s0000200" class="result-header no-select"><p>No items found that beat "<!--$-->hjkl<!--/-->"</p><p>Looking up what beats "<!--$-->hjkl<!--/-->"</p></div>

Reproduction steps:

  • open website
  • search for something that has uses, for example "rock"
  • click on one of the results, for example "paper" to search for it
  • search for something without results, for example "hjkl"

Then you can also search for something else ans you'll see top text get into a loading state and the to non-loading state with newly searched item, and bottom text will stay in loading state ith old item

empty thornBOT
#

Hi @modest skiff. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

Your issue appears to be with the logic inside your SolidJS <Switch> and <Match> blocks. The <Switch> component renders the first <Match> whose when condition is truthy. If multiple <Match> conditions can be true at the same time, only the first one will render. However, if your props or state are not updating as expected, or if the fallback is not being used correctly, you might see unexpected results.

From your code, the order of your <Match> statements is:

  1. loading
  2. !searchItem
  3. !results().length

If, for example, loading is true and results().length is 0, both conditions could be true, but only the first <Match> will render. However, if your state updates are asynchronous or not batched, you might see a transient state where both appear, especially if the parent component is re-rendering or the state is not being reset as expected.

Here are some suggestions:

  • Make sure that loading is mutually exclusive with the other states. For example, if loading is true, results and searchItem should be in their initial state.
  • Consider reordering your <Match> blocks so that the most restrictive or highest-priority condition comes first.
  • Double-check that your state updates (for loading, searchItem, results) are happening in a predictable, synchronous way.

A possible improved version:

<Switch>
  <Match when={props.loading()}>
    <p>Looking up what beats "{props.searchItem()}"</p>
  </Match>
  <Match when={!props.searchItem()}>
    {null}
  </Match>
  <Match when={!props.results().length}>
    <p>No items found that beat "{props.searchItem()}"</p>
  </Match>
  <Match when={true}>
    {props.header()}
  </Match>
</Switch>

Or, if you want to ensure only one state is ever shown, you could use if/else logic in your component instead of <Switch>.

#

Unfortunately, the knowledge sources do not contain specific information about SolidJS <Switch> and <Match> behavior in Astro, but they do confirm that SolidJS components are supported and rendered on the server using renderToStringAsync, and that Suspense boundaries are handled automatically for async components. If you are using async data, ensure your state is being updated in a way that avoids race conditions or stale closures, as described in the SolidJS integration guide.

If the issue persists, you may want to add logging or use Solid's devtools to trace state changes and ensure that your loading, searchItem, and results signals are updating as expected.

Let me know if you need more targeted help with your state management!

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@modest skiff Kapa.ai is still learning and improving, please let me know how I did by reacting below.

modest skiff
#

@empty thorn
Can it be with my search function state handling?

  async function getWhatBeats(item: string) {
    setInputItem(item);
    setSearchItem(item);
    setHeader("");
    setLoading(true);
    setResults([]);

    const cached = getCache(item);
    if (cached) {
      setResults(cached);
      setHeader(`Items that beat "${item}"`);
      setLoading(false);
      updateUrl(item);
      return;
    }

    try {
      const res = await fetch(
        `${CONFIG.apiUrl}?item=${encodeURIComponent(item)}`
      );
      if (!res.ok) throw new Error("API error");
      const data = (await res.json()) as string[];
      setCache(item, data);
      setResults(data);
      setHeader(`Items that beat "${item}"`);
      updateUrl(item);
    } catch {
      setHeader("");
      setResults([]);
    } finally {
      setLoading(false);
    }
  }
empty thornBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

Based on the knowledge sources provided, there is no explicit information about SolidJS state management or <Switch>/<Match> behavior in Astro that would directly confirm or deny whether your search function’s state handling is the cause of your issue.

However, the Astro SolidJS integration guide confirms that SolidJS components are supported and rendered on the server, and that Suspense boundaries are handled automatically for async components. This means your async state updates should generally work as expected in Astro.

Your function appears to set multiple states in sequence (setInputItem, setSearchItem, setHeader, setLoading, setResults), then performs an async fetch, and updates state again based on the result. In SolidJS, state setters are synchronous, but the actual DOM updates are batched and applied after the current execution context. If multiple async calls to getWhatBeats can overlap (for example, if a user triggers multiple searches quickly), it is possible for state updates from an earlier call to overwrite those from a later call, leading to inconsistent UI states.

Key points to check:

  • Ensure that only the latest search result updates the state. You may need to track the current search or use a cancellation/token pattern to ignore outdated results.
  • Make sure that setLoading(false) is only called for the most recent search, to avoid race conditions where an earlier search finishes after a later one.

Since the knowledge sources do not provide detailed guidance on SolidJS state management or async race conditions in Astro, I cannot provide a definitive answer. But based on general SolidJS and Astro integration knowledge, your state handling could indeed be the source of the issue if multiple async calls are not properly managed.

#

For more on how Astro handles SolidJS components and async data, see the SolidJS integration usage guide.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@modest skiff Kapa.ai is still learning and improving, please let me know how I did by reacting below.

modest skiff
#

@empty thorn

ChatGPT said using batch function might solve the issue

empty thornBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

I'm sorry, but the knowledge sources provided do not mention the use of a batch function in the context of SolidJS state management or its integration with Astro. The only reference to batch in the sources is related to database transactions in Astro DB, not UI state updates or SolidJS components Astro DB batch transactions.

Therefore, I cannot confirm or provide guidance on using a batch function to solve your UI state issue based on the available documentation. If you need more information about SolidJS's batch function specifically, you may want to consult the official SolidJS documentation.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: