S
SolidJS3mo ago
Seb

Input focus problem when trying to retrieve data with createAsync

I have the following code where I try to call a server function based on the content of an input. The goal is to retrieve a list of cities based on the entered zip code. My problem with this code is that each type I type something in the input, it looses the focus. I found several information about input loosing focus because the input is recreated but I don't think I am in this case. I can't figure out the problem here.
import { createStore } from 'solid-js/store';
import { createAsync, query } from '@solidjs/router';
import { For } from 'solid-js';

type SearchFields = {
zipCode?: string;
};

const getCities = query(async (zipCode?: string) => {
if (!zipCode || zipCode.length !== 5) return undefined;
return [{ name: "test" }];
}, "getCities");

export default function Root() {
const [searchFields, setSearchFields] = createStore<SearchFields>();
const citiesByZipCode = createAsync(() => getCities(searchFields.zipCode));

createEffect(() => console.log("citiesByZipCode", citiesByZipCode()));
return (
<form method="post">
<fieldset>
<legend>Code postal</legend>
<input oninput={(event) => setSearchFields({ zipCode: event.target.value })} />
<For each={citiesByZipCode()}>{(city) => <div>{city.name}</div>}</For>
</fieldset>
</form>
)
}
import { createStore } from 'solid-js/store';
import { createAsync, query } from '@solidjs/router';
import { For } from 'solid-js';

type SearchFields = {
zipCode?: string;
};

const getCities = query(async (zipCode?: string) => {
if (!zipCode || zipCode.length !== 5) return undefined;
return [{ name: "test" }];
}, "getCities");

export default function Root() {
const [searchFields, setSearchFields] = createStore<SearchFields>();
const citiesByZipCode = createAsync(() => getCities(searchFields.zipCode));

createEffect(() => console.log("citiesByZipCode", citiesByZipCode()));
return (
<form method="post">
<fieldset>
<legend>Code postal</legend>
<input oninput={(event) => setSearchFields({ zipCode: event.target.value })} />
<For each={citiesByZipCode()}>{(city) => <div>{city.name}</div>}</For>
</fieldset>
</form>
)
}
8 Replies
Seb
SebOP3mo ago
Ok, I found the problem. As I don't have a Suspense in my page the createAsync refreshes the page each time it is called. I just have to put a Suspense around my For component to solve the problem. Another option is to use an action with useAction instead of using createAsync. This means we need to manually store the result of the action in a signal or a store in this case but we no longer need to handle the suspense.
josephbrowndev
josephbrowndev3mo ago
You are right. You've correctly diagnosed a classic Solid.js reactivity pitfall. The important is that createAsync is designed to work with Suspense, and without it, the entire component re-executes to handle the loading state, which destroys and recreates the DOM, including your input.
Madaxen86
Madaxen863mo ago
Dont do that. Actions are for mutations and to revalidate the query cache. They are not supposed to be used for data fetching as that will cause unwanted side effects on queries
Seb
SebOP3mo ago
Ok but for this kind of use case is there a way to call the query without using createAsync to avoid to have an unwanted refresh of some parts of the page?
Madaxen86
Madaxen863mo ago
Suspense. You can wrap only the elements or even have multiple elements wrapped in individual Suspense if you access async data in multiple locations in the JSX. Like in this ticket https://discord.com/channels/722131463138705510/1413574767553810453
Seb
SebOP3mo ago
I have some cases like when I use Kobalte Search component where I am not able to put a Suspense around components because the search list is built programmatically, I will ask them for a solution but I could be cool to be able to have something similar to useAction for queries.
Madaxen86
Madaxen863mo ago
Do you have a code snippet or can you put something in https://playground.solidjs.com
Solid Playground
Quickly discover what the solid compiler will generate from your JSX template
Seb
SebOP3mo ago
Here is a sample project to reproduce the problem: https://github.com/scesbron/kobalte-search-test
GitHub
GitHub - scesbron/kobalte-search-test: Test of the kobalte search c...
Test of the kobalte search component. Contribute to scesbron/kobalte-search-test development by creating an account on GitHub.

Did you find this page helpful?