JedWatson / JedWatson/react-select
Passing a single string instead of the whole object
Nobody has claimed this yet.
- Dominant language
- TypeScript
- Stars
- 28k
- Forks
- 4.1k
- PR merge metrics
- No merged PRs in 30d
Description
Hello,
Initially it started as a question, however after having spent nearly 2 days googling and looking for a solution it gradually turned into an issue rather than a mere question. The problem arose when attempting to develop a Select to the following spec:
Using react-hook-form and react-select, create a select component that would allow searching live options from a REST API.
Below is the code to achieve the aforementioned task:
export default function GenericSelectWithApiSearch({
url,
fieldId,
label,
placeholder,
}: {
url: string;
queryParam: string;
fieldId: string;
label: string;
placeholder: string;
}) {
const [inputValue, setValue] = useState("");
const [selectedValue, setSelectedValue] = useState(null);
// handle input change event
const handleInputChange = (value: string) => {
setValue(value);
};
// load options using API call
const loadOptions = async (inputValue: string) => {
const queryUrl =
inputValue.length > 0 ? url + "?search=" + inputValue : url;
const abortController = new AbortController();
const data = await getDataFromServer(queryUrl, abortController.signal);
if (data.type === "success") {
return data.value.docs;
}
return [];
};
const {
control,
formState: { errors },
} = useFormContext(); // retrieve all hook methods
return (
<FormControl isInvalid={!!errors[fieldId]}>
<FormLabel>{label}</FormLabel>
<Controller
control={control}
name={fieldId}
render={({ field: {onChange, ...rest} }) => (
<AsyncSelect
{...rest}
cacheOptions
defaultOptions
getOptionLabel={(e) => e.name}
getOptionValue={(e) => e._id}
loadOptions={loadOptions}
onInputChange={handleInputChange}
placeholder={placeholder}
onChange={onChange}
/>
)}
rules={{ required: true }}
/>
<ErrorMessage errors={errors} name={fieldId} />
</FormControl>
);
}
In a nutshell, the problem is as follows:
A form validator is expecting a string to result from this field. This validation rule check will always fail, because react-select will always return a full object. Now, I don't know what getOptionValue is for then, I expect it does something, because getOptionLabel is performing well in updating a changed label, however the former doesn't seem to be doing anything to cure the problem. You would intuitively expect that something called getOptionValue would be actually able to do something useful with the option value, say ultimately pass it to the form. I am assuming, both of these properties serve the task of updating the react-select component after the onChange event and that's it.
Tinkering with onChange, for example doing the following:
onChange={(e) => {
onChange(e._id)
}}
Will work in setting a correct single value, but will break both getOptionLabel and getOptionValue . I suspect it is because the latter 2 are still expecting the object to access, while onChange modifies the value into a string.
Which brings me to conclude that there is no way to pass just a single selected value, let's say a single string, into a form without breaking the whole select component.
Is this really the case? If yes, it seems very limiting from a design perspective. Or am I missing something and there is indeed a way?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the supplied GenericSelectWithApiSearch example, focusing on the AsyncSelect, Controller, getOptionLabel, getOptionValue, and onChange interaction. Check the documented behavior and existing examples for controlled values, then define whether the expected result is supported and what form value and displayed option should be preserved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- react, typescript
- Domain
- frontend
- Issue type
- Bug
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100