Reputation: 3
I am using SolidJS and SUID ( Solid material UI ) library.
I am trying to use the same example as in the SUID documentation.
https://suid.io/components/select
import { For, createResource, createSignal } from 'solid-js';
import { Select, MenuItem } from '@suid/material'; // or "solid-ui", based on the library's exports
function Post() {
const [postsResource, { mutate, refetch }] = createResource(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
});
// State for the selected option
const [selectedOption, setSelectedOption] = createSignal('any');
return (
<div>
<h1>Posts</h1>
{postsResource.loading && <p>Loading...</p>}
{postsResource.error && <p>Error: {postsResource.error.message}</p>}
{
<>
<Select
// defaultValue={'any'}
// value={selectedOption()}
onChange={(e) => {
console.log('onChange', e.currentTarget);
setSelectedOption(e.currentTarget.value);
}}
>
<MenuItem value="any">Choose any...</MenuItem>
<MenuItem value="option1">option1</MenuItem>
<MenuItem value="option2">option2</MenuItem>
<For each={postsResource()}>
{(post) => <MenuItem value={post.id}>{post.title}</MenuItem>}
</For>
</Select>
</>
}
</div>
);
}
export default Post;
In this case, the Options that have values like any
, option1
and option2
(static options) are selectable, but other are not.
Also I should mention, when I use static options (code below) a Select works fine.
const options = [
{id: 1, label: 'Option 1'},
{id: 2, label: 'Option 2'},
{id: 3, label: 'Option 3'},
];
But when I use dynamic options (fetch, createResource
, promise, etc), something goes wrong.
There are main problems:
onChange
handler always receives similar valueMUI: A component is changing the uncontrolled value state of Select to be controlled.
Elements should not switch from uncontrolled to controlled (or vice versa).
Decide between using a controlled or uncontrolled Select element for the lifetime of the component.
The nature of the state is determined during the first render. It's considered controlled if the value is not `undefined`.
I tried to:
defaultValue
to Select
;defaultValue
to createSignal;tabIndex
, because I noticed that in For
each MenuItem
has tabIndex=-1
Provide you with playground for your experiments.
Original version stackblitz1
With Show & Props stackblitz2
What my expectations are:
Upvotes: 0
Views: 557
Reputation: 13698
The value from createResource
will be undefined
until the request resolves to a value. So, the component For
receives undefined
initially. You should restructure your component accordingly. It is best to use Switch/Match with resource.state value for conditional rendering.
Edit: Problem is with how SUID handles event. Select implements controlled data flow that somehow does not work well reactive values.
Try using a static value like the index number, it works as expected. As soon as you use a reactive value, it emit errors.
import { Match, Switch, createResource, createSignal } from 'solid-js';
import { Select, MenuItem } from '@suid/material';
function Post() {
const [data, { mutate, refetch }] = createResource(async () => {
const response = await fetch('https://jsonplaceholder.typicode.com/posts');
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
});
const [value, setValue] = createSignal('any');
const handleChange = (event) => {
console.log(event.target.value);
setValue(event.target.value);
console.log(event.currentTarget.value);
};
return (
<div>
<h1>Posts {value()}</h1>
<Switch>
<Match when={data.state === 'pending'}>Loading</Match>
<Match when={data.state === 'errored'}>Failed</Match>
<Match when={data.state === 'ready'}>
<Select
labelId="demo-simple-select-label"
id="demo-simple-select"
value={value()}
label="Value"
onChange={handleChange}
>
{data().map((post, index) => (
<MenuItem value={index}>{post.title}</MenuItem>
))}
</Select>
</Match>
</Switch>
</div>
);
}
export default Post;
Upvotes: 0