Unable to maintain formik state values within react-select component - reactjs

I am using react-select (multi-values) with Formik together with Material-UI Stepper (wizard) and have the values stored successfully within Formik's initialStates values but when I advance to the next screen, using conditional component rendering within my Stepper and then return back one screen where my react-select component resides, it no longer holds/shows the values that have already been selected within my react-select component even though the values are still in Formik's initialStates values.
My state is as follows which is storing my selectedOptions correctly:
import Select from 'react-select';
const myOptions= [
{ value: 'Food', label: 'Food' },
{ value: 'Being Fabulous', label: 'Being Fabulous' },
{ value: 'Unicorns', label: 'Unicorns' },
{ value: 'Kittens', label: 'Kittens' },
];
"props": {
"myGroups": [
{
"myGroupName": "",
"selectedOptions": [
{
"value": "Unicorns",
"label": "Unicorns"
},
{
"value": "Kittens",
"label": "Kittens"
}
]
}
]
}
Here is the code for the react-select component:
<Formik initialValues={initialFormValues} validationSchema={formSchema} onSubmit={this.handleFormSubmit} enableReinitialize>
{({ handleSubmit, handleChange }) => (
<Form noValidate onSubmit={handleSubmit} autoComplete='off'>
<Select
options={myOptions}
isMulti={true}
name={`myGroups.${index}.selectedOptions`}
onChange={(selectedOption) => {
let e = { target: { name: `myGroups.${index}.selectedOptions`, value: selectedOption } };
handleChange(e);
}}
/>
</Form>
)}
</Formik>
When returning, I expected to see both "Unicorns" and "Kittens" within the select but it's empty.
Any ideas how I can maintain state within this component? Can I perhaps somehow use `defaultValue' ?

The only solution I found is to install this library : formik-material-ui
You can after easy import:
import { Select } from 'formik-material-ui';
And use it in the Field component props.

Related

How to set react hook form default values when using Controller with custom components

What I'm trying to do:
Provide default values to my custom controlled rhf components and have them update like an rhf uncontrolled component.
Better understand how Controller sets default values so I can troubleshoot.
My problem:
I can only set default values with a rhf uncontrolled component as shown in the docs. For example, by creating a defaultValues object with each input's default value then calling reset({...defaultValues}) in a useEffect on page load.
I don't understand how rhf passes/sets default values with Controller
Examples:
Codesandbox here
// Parent form component (RegistrationForm.tsx)
// set up form default values
const defaultValues = {
standardRadio: "mint",
registerRadio: "supercross"
};
// fill in default values on load
useEffect(() => {
reset({ ...defaultValues });
}, []);
// DOESN'T WORK: Can't set the default value of WrapperRadioGroup
<WrapperRadioGroup
name="standardRadio"
groupLabel="This is a radio group label"
control={control}
style="standard"
defaultValue=" "
options={[
{ value: "orange", label: "Orange ice cream" },
{ value: "mint", label: "Mint ice cream" },
{ value: "chocolate", label: "Chocolate ice cream" },
{ value: "vanilla", label: "Vanilla ice cream" }
]}
/>
// Default value set properly using the following uncontrolled component
<input
{...register("registerRadio")}
id="registerRadio1"
type="radio"
value="motogp"
/>
<label htmlFor="registerRadio1">Moto GP</label>
...
<input
{...register("registerRadio")}
id="registerRadio4"
type="radio"
value="islemantt"
/>
<label htmlFor="registerRadio4">Isle of Man TT</label>
Figured it out. When using Controller there's no need to pass a defaultValue prop on the parent component as doing so will override the value used by RHF's Controller. RHF takes the value you set up in your defaultValues object and then make that the current value for the input.
Example:
Set the default values for all of your inputs via an object. (Key: input's name value: input default value).
const defaultValues = {
standardRadio: "mint",
registerRadio: "supercross"
}
Use reset() to update the form inputs. See documentation.
useEffect(() => {
reset({ ...defaultValues });
}, []);
Don't pass a defaultValue prop to the controlled component. If you do it will override RHF Controller's value.
<WrapperRadioGroup
name="standardRadio"
groupLabel="This is a radio group label"
control={control}
style="standard"
=> defaultValue=" " // !! DON'T PASS A DEFAULTVALUE PROP. OVERRIDES RHF's CONTROLLER
options={[
{ value: "orange", label: "Orange ice cream" },
{ value: "mint", label: "Mint ice cream" },
{ value: "chocolate", label: "Chocolate ice cream" },
{ value: "vanilla", label: "Vanilla ice cream" }
]}
/>
If you need the default value in the input's controlled component then access it via props.value

Access selected value from react's Select Component

Hello dear community,
I want to create a very basic website for my school assignment.
I have a dropdown menu with a Select Component as its implementation. I need to access the selected value, which is a currency in my case, in order to update the information displayed on the page once a currency has been selected.
I am kind of frustrated since I wasn't able to find a helpfull solution to my relatively basic problem (I think it's basic :D)
My component class here:
import { Component } from "react";
import Select from 'react-select';
interface DropdownMenuProps {
values: [{}]
defaultValue: string
}
interface DropdownMenuState { }
/**
* Represents a Dropdown Menu
*/
export default class DropdownMenu extends Component<DropdownMenuProps, DropdownMenuState> {
render() {
return (
<div style={{ width: '120px' }}>
<Select id="dropdown-menu"
placeholder={this.props.defaultValue}
options={this.props.values}
// getOptionValue={(option) => option.value}
// getOptionLabel={(option) => option.label}
/>
</div>
)
}
}
This is how I create a dropdown menu compent:
<DropdownMenu defaultValue="Currency" values={[{ label: "EUR", value: "EUR" }, { label: "GBP", value: "GBP" }, { label: "USD", value: "USD" }]} ></DropdownMenu>
I'm glad for any tips :)
You have to use the onChange prop of react-select:
<select
id="dropdown-menu"
onChange={handleSelectChange}
>
and in this function you could handle the changes:
const handleSelectChange = (selectedVal) => console.log(selectedVal)
I recommend you using directly onChange and save it into a state:
1st:
Create state with the name you want:
const [selectValue, setSelectValue] = useState({});
2nd: Create options:
const options = [
{ label: "Tomate", value: 1 },
{ label: "Queso", value: 2 }
];
3rd: add method onChange in select and pass options:
const onChange = (ev) => {
setSelectValue(ev);
//console.log(ev);
console.log(selectValue);
};
<Select
id="dropdown-menu"
placeholder={"e"}
options={options}
onChange={onChange}
/>
I have created demo here:
https://codesandbox.io/s/ancient-pond-96h53?file=/src/App.js

How to format value of the React Select

I use "react final forms" and "react select".
I've organized an interface and functionality works, but I have one thing which I don't like.
React select requires options in next format:
const options = [
{ value: 'chocolate', label: 'Chocolate' },
{ value: 'strawberry', label: 'Strawberry' },
{ value: 'vanilla', label: 'Vanilla' }
]
and the value also should be set as { value: 'chocolate', label: 'Chocolate' }.
But for me is strange to have in my model of data (and send to the server also) the value like this - { value: 'chocolate', label: 'Chocolate' }, because I need only 'chocolate'.
Easy way is format the object into a single value after the form will be saved and format back from single value to the object before the rendering of the element. I know how to do it outside of form, but in this case I should solve this problem again and again for each select element separately.
What I would like to do:
Find a way how to set value of the react select as single value, like 'chocolate' instead of object.
OR
Create a wrapper for react select component and format value there when it sets (it's easy) and when the form get the value from this field (this I don't know how to do).
I will appreciate any help.
Method 1
With strings:
import React, { useState } from "react";
import ReactDOM from "react-dom";
import Select from "react-select";
const data = ["1", "2"];
function SingleStringReactSelect() {
const [option, setOption] = useState();
return (
<section>
<Select
onChange={option => setOption(option)}
value={[option]}
getOptionLabel={label => label}
getOptionValue={value => value}
closeMenuOSelect={false}
options={data}
/>
</section>
);
}
Method 2:
Created example:
https://codesandbox.io/s/react-codesandboxer-example-z57ke
You can use map in options and with Wrapper like SingleValueReactSelect
import React, { Fragment, useState } from "react";
import Select from "react-select";
const data = ["chocolate", "strawberry", "vanilla"];
export function SingleValueReactSelect(props) {
const [selectedItem, setSelectedItem] = useState();
return (
<Select
{...props}
value={selectedItem}
onChange={item => {
setSelectedItem(item);
props.onChange(item.value);
}}
options={props.options.map(item => ({ label: item, value: item }))}
/>
);
}
export default function AppDemo() {
return (
<Fragment>
<p>SingleValueReactSelect Demo</p>
<SingleValueReactSelect
isClearable
isSearchable
options={data}
onChange={item => {
alert(item);
}}
/>
</Fragment>
);
}
You can transform/filter the object data once you are sending the form data to server or another component.
Setting the value of the react-select as a single value will not show it as selected in the React-Select.

How to disable `deselect-option` in `react-select`?

I would like to use the react-select multi Select component and be able to select the same option multiple times. However, react-select does not allow one to do this. You can change the dropdown to show already selected options with hideSelectOptions={false}, but if you select one of them again, it will be deselected.
This issue #3234 describes this same problem and sugggests that one way to solve this problem is to handle the action argument to onChange somehow.
Here is the solution that I attempted based off of the suggested solution:
import React, { Component } from "react";
import Select from "react-select";
export default class MultiSelect extends Component<*, State> {
handleChange(option, action) {
console.log(option, action);
// return;
if (action === "deselect-option") {
action = "select-option";
// now how do I do the component's state?
}
}
render() {
return (
<Select
isMulti
className="basic-single"
classNamePrefix="select"
name="color"
options={[{"label": "hello", "value": "hello"}, {"label": "world", "value": "world"}]}
hideSelectedOptions={false}
onChange={this.handleChange}
/>
);
}
}
I expected to be able to enter "hello" multiple times but when I tried to enter "hello" again it was deleted.
In options, the data field makes value dynamic with any key, in this case, use Date.now() to make dynamic. then use actions 'select-option' to append to options, use actions 'remove-value'' to filter all fields in the Options data field with a label matching with selected option label and append to data and append one more object to Options datafield
options = [
{ value: Date.now(), label: "SUBJECT" ,val:"SUBJ" },
{ value: Date.now, label: "VERB", val:"VERB" }
]
<Select options={options} isMulti onChange={(e, option) => {
if (option.action === "select-option") {
Options=[
...Options,
{
value: option.option.value + "_" + Date.now(),
label: option.option.label
}
];
} else if (option.action === "remove-value" ||option.action === "pop-value") {
tempData = data.filter(opt => opt.label !== option.removedValue.label)
Options=[
...tempData,
{
value: option.removedValue.value + "_" + Date.now(),
label: option.removedValue.label
}
]
}
}
} />

React Grommet Select - passing in object data as options

I am using Grommet v2 components and trying to mirror the display used in the Select 'Seasons' example in Grommet's storybook.
The field appears like this:
The difference is my data needs to separate label and value:
const Options = [
{
label: "S01",
value: "283736"
},
{
label: "S02",
value: "293774"
},
instead of using the default:
const Options = [
"S01",
"S02",
Here is an example on Codesandbox
The object format was used in Grommet's example of ObjectMultiSelect in their storybook. I found the Select component needs
labelKey="label" and valueKey="value" to load the objects as options, but adding these two props seems to break the component options.
I would like for the data passed in to resemble
const Options = [
{
label: "S01",
value: "283736"
},
{
label: "S02",
value: "293774"
},
and still have the options displayed as above.
<Select
options={[
{
lab: "S01",
val: "283736"
},
{
lab: "S02",
value: "293774"
}
]}
labelKey="lab"
dropHeight="large"
name="primaryServer"
value={this.props.values.primaryServer}
placeholder="Select Primary Server"
emptySearchMessage={"No Servers Available"}
onChange={({ option }) => {
console.log(option.lab)
console.log(option.val)
}}
/>
// Output // S01 // 283736
// This worked for me. labelKey="lab" is required.

Resources