I'd like to use React Select library so that a user could select one option. API server stores available options. API request argument is a prefix and the server responses with a list of options (array of strings) matching the given prefix.
So I'm using Async component. Because the server responses with an array of strings, I define component's props getOptionValue and getOptionLabel as {d => d}.
Labels in the menu are shown as expected, but the problem is that when I select some option, the menu just closes and no option seems to be selected.
You can see this behavior in https://codesandbox.io/s/reactcodesandboxerexample-j1xxh , code is in file example.js. API request is replaced by creating Promise.
I tried to map fetched options to objects with properties value and label so that I don't have to override getOptionValue and getOptionLabel, but this mapping takes a huge amount of time (several seconds), because number of fetched options may be in thousands.
Does anybody have an idea how could I fix this buggy behavior in React Select, so that I could see the selected option?
This seems to be a problem as for me :( any ideas anyone?
Not sure if this helps, but it helped me understand how react-select works. I forked your sandbox and converted it to use Hooks. From there, I tooled around with the CSS until I got the inner input to show the state of currentVal, which I also pass in according to the docs. Here is the link: https://codesandbox.io/s/react-codesandboxer-example-tiwpw
I'm sure there is a better way of doing this, but the real CSS juice comes here where I override the inline styles using the !important flag:
valueContainer: () => ({
border: "1px dotted blue",
minWidth: "20px",
minHeight: "20px",
"& input": {
border: "1px dashed green !important",
width: "20px !important",
opacity: "1 !important"
}
})
I think, we need better documentation explaining how getOptionValue is used. I just tested couple scenarios with Select and list of objects as options:
defaultValue - needs to be an object in order to find and select option in list. I expected (at least other libraries work that way): in order to preselect value each option is compared as defaultValue === getOptionValue(option)My usecase:
options is list of Objects (e.g. Author in format {id: number, name: string})Authors for the Book. Book is {id: number, name: string, authorIds: number[]}@simeonborko This is an interesting way around not supporting simpleValues. I can attempt to look a bit more into this but much of the internal code is dependent on the value being an object so it's likely just a matter of finding where the breakdown is happening though I would suspect where the internal state is set.
It's interesting that your application is seeing a performance hit of a few seconds just from mapping to a few thousand objects.
@Klinton90 not sure if you resolved this as its been over a year, and we all agree the documentation could use a bit more love and I think its complexity is attributed to how much this project can do and how flexible it is.
Your assertions about the value and defaultValue are both correct about needing to be objects (or at least should be hence this issue thread).
About your use case, could you speak a bit more about what you are trying to accomplish?
If you were going to use the getObjectLabel/Value methods you could do the following:
return (
<>
<Select placeholder="Authors"
options={authors}
getObjectLabel={x => x.name}
getObjectValue={x => x.id }
/>
<Select placeholder="Books"
options={books}
getObjectLabel={x => x.name}
getObjectValue={x => x.id }
/>
If you needed some object relational model where you are choosing the authors in the books, then my understanding is that you choose the book first, and then select the authors associated with it?
If so, here is a quick example. If you had another relationship in mind, perhaps this could help with that, but if not, feel free to reply and Ill try to answer any questions.
const authorOptions = [ /* your data */ ];
const bookOptions= [ /* your data */ ];
const [ book, setBook ] = useState();
const [ bookAuthors, setBookAuthors ] = useState();
const onChangeBook = option => {
setBook(option);
const existingAuthors = option.authorIds.map(authorId =>
authorOptions.find(author => author.id === authorId)
);
setBookAuthors(existingAuthors);
}
const onChangeAuthor = options => {
const newBook = { ...book, authorIds: (options ?? []).map(({ id }) => id) };
setBook(newBook);
setBookAuthors(options);
}
return (
<>
<Select placeholder="Books"
options={bookOptions}
getObjectLabel={x => x.name}
getObjectValue={x => x.id }
value={book}
onChange={onChangeBook}
/>
<Select placeholder={!book ? 'Please select a book first' : 'Book Authors" }
isDisabled={!book}
options={authorOptions}
getObjectLabel={x => x.name}
getObjectValue={x => x.id }
value={bookAuthors}
onChange={onChangeAuthor}
/>
</>
);