-
Star
(131)
You must be signed in to star a gist -
Fork
(5)
You must be signed in to fork a gist
-
-
Save hubgit/e394e9be07d95cd5e774989178139ae8 to your computer and use it in GitHub Desktop.
const options = [ | |
{ value: 'foo', label: 'Foo' }, | |
{ value: 'bar', label: 'Bar' }, | |
] | |
return <Field name={'example'} component={SelectField} options={options} /> |
import { FieldProps } from 'formik' | |
import React from 'react' | |
import Select, { Option, ReactSelectProps } from 'react-select' | |
export const SelectField: React.SFC<ReactSelectProps & FieldProps> = ({ | |
options, | |
field, | |
form, | |
}) => ( | |
<Select | |
options={options} | |
name={field.name} | |
value={options ? options.find(option => option.value === field.value) : ''} | |
onChange={(option: Option) => form.setFieldValue(field.name, option.value)} | |
onBlur={field.onBlur} | |
/> | |
) |
Thanks for the snippets! Here is a version for anyone who needs the multiple selection to work with formik (@tjugg):
import { FieldProps } from "formik"; import React from "react"; import Select from "react-select"; import { OptionsType, ValueType } from "react-select/lib/types"; interface Option { label: string; value: string; } interface CustomSelectProps extends FieldProps { options: OptionsType<Option>; isMulti?: boolean; } export const CustomSelect = ({ field, form, options, isMulti = false, }: CustomSelectProps) => { const onChange = (option: ValueType<Option | Option[]>) => { form.setFieldValue( field.name, isMulti ? (option as Option[]).map((item: Option) => item.value) : (option as Option).value ); }; const getValue = () => { if (options) { return isMulti ? options.filter(option => field.value.indexOf(option.value) >= 0) : options.find(option => option.value === field.value); } else { return isMulti ? [] : ("" as any); } }; return ( <Select name={field.name} value={getValue()} onChange={onChange} options={options} isMulti={isMulti} /> ); };
thanks This works even with Formik and Chakra UI with bit changes :)
I have issue here because onChange function require two types... this is the error: Generic type 'ValueType' requires 2 type argument(s).
i can set secound type to boolean but that makes me another problem, can anybody help me with this problem?
Updated above with couple typing and import fixes
import {FieldProps} from "formik";
import React from "react";
import Select, {OptionsType, ValueType} from "react-select";
interface Option {
label: string;
value: string;
}
interface FormikSelectProps extends FieldProps {
options: OptionsType<Option>;
isMulti?: boolean;
}
export const FormikSelect =
({
field,
form,
options,
isMulti = false,
}: FormikSelectProps) => {
const onChange = (option: ValueType<Option | Option[], boolean>) => {
form.setFieldValue(
field.name,
isMulti
? (option as Option[]).map((item: Option) => item.value)
: (option as Option).value
);
};
const getValue = () => {
if (options) {
return isMulti
? options.filter(option => field.value.indexOf(option.value) >= 0)
: options.find(option => option.value === field.value);
} else {
return isMulti ? [] : ("" as any);
}
};
return (
<Select
name={field.name}
value={getValue()}
onChange={onChange}
options={options}
isMulti={isMulti}
/>
);
};
isMulti ? (option as Option[]).map((item: Option) => item.value) : (option as Option).value
instead of casting, you would better have a typeguard to let TS know the difference between option
and option[]
:
option instanceof Array
? option.map((item) => item.value)
: option.value,
This is not working for me:
onBlur={field.onBlur}
The issue is that inside of Formik#handleBlur is the following code:
var _a = e.target, name = _a.name,
It's assuming that the input that gets blurred has a name attribute which is the same as the name that formik is using to reference the field. But since the input attribute here is internal to
react-select
, it has a generic name. So after I blur,formik.touched
is{"react-select-3-input":true}
It works if I do this instead:
onBlur: function() { formik.setFieldTouched(field.name); }
Am I doing something wrong here? Is this
onBlur
approach working for other people?
thanks, it works!
I hope it will help someone
Usage
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
<SelectInput name="courseAssignmentId" label="Course Assignment">
{options.map((option) => (
<option key={option.value} value={option.value}>
{option.label}
</option>
))}
</SelectInput>`
my implementation with bootstrap 5
/* eslint-disable react/prop-types */
import React from "react";
import { useField } from "formik";
import Select from "react-select";
function SelectInput({ label, ...props }) {
const [field, meta, { setValue, setTouched }] = useField(props);
const options = props.children.map((option) => ({
value: option.props.value,
label: option.props.children,
}));
const onChange = ({ value }) => {
setValue(value);
};
return (
<div className="mb-3">
<label htmlFor={props.id || props.name} className="form-label">
{label}
</label>
<Select
defaultValue={options.find((option) => option.value === field.value)}
options={options}
onChange={onChange}
onBlur={setTouched}
/>
{meta.touched && meta.error ? (
<div className="form-text text-danger">{meta.error}</div>
) : null}
</div>
);
}
export default SelectInput;
This is great. thx!
Did react-select just change its type definitions? Definitely not seeing OptionsType and ValueType
Did react-select just change its type definitions? Definitely not seeing OptionsType and ValueType
Yes, in v5 the types are different: https://react-select.com/upgrade
OptionsType => Options
ValueType => OnChangeValue
Here's my implementation of an async multi select component used with Formik. This gist was really helpful for me in creating this, but I didn't see any other posts with both async and multi select so I'll add it here.
import { useField, FieldProps } from "formik";
import React from "react";
import AsyncSelect from "react-select/async"
const getOptions = () => {
return [{value: "1", label: "Test one"}, {value: "2", label: "Test two"}];
};
const promiseOptions = () =>
new Promise((resolve) => {
timeout(resolve(getOptions()),
1000);
});
const asyncMultiSelect = ({
label,
...props
}) => {
const [field, meta, helpers] = useField(props);
const { setValue } = helpers;
const onChange = (option) => {
setValue(
(option).map((item) => item.value)
);
};
return (
<div>
<label>{label}</label>
<AsyncSelect
defaultOptions
loadOptions={promiseOptions}
name={field.name}
onChange={onChange}
isMulti
/>
</div>
);
};
export default asyncMultiSelect;
Here's the code in the file with the Formik form:
<Field as={asyncMultiSelect} label="Make a selection" name="mySelect" />
Updated above with couple typing and import fixes
import {FieldProps} from "formik"; import React from "react"; import Select, {OptionsType, ValueType} from "react-select"; interface Option { label: string; value: string; } interface FormikSelectProps extends FieldProps { options: OptionsType<Option>; isMulti?: boolean; } export const FormikSelect = ({ field, form, options, isMulti = false, }: FormikSelectProps) => { const onChange = (option: ValueType<Option | Option[], boolean>) => { form.setFieldValue( field.name, isMulti ? (option as Option[]).map((item: Option) => item.value) : (option as Option).value ); }; const getValue = () => { if (options) { return isMulti ? options.filter(option => field.value.indexOf(option.value) >= 0) : options.find(option => option.value === field.value); } else { return isMulti ? [] : ("" as any); } }; return ( <Select name={field.name} value={getValue()} onChange={onChange} options={options} isMulti={isMulti} /> ); };
I am having issues with my form using this custom component. The values are not added to formik field values. To explain in detail, I have a select which change, determines the values to pre-select on my custom react-select input (note values here not options). This also cascades this down to a 3rd input. These is a cascading inputs seem to be getting the values, however, the this values are on in the field value object. Please note that because this is a dynamic input am not able to use initialValues object. So i somewhat use the formik props to get the selected values and cascade down. see screenshots below
React select (single select) that uses more of the formik hooks to reduce props passing and keep everything as simple as possible. Must be under the <Formik>/<Form>
code to ensure hooks all work properly.
import React from 'react';
import Select, { Options } from 'react-select';
import { useField } from 'formik';
type Props = {
selectOptions: Options[],
formikFieldName: string,
placeholder?: string,
};
/**
* React Select but hooked into Formik
* @returns {JSX.Element}
* @constructor
*/
const FormikSelect = ({
selectOptions,
formikFieldName,
placeholder,
}: Props) => {
// eslint-disable-next-line no-unused-vars
const [field, _, helpers] = useField(formikFieldName);
const { setValue } = helpers;
return (
<Select
defaultValue={selectOptions.find(
(option) => option.value === field.value
)}
options={selectOptions}
placeholder={placeholder}
onBlur={field.onBlur}
onChange={(option) => setValue(option.value)}
/>
);
};
FormikSelect.defaultProps = {
placeholder: '',
};
export default FormikSelect;
Example usage
<FormikSelect
selectOptions={[
{ value: 'foo', label: 'Foo' },
{ value: 'bar', label: 'Bar' },
]}
formikFieldName="formikInitVals.shippingMethods"
placeholder="Shipping Methods"
/>
Versions
formik: 2.4
react: 18.2
@alexluongfm with your versions still gives Generic type 'Options' requires 1 type argument(s).
error on line 6
"react-select": "^5.7.4",
My Solution for react-select@^5.7.4:
export default function MultipleSelect({ fieldName, placeholder, ...props }) {
const [field, meta, { setValue }] = useField(fieldName);
const options = props.children.map((option) => ({
value: option.props.value,
label: option.props.children,
}));
const onChange = (selectedOptions: MultiValue<any>) => {
setValue(selectedOptions);
}
return (<>
<Select
isMulti={true}
defaultValue={options.find((option) => option.value === field.value)}
placeholder={placeholder}
onChange={onChange}
options={options}
onBlur={field.onBlur}
/>
</>);
}
Form of select should be wrapped with <Formik></Formik>
I just did this...
onValueChange={(val) => formik.setFieldValue('timezone', val)}
Hey everybody. I've gotten this code to work with a single select via this:
`import Select from 'react-select';
import { useField } from 'formik';
export default function SelectField(props) {
const [field, state, { setValue, setTouched }] = useField(props.field.name);
const onChange = ({ value }) => {
setValue(value);
};
return <Select {...props} onChange={onChange} onBlur={setTouched} />;
}
`
and
<Field component={SelectField} name="campfeatures" options={selectObjects} />
How would I turn this into being capable of taking multi select?
Thanks for your help!